mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 10:12:25 -05:00
Piano: Make note() callable by multiple sources
Rather than checking key codes and mouse positions, we should have a more general way to play notes. You can call note() either with a KeyCode or a PianoKey directly. Additionally, m_note_on[] is now an array of integers instead of bools. This allows multiple sources to play a note. This is kind of like a "reference counted note": two sources can increment the note and it will only turn off once they have both decremented it back to 0. We are now only using keys[] to prevent multiple consecutive calls to keydown_event() (when a key is held), since that would result in playing a note many times.
This commit is contained in:
parent
165765145c
commit
ebaadda6bd
Notes:
sideshowbarker
2024-07-19 10:45:03 +09:00
Author: https://github.com/willmcpherson2 Commit: https://github.com/SerenityOS/serenity/commit/ebaadda6bd4 Pull-request: https://github.com/SerenityOS/serenity/pull/898
2 changed files with 57 additions and 30 deletions
|
@ -64,7 +64,7 @@ void PianoWidget::fill_audio_buffer(uint8_t* stream, int len)
|
|||
auto* sst = (Sample*)stream;
|
||||
for (int i = 0; i < m_sample_count; ++i) {
|
||||
static const double volume = 1800;
|
||||
for (size_t n = 0; n < (sizeof(m_note_on) / sizeof(bool)); ++n) {
|
||||
for (size_t n = 0; n < (sizeof(m_note_on) / sizeof(u8)); ++n) {
|
||||
if (!m_note_on[n])
|
||||
continue;
|
||||
double val = 0;
|
||||
|
@ -85,7 +85,7 @@ void PianoWidget::fill_audio_buffer(uint8_t* stream, int len)
|
|||
|
||||
// Release pressed notes.
|
||||
if (m_release_enabled) {
|
||||
for (size_t n = 0; n < (sizeof(m_note_on) / sizeof(bool)); ++n) {
|
||||
for (size_t n = 0; n < (sizeof(m_note_on) / sizeof(u8)); ++n) {
|
||||
if (m_note_on[n])
|
||||
m_power[n] *= 0.965;
|
||||
}
|
||||
|
@ -171,21 +171,6 @@ int PianoWidget::octave_base() const
|
|||
return (m_octave - m_octave_min) * 12;
|
||||
}
|
||||
|
||||
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;
|
||||
m_note_on[n] = is_down;
|
||||
m_sin_pos[n] = 0;
|
||||
m_saw_pos[n] = 0;
|
||||
if (is_down)
|
||||
m_power[n] = 1;
|
||||
//printf("note[%u] = %u (%g)\n", (unsigned)n, is_down, note_frequency[n]);
|
||||
}
|
||||
|
||||
struct KeyDefinition {
|
||||
int index;
|
||||
PianoKey piano_key;
|
||||
|
@ -216,14 +201,45 @@ const KeyDefinition key_definitions[] = {
|
|||
{ 10, K_Gb2, "]", KeyCode::Key_RightBracket },
|
||||
};
|
||||
|
||||
void PianoWidget::update_keys()
|
||||
void PianoWidget::note(KeyCode key_code, SwitchNote switch_note)
|
||||
{
|
||||
for (auto& kd : key_definitions)
|
||||
note(kd.piano_key, kd.key_code);
|
||||
for (auto& kd : key_definitions) {
|
||||
if (kd.key_code == key_code) {
|
||||
note(kd.piano_key, switch_note);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PianoWidget::note(PianoKey piano_key, SwitchNote switch_note)
|
||||
{
|
||||
int n = octave_base() + piano_key;
|
||||
|
||||
if (switch_note == On) {
|
||||
if (m_note_on[n] == 0) {
|
||||
m_sin_pos[n] = 0;
|
||||
m_square_pos[n] = 0;
|
||||
m_saw_pos[n] = 0;
|
||||
m_triangle_pos[n] = 0;
|
||||
}
|
||||
++m_note_on[n];
|
||||
m_power[n] = 1;
|
||||
} else {
|
||||
if (m_note_on[n] > 1) {
|
||||
--m_note_on[n];
|
||||
} else if (m_note_on[n] == 1) {
|
||||
--m_note_on[n];
|
||||
m_power[n] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PianoWidget::keydown_event(GKeyEvent& event)
|
||||
{
|
||||
if (keys[event.key()])
|
||||
return;
|
||||
keys[event.key()] = true;
|
||||
|
||||
switch (event.key()) {
|
||||
case KeyCode::Key_C:
|
||||
|
||||
|
@ -246,17 +262,17 @@ void PianoWidget::keydown_event(GKeyEvent& event)
|
|||
++m_octave;
|
||||
memset(m_note_on, 0, sizeof(m_note_on));
|
||||
break;
|
||||
default:
|
||||
note((KeyCode)event.key(), On);
|
||||
}
|
||||
|
||||
keys[event.key()] = true;
|
||||
update_keys();
|
||||
update();
|
||||
}
|
||||
|
||||
void PianoWidget::keyup_event(GKeyEvent& event)
|
||||
{
|
||||
keys[event.key()] = false;
|
||||
update_keys();
|
||||
note((KeyCode)event.key(), Off);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -266,7 +282,10 @@ void PianoWidget::mousedown_event(GMouseEvent& event)
|
|||
|
||||
m_piano_key_under_mouse = find_key_for_relative_position(event.x() - x(), event.y() - y());
|
||||
|
||||
update_keys();
|
||||
if (!m_piano_key_under_mouse)
|
||||
return;
|
||||
|
||||
note(m_piano_key_under_mouse, On);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -274,7 +293,7 @@ void PianoWidget::mouseup_event(GMouseEvent&)
|
|||
{
|
||||
m_mouse_pressed = false;
|
||||
|
||||
update_keys();
|
||||
note(m_piano_key_under_mouse, Off);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -283,14 +302,17 @@ void PianoWidget::mousemove_event(GMouseEvent& event)
|
|||
if (!m_mouse_pressed)
|
||||
return;
|
||||
|
||||
int mouse_was_over = m_piano_key_under_mouse;
|
||||
PianoKey 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();
|
||||
if (mouse_was_over)
|
||||
note(mouse_was_over, Off);
|
||||
if (m_piano_key_under_mouse)
|
||||
note(m_piano_key_under_mouse, On);
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,13 @@ private:
|
|||
void render_knobs(GPainter&);
|
||||
void render_knob(GPainter&, const Rect&, bool state, const StringView&);
|
||||
|
||||
void note(Music::PianoKey offset_n, KeyCode key_code);
|
||||
void update_keys();
|
||||
enum SwitchNote {
|
||||
Off,
|
||||
On
|
||||
};
|
||||
void note(KeyCode, SwitchNote);
|
||||
void note(PianoKey, SwitchNote);
|
||||
|
||||
int octave_base() const;
|
||||
|
||||
int m_sample_count { 0 };
|
||||
|
@ -46,7 +51,7 @@ private:
|
|||
|
||||
#define note_count sizeof(note_frequency) / sizeof(double)
|
||||
|
||||
bool m_note_on[note_count];
|
||||
u8 m_note_on[note_count];
|
||||
double m_power[note_count];
|
||||
double m_sin_pos[note_count];
|
||||
double m_square_pos[note_count];
|
||||
|
|
Loading…
Add table
Reference in a new issue