Commit adcf2ec4 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Add more comments, some small code polish

parent fda94046
......@@ -43,6 +43,7 @@ note_on(uint8_t note)
{
uint8_t v = voice_acquire(note);
if (v == NUM_VOICES) {
// This should never happen if the voice assigner is working correctly.
return;
}
......@@ -55,6 +56,7 @@ 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;
}
......@@ -78,7 +80,7 @@ main(void)
uint8_t note = midi_data() >> 8;
uint8_t velocity = midi_data() & 0xff;
if (velocity) {
if (velocity > 0) {
note_on(note);
} else {
note_off(note);
......
......@@ -9,10 +9,10 @@ enum _statuses {
MIDI_NUM_STATUSES,
};
uint8_t midi_read();
void midi_init();
uint8_t midi_read(void);
void midi_init(void);
void midi_set_channel(uint8_t channel);
uint8_t midi_status();
uint16_t midi_data();
uint8_t midi_status(void);
uint16_t midi_data(void);
#endif
#include "voice.h"
// The voice assigner moves voices between the 'avail' (available) queue
// and the 'playing' list. The 'avail' data structure is a queue to get a
// pleasing 'rotating' voice assignment effect. The 'playing' list is a
// linked list to be able to free up arbitrary voices when they get
// released, and to be able to find the longest playing voices in case we
// need to steal a voice.
// -- initial condition
// avail: 0,1,2,3 playing: empty
// -- play voice 0
// avail: 1,2,3 playing: 0
// -- play voice 1. Note that we are drawing the 'playing' structure backwards here.
// avail: 2, 3 playing: 0, 1 <- playing_head
// -- release voice 0
// avail: 2, 3, 0 playing: 1
// -- play voice 2
// avail: 3, 0 playing: 1, 2
// -- play voice 3
// avail: 0 playing: 1, 2, 3
// -- play voice 0
// avail: empty playing: 1, 2, 3, 0
// -- new voice is requested: we must steal one first. voice 1 is the oldest now; we release it.
// avail: 1 playing: 2, 3, 0
// -- now use voice 1 and add it to the back (playing_head) of the playing list
// avail: empty playing: 2, 3, 0, 1
// -- example of 'rotating' effect
// avail: 0, 1, 2, 3 playing: empty
// -- play 0
// avail: 1, 2, 3 playing: 0
// -- release 0
// avail: 1, 2, 3, 0 playing: empty
// -- now we play 1
// avail: 2, 3, 0, 1 playing: 1
// avail is a fixed-size queue implemented with an array and two
// 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.
......@@ -49,7 +84,7 @@ avail_dequeue(void)
return v;
}
// play is an ordered set implemented as a sort of bounded singly linked
// 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
......@@ -57,6 +92,19 @@ avail_dequeue(void)
uint8_t playing[NUM_VOICES];
uint8_t playing_head = 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)
{
......@@ -91,7 +139,7 @@ playing_oldest(void)
}
// notes maps voices to the MIDI note they are currently playing, if they
// are playing.
// are playing. If v is not playing the meaning / value of notes[v] is undefined.
uint8_t notes[NUM_VOICES];
void
......
......@@ -8,11 +8,16 @@ enum _voices {
VOICE2,
VOICE3,
VOICE4,
NUM_VOICES,
NUM_VOICES, // dual use: number of voices, but also the "not found" or "empty" response
};
void voice_init(void);
// voice_acquire returns a voice number for playing the given note
uint8_t voice_acquire(uint8_t note);
// 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);
#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