...
 
Commits (3)
......@@ -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
......@@ -5,8 +5,8 @@
#include "list.h"
#define NUM_NOTES 128
uint8_t notes_array[NUM_NOTES];
struct list notes = {
static uint8_t notes_array[NUM_NOTES];
static struct list notes = {
.array = notes_array,
.sup = NUM_NOTES,
};
......
......@@ -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);
}
#include "voice.h"
#include "queue.h"
#include "list.h"
// The voice assigner moves voices between the 'avail' (available) queue
......@@ -41,55 +40,38 @@
// 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 + 1];
struct queue avail = {
static uint8_t avail_array[NUM_VOICES];
static struct list avail = {
.array = avail_array,
.size = NUM_VOICES,
.sup = NUM_VOICES,
};
void
avail_enqueue(uint8_t v)
{
q_enqueue(&avail, v);
l_push(&avail, v);
}
uint8_t
avail_is_empty(void)
{
return q_empty(&avail);
return l_empty(&avail);
}
uint8_t
avail_dequeue(void)
{
return q_dequeue(&avail);
uint8_t v = l_last(&avail);
l_delete(&avail, v);
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)
{
......@@ -108,14 +90,10 @@ 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)
{
q_flush(&avail);
l_flush(&avail);
for (uint8_t i = 0; i < NUM_VOICES; i++) {
avail_enqueue(i);
}
......@@ -137,7 +115,7 @@ release_oldest(void)
}
uint8_t
voice_acquire(uint8_t note)
voice_acquire()
{
if (avail_is_empty()) {
release_oldest();
......@@ -150,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