poly2.c 2.02 KB
Newer Older
1
#include "pitch.h"
2 3 4 5 6 7 8 9 10 11
#include "poly2.h"
#include "gate.h"
#include "voice.h"
#include "vibrato.h"
#include "midi.h"
#include "list.h"
#include "notes.h"

static uint8_t playing[NUM_VOICES];
static uint16_t current_bend;
12
static uint8_t current_note[NUM_VOICES];
13

14 15
INIT_LIST(avail, NUM_VOICES);
INIT_LIST(want_play, NUM_NOTES);
16 17 18 19 20 21

void poly2_update_playing(void);

void
poly2_init(void)
{
22 23
	l_flush(want_play);
	l_flush(avail);
Jacob Vosmaer's avatar
Jacob Vosmaer committed
24
	for_each_voice(i) {
25
		playing[i] = NUM_NOTES;
26
		current_note[i] = NUM_NOTES;
27
		l_push(avail, i);
28 29 30 31 32 33 34 35
	}

	current_bend = BEND_CENTER;
}

void
poly2_set_pitch(uint8_t v, uint8_t note)
{
36
	pitch_set_note(v, note, vibrato_detune(), current_bend);
37 38 39 40 41 42 43 44 45
}

void
poly2_note_on(uint8_t note)
{
	if (note >= NUM_NOTES) {
		return; // should never happen
	}

46
	l_append(want_play, note);
47 48 49 50 51 52
	poly2_update_playing();
}

static uint8_t
poly2_is_playing(uint8_t note)
{
Jacob Vosmaer's avatar
Jacob Vosmaer committed
53
	for_each_voice(v) {
54 55 56 57 58 59 60 61 62 63 64
		if (playing[v] == note) {
			return 1;
		}
	}

	return 0;
}

void
poly2_update_playing(void)
{
Jacob Vosmaer's avatar
Jacob Vosmaer committed
65
	for_each_voice(v) {
66
		if ((playing[v] < NUM_NOTES) && !(l_index(want_play, playing[v]) < NUM_VOICES)) {
67 68
			gate_off(v);
			playing[v] = NUM_NOTES;
69
			l_push(avail, v);
70 71 72
		}
	}

73 74 75 76 77
	for (
		uint8_t i = 0, j = want_play->head;
		(i < NUM_VOICES) && (j != want_play->sup);
		i++, (j = l_succ(want_play, j))
	) {
78 79 80 81
		if (poly2_is_playing(j)) {
			continue;
		}

82 83
		uint8_t v = l_last(avail);
		if (v == avail->sup) {
84 85 86 87 88
			// no voices available
			continue;
		}

		poly2_set_pitch(v, j);
89
		gate_on(v);
90
		playing[v] = j;
91
		current_note[v] = j;
92
		l_delete(avail, v);
93 94 95 96 97 98 99 100 101 102
	}
}

void
poly2_note_off(uint8_t note)
{
	if (note >= NUM_NOTES) {
		return; // should never happen
	}

103
	l_delete(want_play, note);
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	poly2_update_playing();
}

void
poly2_control_change(uint8_t ctl, uint8_t val)
{
	switch (ctl) {
	case CC_MOD_WHEEL:
		vibrato_set_depth(val);
		break;
	case CC_VIB_RATE:
		vibrato_set_rate(val);
		break;
	}
}

void
poly2_pitch_bend(uint16_t bend)
{
	current_bend = bend;
}

void
poly2_update_clock(uint8_t delta)
{
129
	(void) delta;
130

Jacob Vosmaer's avatar
Jacob Vosmaer committed
131
	for_each_voice(v) {
132
		poly2_set_pitch(v, current_note[v]);
133 134
	}
}