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().
This commit is contained in:
William McPherson 2020-02-06 19:13:25 +11:00 committed by Andreas Kling
parent 82d17d2c79
commit 9a05bbaace
Notes: sideshowbarker 2024-07-19 09:33:42 +09:00
6 changed files with 47 additions and 38 deletions

View file

@ -113,8 +113,10 @@ void AudioEngine::fill_buffer(FixedArray<Sample>& 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) {

View file

@ -40,6 +40,8 @@ public:
~AudioEngine();
const FixedArray<Sample>& 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<Sample>& 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<Sample> 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 };
};

View file

@ -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)

View file

@ -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)

View file

@ -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<double>(roll_width) / m_horizontal_notes;
double note_width = static_cast<double>(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<double>(roll_width) / m_horizontal_notes;
double note_width = static_cast<double>(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();
}

View file

@ -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 };
};