serenity/Userland/Applications/Piano/MainWidget.cpp
kleines Filmröllchen a0b2e8608b Piano: Remove waveform cycling with C
This is not the most useful keyboard binding anyways, plus it will be
extremely hacky to implement it with the generic processor parameter
widgets. Therefore, we'll get rid of it and add back a more generic
keyboard binding system later.
2022-07-25 15:25:13 +02:00

162 lines
5 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "MainWidget.h"
#include "KeysWidget.h"
#include "KnobsWidget.h"
#include "PlayerWidget.h"
#include "RollWidget.h"
#include "SamplerWidget.h"
#include "TrackManager.h"
#include "WaveWidget.h"
#include <LibGUI/Action.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Menu.h>
#include <LibGUI/TabWidget.h>
MainWidget::MainWidget(TrackManager& track_manager, AudioPlayerLoop& loop)
: m_track_manager(track_manager)
, m_audio_loop(loop)
{
set_layout<GUI::VerticalBoxLayout>();
layout()->set_spacing(2);
layout()->set_margins(2);
set_fill_with_background_color(true);
m_wave_widget = add<WaveWidget>(track_manager);
m_wave_widget->set_fixed_height(100);
m_tab_widget = add<GUI::TabWidget>();
m_roll_widget = m_tab_widget->add_tab<RollWidget>("Piano Roll", track_manager);
m_roll_widget->set_fixed_height(300);
m_tab_widget->add_tab<SamplerWidget>("Sampler", track_manager);
m_player_widget = add<PlayerWidget>(track_manager, loop);
m_keys_and_knobs_container = add<GUI::Widget>();
m_keys_and_knobs_container->set_layout<GUI::HorizontalBoxLayout>();
m_keys_and_knobs_container->layout()->set_spacing(2);
m_keys_and_knobs_container->set_fixed_height(130);
m_keys_and_knobs_container->set_fill_with_background_color(true);
m_keys_widget = m_keys_and_knobs_container->add<KeysWidget>(track_manager.keyboard());
m_knobs_widget = m_keys_and_knobs_container->add<KnobsWidget>(track_manager, *this);
m_roll_widget->set_keys_widget(m_keys_widget);
}
void MainWidget::add_track_actions(GUI::Menu& menu)
{
menu.add_action(GUI::Action::create("&Add Track", { Mod_Ctrl, Key_T }, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/plus.png"sv).release_value_but_fixme_should_propagate_errors(), [&](auto&) {
m_player_widget->add_track();
}));
menu.add_action(GUI::Action::create("&Next Track", { Mod_Ctrl, Key_N }, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/go-last.png"sv).release_value_but_fixme_should_propagate_errors(), [&](auto&) {
turn_off_pressed_keys();
m_player_widget->next_track();
turn_on_pressed_keys();
m_knobs_widget->update_knobs();
}));
}
// FIXME: There are some unnecessary calls to update() throughout this program,
// which are an easy target for optimization.
void MainWidget::custom_event(Core::CustomEvent&)
{
m_wave_widget->update();
m_roll_widget->update();
}
void MainWidget::keydown_event(GUI::KeyEvent& event)
{
// This is to stop held-down keys from creating multiple events.
if (m_keys_pressed[event.key()])
return;
else
m_keys_pressed[event.key()] = true;
note_key_action(event.key(), DSP::Keyboard::Switch::On);
special_key_action(event.key());
m_keys_widget->update();
}
void MainWidget::keyup_event(GUI::KeyEvent& event)
{
m_keys_pressed[event.key()] = false;
note_key_action(event.key(), DSP::Keyboard::Switch::Off);
m_keys_widget->update();
}
void MainWidget::note_key_action(int key_code, DSP::Keyboard::Switch switch_note)
{
auto key = m_keys_widget->key_code_to_key(key_code);
if (key == -1)
return;
m_track_manager.keyboard()->set_keyboard_note_in_active_octave(key, switch_note);
}
void MainWidget::special_key_action(int key_code)
{
switch (key_code) {
case Key_Z:
set_octave_and_ensure_note_change(DSP::Keyboard::Direction::Down);
break;
case Key_X:
set_octave_and_ensure_note_change(DSP::Keyboard::Direction::Up);
break;
case Key_Space:
m_player_widget->toggle_paused();
break;
}
}
void MainWidget::turn_off_pressed_keys()
{
if (m_keys_widget->mouse_note() != -1)
m_track_manager.keyboard()->set_keyboard_note_in_active_octave(m_keys_widget->mouse_note(), DSP::Keyboard::Switch::Off);
for (int i = 0; i < key_code_count; ++i) {
if (m_keys_pressed[i])
note_key_action(i, DSP::Keyboard::Switch::Off);
}
}
void MainWidget::turn_on_pressed_keys()
{
if (m_keys_widget->mouse_note() != -1)
m_track_manager.keyboard()->set_keyboard_note_in_active_octave(m_keys_widget->mouse_note(), DSP::Keyboard::Switch::On);
for (int i = 0; i < key_code_count; ++i) {
if (m_keys_pressed[i])
note_key_action(i, DSP::Keyboard::Switch::On);
}
}
void MainWidget::set_octave_and_ensure_note_change(int octave)
{
turn_off_pressed_keys();
MUST(m_track_manager.keyboard()->set_virtual_keyboard_octave(octave));
turn_on_pressed_keys();
m_knobs_widget->update_knobs();
m_keys_widget->update();
}
void MainWidget::set_octave_and_ensure_note_change(DSP::Keyboard::Direction direction)
{
turn_off_pressed_keys();
m_track_manager.keyboard()->change_virtual_keyboard_octave(direction);
turn_on_pressed_keys();
m_knobs_widget->update_knobs();
m_keys_widget->update();
}