summaryrefslogtreecommitdiff
path: root/Applications/Piano
diff options
context:
space:
mode:
Diffstat (limited to 'Applications/Piano')
-rw-r--r--Applications/Piano/Music.h1
-rw-r--r--Applications/Piano/PianoWidget.cpp159
-rw-r--r--Applications/Piano/PianoWidget.h11
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 };
};