Skip to content

Commit

Permalink
Drop notes when note priority stack full (after 10 concurrent 'note o…
Browse files Browse the repository at this point in the history
…n's)
  • Loading branch information
rhargreaves committed Jul 17, 2024
1 parent 197d7c9 commit fe82769
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 28 deletions.
4 changes: 4 additions & 0 deletions src/midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,10 @@ void midi_note_on(u8 chan, u8 pitch, u8 velocity)

if (!dynamicMode) {
MidiChannel* midiChannel = &midiChannels[chan];
if (note_priority_isFull(&midiChannel->notePriority)) {
log_warn("Ch %d: Note priority stack full", chan + 1);
return;
}
note_priority_push(&midiChannel->notePriority, pitch);
midiChannel->prevVelocity = velocity;
}
Expand Down
11 changes: 6 additions & 5 deletions src/note_priority.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ void note_priority_init(NotePriorityStack* notePriority)
void note_priority_push(NotePriorityStack* notePriority, u8 pitch)
{
if (notePriority->top == NOTE_PRIORITY_LENGTH - 1) {
// rewrite array, evicting oldest item
for (u16 i = 0; i < notePriority->top; i++) {
notePriority->slot[i] = notePriority->slot[i + 1];
}
notePriority->top--;
return;
}
notePriority->slot[++notePriority->top] = pitch;
}
Expand All @@ -43,3 +39,8 @@ void note_priority_remove(NotePriorityStack* notePriority, u8 pitch)
}
notePriority->top = writeCursor;
}

bool note_priority_isFull(NotePriorityStack* notePriority)
{
return notePriority->top == NOTE_PRIORITY_LENGTH - 1;
}
2 changes: 2 additions & 0 deletions src/note_priority.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <types.h>
#include <stdbool.h>

#define NOTE_PRIORITY_LENGTH 10

Expand All @@ -12,3 +13,4 @@ void note_priority_init(NotePriorityStack* notePriority);
void note_priority_push(NotePriorityStack* notePriority, u8 pitch);
u8 note_priority_pop(NotePriorityStack* notePriority);
void note_priority_remove(NotePriorityStack* notePriority, u8 pitch);
bool note_priority_isFull(NotePriorityStack* notePriority);
5 changes: 3 additions & 2 deletions tests/unit/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ int main(void)
midi_test(test_midi_pitch_bends_up_an_octave_upper_freq_limit),
midi_test(test_midi_persists_pitch_bend_between_notes),
midi_test(test_midi_note_priority_respected_for_multiple_notes),
midi_test(test_midi_note_priority_removes_oldest_when_full),
midi_test(test_midi_drops_note_when_note_priority_stack_full),

midi_test(test_midi_sets_psg_pitch_bend_down),
midi_test(test_midi_sets_psg_pitch_bend_up),
Expand Down Expand Up @@ -368,7 +368,8 @@ int main(void)
buffer_test(test_buffer_returns_cannot_write_if_full),
buffer_test(test_buffer_returns_can_write_if_empty),

note_priority_test(test_note_priority_evicts_old_items)
note_priority_test(test_note_priority_ignores_push_when_full),
note_priority_test(test_note_priority_indicates_when_full)
// clang-format on
};

Expand Down
22 changes: 4 additions & 18 deletions tests/unit/test_midi_fm.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,13 +730,13 @@ static void test_midi_note_priority_respected_for_multiple_notes(
__real_midi_note_off(0, MIDI_PITCH_CS4);
}

#define NOTE_PRIORITY_OVERFLOW_LENGTH 11
#define NOTE_PRIORITY_OVERFLOW_LENGTH 10

static void test_midi_note_priority_removes_oldest_when_full(
static void test_midi_drops_note_when_note_priority_stack_full(
UNUSED void** state)
{
const u16 expectedFreqNum[NOTE_PRIORITY_OVERFLOW_LENGTH] = { 0x25f, 0x284,
0x2a9, 0x2d2, 0x2fd, 0x32a, 0x35a, 0x38e, 0x3c4, 0x3fd, 0x439 };
0x2a9, 0x2d2, 0x2fd, 0x32a, 0x35a, 0x38e, 0x3c4, 0x3fd };
const u8 expectedOctave = 4;

for (u16 i = 0; i < NOTE_PRIORITY_OVERFLOW_LENGTH; i++) {
Expand All @@ -752,19 +752,5 @@ static void test_midi_note_priority_removes_oldest_when_full(
__real_midi_note_on(0, pitch, MAX_MIDI_VOLUME);
}

for (s16 i = NOTE_PRIORITY_OVERFLOW_LENGTH - 1; i >= 2; i--) {
u8 pitch = 59 + i;
u16 freqNum = expectedFreqNum[i - 1];

print_message("noteOff: pitch = %d, freqNum = 0x%x, octave = %d\n",
pitch, freqNum, expectedOctave);

expect_synth_pitch(0, expectedOctave, freqNum);
expect_synth_volume_any();
expect_value(__wrap_synth_noteOn, channel, 0);
__real_midi_note_off(0, pitch);
}

expect_value(__wrap_synth_noteOff, channel, 0);
__real_midi_note_off(0, 60);
__real_midi_note_on(0, 100, MAX_MIDI_VOLUME);
}
2 changes: 2 additions & 0 deletions tests/unit/test_midi_psg.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ static void test_midi_shifts_semitone_in_psg_envelope(UNUSED void** state)

expect_psg_tone(expectedPsgChan, expectedInitialTone);
__real_midi_psg_tick();

__real_midi_note_off(chan, MIDI_PITCH_C4);
}
}

Expand Down
19 changes: 16 additions & 3 deletions tests/unit/test_note_priority.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,33 @@ static int test_note_priority_setup(UNUSED void** state)
return 0;
}

static void test_note_priority_evicts_old_items(UNUSED void** state)
static void test_note_priority_ignores_push_when_full(UNUSED void** state)
{
const u16 additive = 50;

for (u16 i = 0; i <= 11; i++) {
for (u16 i = 0; i < NOTE_PRIORITY_LENGTH + 1; i++) {
// print_message("pushing %d\n", i + additive);
note_priority_push(&testStack, i + additive);
}

for (s16 i = 11; i > 1; i--) {
for (s16 i = NOTE_PRIORITY_LENGTH - 1; i >= 0; i--) {
u8 item = note_priority_pop(&testStack);
u8 expected = i + additive;

// print_message("expected %d, popping %d\n", expected, item);
assert_int_equal(item, expected);
}

u8 nilPop = note_priority_pop(&testStack);
assert_int_equal(nilPop, 0);
}

static void test_note_priority_indicates_when_full(UNUSED void** state)
{
for (u16 i = 0; i < NOTE_PRIORITY_LENGTH; i++) {
assert_int_equal(note_priority_isFull(&testStack), false);
note_priority_push(&testStack, i);
}

assert_int_equal(note_priority_isFull(&testStack), true);
}

0 comments on commit fe82769

Please sign in to comment.