From 9a05bbaaced69d2c55f5aa9f0ecfa4ae21bd461a Mon Sep 17 00:00:00 2001 From: William McPherson Date: Thu, 6 Feb 2020 19:13:25 +1100 Subject: [PATCH] Piano: Move piano roll internals to AudioEngine The piano roll data definitely belongs in AudioEngine along with the note and time data. Now RollWidget only has GUI information, much like the other widgets. Note that this commit exacerbates issue #1158 which is caused by RollWidget::paint_event(). --- Applications/Piano/AudioEngine.cpp | 30 ++++++++++++++++++++++++- Applications/Piano/AudioEngine.h | 9 ++++++++ Applications/Piano/MainWidget.cpp | 2 +- Applications/Piano/Music.h | 2 ++ Applications/Piano/RollWidget.cpp | 35 +++++------------------------- Applications/Piano/RollWidget.h | 7 ------ 6 files changed, 47 insertions(+), 38 deletions(-) diff --git a/Applications/Piano/AudioEngine.cpp b/Applications/Piano/AudioEngine.cpp index 11c4a4e109..d91d0180ee 100644 --- a/Applications/Piano/AudioEngine.cpp +++ b/Applications/Piano/AudioEngine.cpp @@ -113,8 +113,10 @@ void AudioEngine::fill_buffer(FixedArray& buffer) m_delay_buffers.enqueue(move(delay_buffer)); } - if (++m_time == m_tick) + if (++m_time == m_tick) { m_time = 0; + update_roll(); + } memcpy(m_back_buffer_ptr->data(), buffer.data(), buffer_size); swap(m_front_buffer_ptr, m_back_buffer_ptr); @@ -205,6 +207,32 @@ void AudioEngine::set_note_current_octave(int note, Switch switch_note) set_note(note + octave_base(), switch_note); } +void AudioEngine::set_roll_note(int y, int x, Switch switch_note) +{ + ASSERT(x >= 0 && x < horizontal_notes); + ASSERT(y >= 0 && y < note_count); + + m_roll_notes[y][x] = switch_note; + + if (x == m_current_column && switch_note == Off) // If you turn off a note that is playing. + set_note((note_count - 1) - y, Off); +} + +void AudioEngine::update_roll() +{ + if (++m_current_column == horizontal_notes) + m_current_column = 0; + if (++m_previous_column == horizontal_notes) + m_previous_column = 0; + + for (int note = 0; note < note_count; ++note) { + if (m_roll_notes[note][m_previous_column] == On) + set_note((note_count - 1) - note, Off); + if (m_roll_notes[note][m_current_column] == On) + set_note((note_count - 1) - note, On); + } +} + void AudioEngine::set_octave(Direction direction) { if (direction == Up) { diff --git a/Applications/Piano/AudioEngine.h b/Applications/Piano/AudioEngine.h index 8e1a048234..229c365f1a 100644 --- a/Applications/Piano/AudioEngine.h +++ b/Applications/Piano/AudioEngine.h @@ -40,6 +40,8 @@ public: ~AudioEngine(); const FixedArray& buffer() const { return *m_front_buffer_ptr; } + Switch roll_note(int y, int x) const { return m_roll_notes[y][x]; } + int current_column() const { return m_current_column; } int octave() const { return m_octave; } int octave_base() const { return (m_octave - octave_min) * 12; } int wave() const { return m_wave; } @@ -54,6 +56,7 @@ public: void fill_buffer(FixedArray& buffer); void set_note(int note, Switch); void set_note_current_octave(int note, Switch); + void set_roll_note(int y, int x, Switch); void set_octave(Direction); void set_wave(int wave); void set_wave(Direction); @@ -70,6 +73,8 @@ private: double triangle(size_t note); double noise() const; + void update_roll(); + void set_sustain_impl(int sustain); FixedArray m_front_buffer { sample_count }; @@ -98,4 +103,8 @@ private: int m_time { 0 }; int m_tick { 8 }; + + Switch m_roll_notes[note_count][horizontal_notes] { { Off } }; + int m_current_column { 0 }; + int m_previous_column { horizontal_notes - 1 }; }; diff --git a/Applications/Piano/MainWidget.cpp b/Applications/Piano/MainWidget.cpp index d64850fca7..de3b908741 100644 --- a/Applications/Piano/MainWidget.cpp +++ b/Applications/Piano/MainWidget.cpp @@ -75,7 +75,7 @@ void MainWidget::custom_event(Core::CustomEvent&) m_wave_widget->update(); if (m_audio_engine.time() == 0) - m_roll_widget->update_roll(); + m_roll_widget->update(); } void MainWidget::keydown_event(GUI::KeyEvent& event) diff --git a/Applications/Piano/Music.h b/Applications/Piano/Music.h index cdd787cce8..2a0a030cf8 100644 --- a/Applications/Piano/Music.h +++ b/Applications/Piano/Music.h @@ -116,6 +116,8 @@ constexpr int black_keys_per_octave = 5; constexpr int octave_min = 1; constexpr int octave_max = 7; +constexpr int horizontal_notes = 32; + // Equal temperament, A = 440Hz // We calculate note frequencies relative to A4: // 440.0 * pow(pow(2.0, 1.0 / 12.0), N) diff --git a/Applications/Piano/RollWidget.cpp b/Applications/Piano/RollWidget.cpp index 8b2a8f93cd..12e5e9a9db 100644 --- a/Applications/Piano/RollWidget.cpp +++ b/Applications/Piano/RollWidget.cpp @@ -53,7 +53,7 @@ RollWidget::~RollWidget() void RollWidget::paint_event(GUI::PaintEvent& event) { int roll_width = widget_inner_rect().width(); - double note_width = static_cast(roll_width) / m_horizontal_notes; + double note_width = static_cast(roll_width) / horizontal_notes; set_content_size({ roll_width, roll_height }); @@ -74,7 +74,7 @@ void RollWidget::paint_event(GUI::PaintEvent& event) for (int y = 0; y < notes_to_paint; ++y) { int y_pos = y * note_height; - for (int x = 0; x < m_horizontal_notes; ++x) { + for (int x = 0; x < horizontal_notes; ++x) { // This is needed to avoid rounding errors. You can't just use // note_width as the width. int x_pos = x * note_width; @@ -82,9 +82,9 @@ void RollWidget::paint_event(GUI::PaintEvent& event) int distance_to_next_x = next_x_pos - x_pos; Gfx::Rect rect(x_pos, y_pos, distance_to_next_x, note_height); - if (m_roll_notes[y + note_offset][x] == On) + if (m_audio_engine.roll_note(y + note_offset, x) == On) painter.fill_rect(rect, note_pressed_color); - else if (x == m_current_column) + else if (x == m_audio_engine.current_column()) painter.fill_rect(rect, column_playing_color); else if (key_pattern[key_pattern_index] == Black) painter.fill_rect(rect, Color::LightGray); @@ -108,7 +108,7 @@ void RollWidget::mousedown_event(GUI::MouseEvent& event) return; int roll_width = widget_inner_rect().width(); - double note_width = static_cast(roll_width) / m_horizontal_notes; + double note_width = static_cast(roll_width) / horizontal_notes; int y = (event.y() + vertical_scrollbar().value()) - frame_thickness(); y /= note_height; @@ -125,30 +125,7 @@ void RollWidget::mousedown_event(GUI::MouseEvent& event) ++x; x /= note_width; - if (m_roll_notes[y][x] == On) { - if (x == m_current_column) // If you turn off a note that is playing. - m_audio_engine.set_note((note_count - 1) - y, Off); - m_roll_notes[y][x] = Off; - } else { - m_roll_notes[y][x] = On; - } - - update(); -} - -void RollWidget::update_roll() -{ - if (++m_current_column == m_horizontal_notes) - m_current_column = 0; - if (++m_previous_column == m_horizontal_notes) - m_previous_column = 0; - - for (int note = 0; note < note_count; ++note) { - if (m_roll_notes[note][m_previous_column] == On) - m_audio_engine.set_note((note_count - 1) - note, Off); - if (m_roll_notes[note][m_current_column] == On) - m_audio_engine.set_note((note_count - 1) - note, On); - } + m_audio_engine.set_roll_note(y, x, m_audio_engine.roll_note(y, x) == On ? Off : On); update(); } diff --git a/Applications/Piano/RollWidget.h b/Applications/Piano/RollWidget.h index 7eea45bf76..dfbef95300 100644 --- a/Applications/Piano/RollWidget.h +++ b/Applications/Piano/RollWidget.h @@ -37,8 +37,6 @@ class RollWidget final : public GUI::ScrollableWidget { public: virtual ~RollWidget() override; - void update_roll(); - private: RollWidget(GUI::Widget* parent, AudioEngine&); @@ -46,9 +44,4 @@ private: virtual void mousedown_event(GUI::MouseEvent& event) override; AudioEngine& m_audio_engine; - - int m_horizontal_notes { 32 }; - Switch m_roll_notes[note_count][32] { { Off } }; - int m_current_column { 0 }; - int m_previous_column { m_horizontal_notes - 1 }; };