diff options
-rw-r--r-- | Applications/Piano/Music.h | 1 | ||||
-rw-r--r-- | Applications/Piano/PianoWidget.cpp | 159 | ||||
-rw-r--r-- | Applications/Piano/PianoWidget.h | 11 |
3 files changed, 116 insertions, 55 deletions
diff --git a/Applications/Piano/Music.h b/Applications/Piano/Music.h index 098d04e0a2..480765f293 100644 --- a/Applications/Piano/Music.h +++ b/Applications/Piano/Music.h @@ -12,6 +12,7 @@ struct Sample { enum WaveType { Sine, Saw, Square, InvalidWave }; enum PianoKey { + K_None, K_C1, K_Db1, K_D1, K_Eb1, K_E1, K_F1, K_Gb1, K_G1, K_Ab1, K_A1, K_Bb1, K_B1, K_C2, K_Db2, K_D2, K_Eb2, K_E2, K_F2, K_Gb2, K_G2, }; diff --git a/Applications/Piano/PianoWidget.cpp b/Applications/Piano/PianoWidget.cpp index ddeed872a0..582a25ac1f 100644 --- a/Applications/Piano/PianoWidget.cpp +++ b/Applications/Piano/PianoWidget.cpp @@ -1,7 +1,7 @@ #include "PianoWidget.h" #include <AK/Queue.h> -#include <LibGUI/GPainter.h> #include <LibDraw/GraphicsBitmap.h> +#include <LibGUI/GPainter.h> #include <math.h> PianoWidget::PianoWidget() @@ -152,8 +152,10 @@ int PianoWidget::octave_base() const return (m_octave - m_octave_min) * 12; } -void PianoWidget::note(PianoKey offset_n, bool is_down) +void PianoWidget::note(PianoKey offset_n, KeyCode key_code) { + bool is_down = keys[key_code] || (m_mouse_pressed && m_piano_key_under_mouse == offset_n); + int n = offset_n + octave_base(); if (m_note_on[n] == is_down) return; @@ -165,28 +167,40 @@ void PianoWidget::note(PianoKey offset_n, bool is_down) //printf("note[%u] = %u (%g)\n", (unsigned)n, is_down, note_frequency[n]); } +struct KeyDefinition { + int index; + PianoKey piano_key; + String label; + KeyCode key_code; +}; + +const KeyDefinition key_definitions[] = { + { 0, K_C1, "A", KeyCode::Key_A }, + { 1, K_D1, "S", KeyCode::Key_S }, + { 2, K_E1, "D", KeyCode::Key_D }, + { 3, K_F1, "F", KeyCode::Key_F }, + { 4, K_G1, "G", KeyCode::Key_G }, + { 5, K_A1, "H", KeyCode::Key_H }, + { 6, K_B1, "J", KeyCode::Key_J }, + { 7, K_C2, "K", KeyCode::Key_K }, + { 8, K_D2, "L", KeyCode::Key_L }, + { 9, K_E2, ";", KeyCode::Key_Semicolon }, + { 10, K_F2, "'", KeyCode::Key_Apostrophe }, + { 11, K_G2, "r", KeyCode::Key_Return }, + { 0, K_Db1, "W", KeyCode::Key_W }, + { 1, K_Eb1, "E", KeyCode::Key_E }, + { 3, K_Gb1, "T", KeyCode::Key_T }, + { 4, K_Ab1, "Y", KeyCode::Key_Y }, + { 5, K_Bb1, "U", KeyCode::Key_U }, + { 7, K_Db2, "O", KeyCode::Key_O }, + { 8, K_Eb2, "P", KeyCode::Key_P }, + { 10, K_Gb2, "]", KeyCode::Key_RightBracket }, +}; + void PianoWidget::update_keys() { - note(K_C1, keys[KeyCode::Key_A]); - note(K_Db1, keys[KeyCode::Key_W]); - note(K_D1, keys[KeyCode::Key_S]); - note(K_Eb1, keys[KeyCode::Key_E]); - note(K_E1, keys[KeyCode::Key_D]); - note(K_F1, keys[KeyCode::Key_F]); - note(K_Gb1, keys[KeyCode::Key_T]); - note(K_G1, keys[KeyCode::Key_G]); - note(K_Ab1, keys[KeyCode::Key_Y]); - note(K_A1, keys[KeyCode::Key_H]); - note(K_Bb1, keys[KeyCode::Key_U]); - note(K_B1, keys[KeyCode::Key_J]); - note(K_C2, keys[KeyCode::Key_K]); - note(K_Db2, keys[KeyCode::Key_O]); - note(K_D2, keys[KeyCode::Key_L]); - note(K_Eb2, keys[KeyCode::Key_P]); - note(K_E2, keys[KeyCode::Key_Semicolon]); - note(K_F2, keys[KeyCode::Key_Apostrophe]); - note(K_Gb2, keys[KeyCode::Key_RightBracket]); - note(K_G2, keys[KeyCode::Key_Return]); + for (auto& kd : key_definitions) + note(kd.piano_key, kd.key_code); } void PianoWidget::keydown_event(GKeyEvent& event) @@ -227,6 +241,39 @@ void PianoWidget::keyup_event(GKeyEvent& event) update(); } +void PianoWidget::mousedown_event(GMouseEvent& event) +{ + m_mouse_pressed = true; + + m_piano_key_under_mouse = find_key_for_relative_position(event.x() - x(), event.y() - y()); + + update_keys(); + update(); +} + +void PianoWidget::mouseup_event(GMouseEvent&) +{ + m_mouse_pressed = false; + + update_keys(); + update(); +} + +void PianoWidget::mousemove_event(GMouseEvent& event) +{ + if (!m_mouse_pressed) + return; + + int mouse_was_over = m_piano_key_under_mouse; + + m_piano_key_under_mouse = find_key_for_relative_position(event.x() - x(), event.y() - y()); + + if (m_piano_key_under_mouse == mouse_was_over) + return; + + update_keys(); + update(); +} static int white_key_width = 22; static int white_key_height = 60; @@ -235,17 +282,8 @@ static int black_key_height = 35; static int black_key_stride = white_key_width - black_key_width; static int black_key_offset = white_key_width - black_key_width / 2; -void PianoWidget::render_piano_key(GPainter& painter, int index, PianoKey n, const StringView& text) +Rect PianoWidget::define_piano_key_rect(int index, PianoKey n) const { - Color color; - if (m_note_on[octave_base() + n]) { - color = Color(64, 64, 255); - } else { - if (is_white(n)) - color = Color::White; - else - color = Color::Black; - } Rect rect; int stride = 0; int offset = 0; @@ -260,6 +298,38 @@ void PianoWidget::render_piano_key(GPainter& painter, int index, PianoKey n, con } rect.set_x(offset + index * rect.width() + (index * stride)); rect.set_y(m_height - white_key_height); + return rect; +} + +PianoKey PianoWidget::find_key_for_relative_position(int x, int y) const +{ + // here we iterate backwards because we want to try to match the black + // keys first, which are defined last + for (int i = (sizeof(key_definitions) / sizeof(KeyDefinition)) - 1; i >= 0; i--) { + auto& kd = key_definitions[i]; + + auto rect = define_piano_key_rect(kd.index, kd.piano_key); + + if (rect.contains(x, y)) + return kd.piano_key; + } + + return K_None; +} + +void PianoWidget::render_piano_key(GPainter& painter, int index, PianoKey n, const StringView& text) +{ + Color color; + if (m_note_on[octave_base() + n]) { + color = Color(64, 64, 255); + } else { + if (is_white(n)) + color = Color::White; + else + color = Color::Black; + } + + auto rect = define_piano_key_rect(index, n); painter.fill_rect(rect, color); painter.draw_rect(rect, Color::Black); @@ -276,27 +346,8 @@ void PianoWidget::render_piano_key(GPainter& painter, int index, PianoKey n, con void PianoWidget::render_piano(GPainter& painter) { - render_piano_key(painter, 0, K_C1, "A"); - render_piano_key(painter, 1, K_D1, "S"); - render_piano_key(painter, 2, K_E1, "D"); - render_piano_key(painter, 3, K_F1, "F"); - render_piano_key(painter, 4, K_G1, "G"); - render_piano_key(painter, 5, K_A1, "H"); - render_piano_key(painter, 6, K_B1, "J"); - render_piano_key(painter, 7, K_C2, "K"); - render_piano_key(painter, 8, K_D2, "L"); - render_piano_key(painter, 9, K_E2, ";"); - render_piano_key(painter, 10, K_F2, "'"); - render_piano_key(painter, 11, K_G2, "r"); - - render_piano_key(painter, 0, K_Db1, "W"); - render_piano_key(painter, 1, K_Eb1, "E"); - render_piano_key(painter, 3, K_Gb1, "T"); - render_piano_key(painter, 4, K_Ab1, "Y"); - render_piano_key(painter, 5, K_Bb1, "U"); - render_piano_key(painter, 7, K_Db2, "O"); - render_piano_key(painter, 8, K_Eb2, "P"); - render_piano_key(painter, 10, K_Gb2, "]"); + for (auto& kd : key_definitions) + render_piano_key(painter, kd.index, kd.piano_key, kd.label); } static int knob_width = 100; @@ -317,7 +368,7 @@ void PianoWidget::render_knob(GPainter& painter, const Rect& rect, bool state, c void PianoWidget::render_knobs(GPainter& painter) { Rect delay_knob_rect(m_width - knob_width - 16, m_height - 50, knob_width, 16); - render_knob(painter, delay_knob_rect, m_delay_enabled, "V: Delay "); + render_knob(painter, delay_knob_rect, m_delay_enabled, "V: Delay "); Rect release_knob_rect(m_width - knob_width - 16, m_height - 30, knob_width, 16); render_knob(painter, release_knob_rect, m_release_enabled, "B: Release "); diff --git a/Applications/Piano/PianoWidget.h b/Applications/Piano/PianoWidget.h index 85b57bdef7..73cc3443be 100644 --- a/Applications/Piano/PianoWidget.h +++ b/Applications/Piano/PianoWidget.h @@ -17,17 +17,23 @@ private: virtual void keydown_event(GKeyEvent&) override; virtual void keyup_event(GKeyEvent&) override; virtual void custom_event(CCustomEvent&) override; + virtual void mousedown_event(GMouseEvent&) override; + virtual void mouseup_event(GMouseEvent&) override; + virtual void mousemove_event(GMouseEvent&) override; double w_sine(size_t); double w_saw(size_t); double w_square(size_t); + Rect define_piano_key_rect(int index, PianoKey) const; + PianoKey find_key_for_relative_position(int x, int y) const; + void render_piano_key(GPainter&, int index, PianoKey, const StringView&); void render_piano(GPainter&); void render_knobs(GPainter&); void render_knob(GPainter&, const Rect&, bool state, const StringView&); - void note(Music::PianoKey offset_n, bool is_down); + void note(Music::PianoKey offset_n, KeyCode key_code); void update_keys(); int octave_base() const; @@ -55,4 +61,7 @@ private: bool m_release_enabled { false }; bool keys[256]; + + PianoKey m_piano_key_under_mouse { K_None }; + bool m_mouse_pressed { false }; }; |