Piano: Expose multi-track functionality

This commit adds some actions for creating and cycling through tracks.

set_octave_and_ensure_note_change() was refactored to allow switching
tracks to implement the same behaviour.

KnobsWidget is getting pretty bad.
This commit is contained in:
William McPherson 2020-06-17 19:34:25 +10:00 committed by Andreas Kling
parent ee52572ca1
commit 34ee76984c
Notes: sideshowbarker 2024-07-19 05:34:20 +09:00
5 changed files with 69 additions and 21 deletions

View file

@ -32,6 +32,12 @@
#include <LibGUI/Label.h>
#include <LibGUI/Slider.h>
constexpr int max_attack = 1000;
constexpr int max_decay = 1000;
constexpr int max_sustain = 1000;
constexpr int max_release = 1000;
constexpr int max_delay = 8;
KnobsWidget::KnobsWidget(TrackManager& track_manager, MainWidget& main_widget)
: m_track_manager(track_manager)
, m_main_widget(main_widget)
@ -76,7 +82,7 @@ KnobsWidget::KnobsWidget(TrackManager& track_manager, MainWidget& main_widget)
m_octave_knob->set_value((octave_max - 1) - (m_track_manager.octave() - 1));
m_octave_knob->on_value_changed = [this](int value) {
int new_octave = octave_max - value;
if (m_change_octave)
if (m_change_underlying)
m_main_widget.set_octave_and_ensure_note_change(new_octave == m_track_manager.octave() + 1 ? Up : Down);
ASSERT(new_octave == m_track_manager.octave());
m_octave_value->set_text(String::number(new_octave));
@ -88,66 +94,67 @@ KnobsWidget::KnobsWidget(TrackManager& track_manager, MainWidget& main_widget)
m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave());
m_wave_knob->on_value_changed = [this](int value) {
int new_wave = last_wave - value;
m_track_manager.current_track().set_wave(new_wave);
if (m_change_underlying)
m_track_manager.current_track().set_wave(new_wave);
ASSERT(new_wave == m_track_manager.current_track().wave());
m_wave_value->set_text(wave_strings[new_wave]);
};
constexpr int max_attack = 1000;
m_attack_knob = m_knobs_container->add<GUI::VerticalSlider>();
m_attack_knob->set_range(0, max_attack);
m_attack_knob->set_value(max_attack - m_track_manager.current_track().attack());
m_attack_knob->set_step(100);
m_attack_knob->on_value_changed = [this](int value) {
int new_attack = max_attack - value;
m_track_manager.current_track().set_attack(new_attack);
if (m_change_underlying)
m_track_manager.current_track().set_attack(new_attack);
ASSERT(new_attack == m_track_manager.current_track().attack());
m_attack_value->set_text(String::number(new_attack));
};
constexpr int max_decay = 1000;
m_decay_knob = m_knobs_container->add<GUI::VerticalSlider>();
m_decay_knob->set_range(0, max_decay);
m_decay_knob->set_value(max_decay - m_track_manager.current_track().decay());
m_decay_knob->set_step(100);
m_decay_knob->on_value_changed = [this](int value) {
int new_decay = max_decay - value;
m_track_manager.current_track().set_decay(new_decay);
if (m_change_underlying)
m_track_manager.current_track().set_decay(new_decay);
ASSERT(new_decay == m_track_manager.current_track().decay());
m_decay_value->set_text(String::number(new_decay));
};
constexpr int max_sustain = 1000;
m_sustain_knob = m_knobs_container->add<GUI::VerticalSlider>();
m_sustain_knob->set_range(0, max_sustain);
m_sustain_knob->set_value(max_sustain - m_track_manager.current_track().sustain());
m_sustain_knob->set_step(100);
m_sustain_knob->on_value_changed = [this](int value) {
int new_sustain = max_sustain - value;
m_track_manager.current_track().set_sustain(new_sustain);
if (m_change_underlying)
m_track_manager.current_track().set_sustain(new_sustain);
ASSERT(new_sustain == m_track_manager.current_track().sustain());
m_sustain_value->set_text(String::number(new_sustain));
};
constexpr int max_release = 1000;
m_release_knob = m_knobs_container->add<GUI::VerticalSlider>();
m_release_knob->set_range(0, max_release);
m_release_knob->set_value(max_release - m_track_manager.current_track().release());
m_release_knob->set_step(100);
m_release_knob->on_value_changed = [this](int value) {
int new_release = max_release - value;
m_track_manager.current_track().set_release(new_release);
if (m_change_underlying)
m_track_manager.current_track().set_release(new_release);
ASSERT(new_release == m_track_manager.current_track().release());
m_release_value->set_text(String::number(new_release));
};
constexpr int max_delay = 8;
m_delay_knob = m_knobs_container->add<GUI::VerticalSlider>();
m_delay_knob->set_range(0, max_delay);
m_delay_knob->set_value(max_delay - m_track_manager.current_track().delay());
m_delay_knob->on_value_changed = [this](int value) {
int new_delay = max_delay - value;
m_track_manager.current_track().set_delay(new_delay);
if (m_change_underlying)
m_track_manager.current_track().set_delay(new_delay);
ASSERT(new_delay == m_track_manager.current_track().delay());
m_delay_value->set_text(String::number(new_delay));
};
@ -161,10 +168,18 @@ void KnobsWidget::update_knobs()
{
m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave());
// FIXME: This is needed because when the slider is changed directly, it
// needs to change the octave, but if the octave was changed elsewhere, we
// need to change the slider without changing the octave.
m_change_octave = false;
// FIXME: This is needed because when the slider is changed normally, we
// need to change the underlying value, but if the keyboard was used, we
// need to change the slider without changing the underlying value.
m_change_underlying = false;
m_octave_knob->set_value(octave_max - m_track_manager.octave());
m_change_octave = true;
m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave());
m_attack_knob->set_value(max_attack - m_track_manager.current_track().attack());
m_decay_knob->set_value(max_decay - m_track_manager.current_track().decay());
m_sustain_knob->set_value(max_sustain - m_track_manager.current_track().sustain());
m_release_knob->set_value(max_release - m_track_manager.current_track().release());
m_delay_knob->set_value(max_delay - m_track_manager.current_track().delay());
m_change_underlying = true;
}

View file

@ -72,5 +72,5 @@ private:
RefPtr<GUI::Slider> m_release_knob;
RefPtr<GUI::Slider> m_delay_knob;
bool m_change_octave { true };
bool m_change_underlying { true };
};

View file

@ -32,7 +32,9 @@
#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)
@ -73,6 +75,21 @@ MainWidget::~MainWidget()
{
}
void MainWidget::add_actions(GUI::Menu& menu)
{
menu.add_action(GUI::Action::create("Add track", { Mod_Ctrl, Key_T }, [&](auto&) {
m_track_manager.add_track();
}));
menu.add_action(GUI::Action::create("Next track", { Mod_Ctrl, Key_N }, [&](auto&) {
turn_off_pressed_keys();
m_track_manager.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.
@ -125,21 +142,29 @@ void MainWidget::special_key_action(int key_code)
}
}
void MainWidget::set_octave_and_ensure_note_change(Direction direction)
void MainWidget::turn_off_pressed_keys()
{
m_keys_widget->set_key(m_keys_widget->mouse_note(), Off);
for (int i = 0; i < key_code_count; ++i) {
if (m_keys_pressed[i])
note_key_action(i, Off);
}
}
m_track_manager.set_octave(direction);
void MainWidget::turn_on_pressed_keys()
{
m_keys_widget->set_key(m_keys_widget->mouse_note(), On);
for (int i = 0; i < key_code_count; ++i) {
if (m_keys_pressed[i])
note_key_action(i, On);
}
}
void MainWidget::set_octave_and_ensure_note_change(Direction direction)
{
turn_off_pressed_keys();
m_track_manager.set_octave(direction);
turn_on_pressed_keys();
m_knobs_widget->update_knobs();
m_keys_widget->update();

View file

@ -42,6 +42,8 @@ class MainWidget final : public GUI::Widget {
public:
virtual ~MainWidget() override;
void add_actions(GUI::Menu&);
void set_octave_and_ensure_note_change(Direction);
private:
@ -54,6 +56,9 @@ private:
void note_key_action(int key_code, Switch);
void special_key_action(int key_code);
void turn_off_pressed_keys();
void turn_on_pressed_keys();
TrackManager& m_track_manager;
RefPtr<WaveWidget> m_wave_widget;

View file

@ -117,6 +117,9 @@ int main(int argc, char** argv)
GUI::AboutDialog::show("Piano", Gfx::Bitmap::load_from_file("/res/icons/32x32/app-piano.png"), window);
}));
auto& edit_menu = menubar->add_menu("Edit");
main_widget.add_actions(edit_menu);
app.set_menubar(move(menubar));
return app.exec();