mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 09:57:34 +00: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
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;
|
auto* sst = (Sample*)stream;
|
||||||
for (int i = 0; i < m_sample_count; ++i) {
|
for (int i = 0; i < m_sample_count; ++i) {
|
||||||
static const double volume = 1800;
|
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])
|
if (!m_note_on[n])
|
||||||
continue;
|
continue;
|
||||||
double val = 0;
|
double val = 0;
|
||||||
|
@ -85,7 +85,7 @@ void PianoWidget::fill_audio_buffer(uint8_t* stream, int len)
|
||||||
|
|
||||||
// Release pressed notes.
|
// Release pressed notes.
|
||||||
if (m_release_enabled) {
|
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])
|
if (m_note_on[n])
|
||||||
m_power[n] *= 0.965;
|
m_power[n] *= 0.965;
|
||||||
}
|
}
|
||||||
|
@ -171,21 +171,6 @@ int PianoWidget::octave_base() const
|
||||||
return (m_octave - m_octave_min) * 12;
|
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 {
|
struct KeyDefinition {
|
||||||
int index;
|
int index;
|
||||||
PianoKey piano_key;
|
PianoKey piano_key;
|
||||||
|
@ -216,14 +201,45 @@ const KeyDefinition key_definitions[] = {
|
||||||
{ 10, K_Gb2, "]", KeyCode::Key_RightBracket },
|
{ 10, K_Gb2, "]", KeyCode::Key_RightBracket },
|
||||||
};
|
};
|
||||||
|
|
||||||
void PianoWidget::update_keys()
|
void PianoWidget::note(KeyCode key_code, SwitchNote switch_note)
|
||||||
{
|
{
|
||||||
for (auto& kd : key_definitions)
|
for (auto& kd : key_definitions) {
|
||||||
note(kd.piano_key, kd.key_code);
|
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)
|
void PianoWidget::keydown_event(GKeyEvent& event)
|
||||||
{
|
{
|
||||||
|
if (keys[event.key()])
|
||||||
|
return;
|
||||||
|
keys[event.key()] = true;
|
||||||
|
|
||||||
switch (event.key()) {
|
switch (event.key()) {
|
||||||
case KeyCode::Key_C:
|
case KeyCode::Key_C:
|
||||||
|
|
||||||
|
@ -246,17 +262,17 @@ void PianoWidget::keydown_event(GKeyEvent& event)
|
||||||
++m_octave;
|
++m_octave;
|
||||||
memset(m_note_on, 0, sizeof(m_note_on));
|
memset(m_note_on, 0, sizeof(m_note_on));
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
note((KeyCode)event.key(), On);
|
||||||
}
|
}
|
||||||
|
|
||||||
keys[event.key()] = true;
|
|
||||||
update_keys();
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PianoWidget::keyup_event(GKeyEvent& event)
|
void PianoWidget::keyup_event(GKeyEvent& event)
|
||||||
{
|
{
|
||||||
keys[event.key()] = false;
|
keys[event.key()] = false;
|
||||||
update_keys();
|
note((KeyCode)event.key(), Off);
|
||||||
update();
|
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());
|
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();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +293,7 @@ void PianoWidget::mouseup_event(GMouseEvent&)
|
||||||
{
|
{
|
||||||
m_mouse_pressed = false;
|
m_mouse_pressed = false;
|
||||||
|
|
||||||
update_keys();
|
note(m_piano_key_under_mouse, Off);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,14 +302,17 @@ void PianoWidget::mousemove_event(GMouseEvent& event)
|
||||||
if (!m_mouse_pressed)
|
if (!m_mouse_pressed)
|
||||||
return;
|
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());
|
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)
|
if (m_piano_key_under_mouse == mouse_was_over)
|
||||||
return;
|
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();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,13 @@ private:
|
||||||
void render_knobs(GPainter&);
|
void render_knobs(GPainter&);
|
||||||
void render_knob(GPainter&, const Rect&, bool state, const StringView&);
|
void render_knob(GPainter&, const Rect&, bool state, const StringView&);
|
||||||
|
|
||||||
void note(Music::PianoKey offset_n, KeyCode key_code);
|
enum SwitchNote {
|
||||||
void update_keys();
|
Off,
|
||||||
|
On
|
||||||
|
};
|
||||||
|
void note(KeyCode, SwitchNote);
|
||||||
|
void note(PianoKey, SwitchNote);
|
||||||
|
|
||||||
int octave_base() const;
|
int octave_base() const;
|
||||||
|
|
||||||
int m_sample_count { 0 };
|
int m_sample_count { 0 };
|
||||||
|
@ -46,7 +51,7 @@ private:
|
||||||
|
|
||||||
#define note_count sizeof(note_frequency) / sizeof(double)
|
#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_power[note_count];
|
||||||
double m_sin_pos[note_count];
|
double m_sin_pos[note_count];
|
||||||
double m_square_pos[note_count];
|
double m_square_pos[note_count];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue