-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwrPoly.c
158 lines (119 loc) · 4.09 KB
/
wrPoly.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "wrPoly.h"
#include <stdlib.h> // malloc, sizeof
#include <stdio.h> // printf
#define RESERVED_PITCH ((int16_t)0x8000)
///////////////////////////////////////
// helper declarations
static void release_voice( poly_alloc_t* self, int8_t voice );
static int8_t find_note( poly_alloc_t* self, int16_t note );
static int8_t find_item( poly_list_t* self, int8_t item );
static int8_t take_front( poly_list_t* self );
static void put_end( poly_list_t* self, int8_t item );
static void drop_index( poly_list_t* self, uint8_t ix );
///////////////////////////////////////
// initialization
poly_alloc_t* poly_init( uint8_t voice_count )
{
poly_alloc_t* self = malloc( sizeof( poly_alloc_t ) );
if( !self ){ printf("poly malloc failed\n"); return NULL; }
self->voice_count = voice_count;
self->notes = malloc(sizeof(int16_t) * voice_count);
if( !self->notes ){ printf("poly !self->notes\n"); return NULL; }
self->busy.count = 0;
self->busy.list = malloc(sizeof(int8_t) * voice_count);
if( !self->busy.list ){ printf("poly !self->busy.list\n"); return NULL; }
self->free.count = voice_count;
self->free.list = malloc(sizeof(int8_t) * voice_count);
if( !self->free.list ){ printf("poly !self->free.list\n"); return NULL; }
for( uint8_t i=0; i<voice_count; i++ ){
self->notes[i] = RESERVED_PITCH;
self->busy.list[i] = -1;
self->free.list[i] = i;
}
return self;
}
void poly_deinit( poly_alloc_t* self )
{
free(self->free.list); self->free.list = NULL;
free(self->busy.list); self->busy.list = NULL;
free(self->notes); self->notes = NULL;
free(self); self = NULL;
}
///////////////////////////////////////
// public interface
int8_t poly_assign_note( poly_alloc_t* self, int16_t note )
{
if( note == RESERVED_PITCH ){ return -1; } // invalid pitch
int8_t voice = take_front( (self->free.count)
? &self->free
: &self->busy );
put_end( &self->busy, voice );
self->notes[voice] = note; // save pitch
return voice;
}
void poly_assign_voice( poly_alloc_t* self, int8_t voice, int16_t note )
{
if( voice < 0 || voice >= self->voice_count ){ return; } // invalid voice
if( note == RESERVED_PITCH ){ return; } // invalid pitch
release_voice( self, voice );
put_end( &self->busy, voice );
self->notes[voice] = note; // save pitch
}
int8_t poly_kill_note( poly_alloc_t* self, int16_t note )
{
if( note == RESERVED_PITCH ){ return -1; } // invalid pitch
int16_t voice = find_note( self, note );
poly_kill_voice( self, voice );
return voice;
}
void poly_kill_voice( poly_alloc_t* self, int8_t voice )
{
if( voice < 0 || voice >= self->voice_count ){ return; }
release_voice( self, voice );
put_end( &self->free, voice );
self->notes[voice] = RESERVED_PITCH; // forget pitch
}
///////////////////////////////////////
// helper fns
static void release_voice( poly_alloc_t* self, int8_t voice ){
int8_t ix = find_item( &self->busy, voice );
if( ix != -1 ){ // found in busy
drop_index( &self->busy, ix );
} else {
ix = find_item( &self->free, voice ); // found in free
drop_index( &self->free, ix );
}
}
static int8_t find_note( poly_alloc_t* self, int16_t note ){
for( uint8_t i=0; i < self->voice_count; i++ ){
if( note == self->notes[i] ){ return i; }
}
return -1;
}
static int8_t find_item( poly_list_t* self, int8_t item ){
for( uint8_t i=0; i < self->count; i++ ){
if( item == self->list[i] ){ return i; }
}
return -1;
}
static int8_t take_front( poly_list_t* self )
{
int8_t front = self->list[0];
self->count--;
// shift list forward
for( uint8_t i=0; i < self->count; i++ ){
self->list[i] = self->list[i+1];
}
return front;
}
static void put_end( poly_list_t* self, int8_t item )
{
self->list[self->count] = item;
self->count++;
}
static void drop_index( poly_list_t* self, uint8_t ix ){
--self->count;
for(; ix < self->count; ix++){
self->list[ix] = self->list[ix+1];
}
}