Commit d8f6193c authored by Jacob Vosmaer's avatar Jacob Vosmaer

Move note tracking to poly.c

parent ed669f07
......@@ -71,11 +71,52 @@ test_push(void)
assert(l_empty(&l));
}
void
test_contains(void)
{
desc("test l_contains()");
l_flush(&l);
l_push(&l, 3);
l_push(&l, 4);
l_push(&l, 10);
l_push(&l, 1);
assert(!l_contains(&l, 0));
assert(l_contains(&l, 1));
assert(!l_contains(&l, 2));
assert(l_contains(&l, 3));
assert(l_contains(&l, 4));
assert(!l_contains(&l, 5));
assert(!l_contains(&l, 6));
assert(!l_contains(&l, 7));
assert(!l_contains(&l, 8));
assert(!l_contains(&l, 9));
for (uint8_t i = 10; i != 0; i++) {
assert(!l_contains(&l, i));
}
l_flush(&l);
// paranoid test, what if there are 3s everywhere
for (uint8_t i = 0; i < TEST_ARRAY_SIZE; i++) {
test_array[i] = 3;
}
assert(!l_contains(&l, 3));
assert(l_empty(&l));
l_push(&l, 4);
assert(!l_contains(&l, 3));
assert(l_contains(&l, 4));
}
int
main(int argc, char** argv)
{
test_flush();
test_empty();
test_push();
test_contains();
return 0;
}
......@@ -69,3 +69,20 @@ l_empty(struct list *l)
{
return l->head == l->sup;
}
uint8_t
l_contains(struct list *l, uint8_t x)
{
if (x >= l->sup) {
return 0;
}
for (uint8_t i = l->head; i != l->sup; i = succ(l, i)) {
if (i == x) {
return 1;
}
}
return 0;
}
......@@ -15,5 +15,6 @@ uint8_t l_first(struct list *l);
uint8_t l_last(struct list *l);
void l_flush(struct list *l);
uint8_t l_empty(struct list *l);
uint8_t l_contains(struct list *l, uint8_t x);
#endif
......@@ -9,6 +9,8 @@ poly_init(void)
voice_init();
}
static uint8_t notes[NUM_VOICES];
void
poly_note_on(uint8_t note)
{
......@@ -20,16 +22,16 @@ poly_note_on(uint8_t note)
dac_set_note(v, note);
gate_on(v);
notes[v] = note;
}
void
poly_note_off(uint8_t note)
{
uint8_t v = voice_release(note);
if (v == NUM_VOICES) {
// This can happen if we get a spurious note off message from MIDI
return;
for (uint8_t v = 0; v < NUM_VOICES; v++) {
if (notes[v] == note) {
voice_release(v);
gate_off(v);
}
}
gate_off(v);
}
......@@ -40,8 +40,8 @@
// pointers. It is used to track which voices are available (i.e. not
// playing). It is a queue in order to get 'rotating' voice assignment.
uint8_t avail_array[NUM_VOICES];
struct list avail = {
static uint8_t avail_array[NUM_VOICES];
static struct list avail = {
.array = avail_array,
.sup = NUM_VOICES,
};
......@@ -66,31 +66,12 @@ avail_dequeue(void)
return v;
}
// playing is an ordered set implemented as a sort of bounded singly linked
// list. It is used to keep track of which notes are playing. The linked
// list aspect is used to be able to determine the oldest playing note,
// and to be able to remove voices from anywhere in the list. A voice may
// only occur once in the list.
uint8_t playing_array[NUM_VOICES];
struct list playing = {
static uint8_t playing_array[NUM_VOICES];
static struct list playing = {
.array = playing_array,
.sup = NUM_VOICES,
};
// playing_head is a number between 0 and NUM_VOICES. if playing_head < NUM_VOICES it
// indicates the last voice that started playing. If playing_head == NUM_VOICES,
// the playing data structure is empty.
// playing[i] for i < NUM_VOICES is the number of the voice that was last before i became last.
// -- empty playing list
// playing_head -> N
// -- add voice 1
// playing_head -> 1, playing[1] = N
// -- add voice 3
// playing_head -> 3, playing[3] = 1, playing[1] = N
void
playing_play(uint8_t v)
{
......@@ -109,10 +90,6 @@ playing_oldest(void)
return l_last(&playing);
}
// notes maps voices to the MIDI note they are currently playing, if they
// are playing. If v is not playing the meaning / value of notes[v] is undefined.
uint8_t notes[NUM_VOICES];
void
voice_init(void)
{
......@@ -138,7 +115,7 @@ release_oldest(void)
}
uint8_t
voice_acquire(uint8_t note)
voice_acquire()
{
if (avail_is_empty()) {
release_oldest();
......@@ -151,27 +128,14 @@ voice_acquire(uint8_t note)
}
playing_play(v);
notes[v] = note;
return v;
}
uint8_t
voice_release(uint8_t note)
void
voice_release(uint8_t v)
{
// Find oldest voice playing this note
uint8_t v = NUM_VOICES;
for (uint8_t i = playing.head; i != playing.sup; i = playing.array[i]) {
if (notes[i] == note) {
v = i;
}
if (l_contains(&playing, v)) {
playing_release(v);
avail_enqueue(v);
}
if (v == NUM_VOICES) {
// This is possible if we received a bogus MIDI 'note off'.
return NUM_VOICES;
}
playing_release(v);
avail_enqueue(v);
return v;
}
......@@ -13,11 +13,10 @@ enum _voices {
void voice_init(void);
// voice_acquire returns a voice number for playing the given note
uint8_t voice_acquire(uint8_t note);
// voice_acquire returns a voice number for playing a new note
uint8_t voice_acquire();
// voice_release returns a voice number that is playing the given note.
// If no voice is playing the note, voice_release returns NUM_VOICES.
uint8_t voice_release(uint8_t note);
// voice_release releases a voice, if playing. If v is not playing this is a no-op.
void voice_release(uint8_t v);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment