More efficient traversal of on notes.
[orgux.git] / core.c
blobb94e66471af4769df1d445e78c5a6f16b73755c4
1 /*
2 orgux - a just-for-fun real time synth
3 Copyright (C) 2009 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include <stdio.h>
21 #include <math.h>
22 #include <stdlib.h>
26 #include "orgux.h"
28 #include "constants.h"
29 #include "instruments.h"
35 extern void precompute(int sample_rate);
36 int precompute_ok = 0;
40 float square_wave[WAVEFORM_LENGTH];
41 float saw_wave[WAVEFORM_LENGTH];
42 float triangle_wave[WAVEFORM_LENGTH];
44 float waveform[128][WAVEFORM_LENGTH];
45 float waveform_M[128][WAVEFORM_LENGTH];
46 float waveform_Z[128][WAVEFORM_LENGTH];
48 float samples[SAMPLE_COUNT][SAMPLE_LENGTH];
49 int sample_len[SAMPLE_COUNT];
50 float antipop[ANTIPOP_LENGTH];
52 struct orgux_state{
53 float volume[16];
54 float pan_l[16];
55 float pan_r[16];
56 float bend[16];
57 int instrument[16];
59 int sample_rate;
60 float lp_alpha;
62 int command_queue[512][5]; /* sample type chan val1 val2 */
63 int command_count;
65 int note_on[MAX_NOTES];
66 int note_channel[MAX_NOTES];
67 int note_note[MAX_NOTES];
68 float velocity[MAX_NOTES];
69 int antipop_flag[MAX_NOTES];
70 int antipop_ptr[MAX_NOTES];
71 float wave_ptr[MAX_NOTES];
72 float wave_step[MAX_NOTES];
73 int sample_ptr[MAX_NOTES];
74 float lp_y[MAX_NOTES];
75 int note_max;
78 #define SWAP(X,Y,T) {T tmp = X; X = Y; Y = tmp;}
79 void note_swap(orgux_state* S, int i1, int i2){
81 SWAP(S->note_on[i1], S->note_on[i2], int);
82 SWAP(S->note_channel[i1], S->note_channel[i2], int);
83 SWAP(S->note_note[i1], S->note_note[i2], int);
84 SWAP(S->velocity[i1], S->velocity[i2], float);
85 SWAP(S->antipop_flag[i1], S->antipop_flag[i2], int);
86 SWAP(S->antipop_ptr[i1], S->antipop_ptr[i2], int);
87 SWAP(S->wave_ptr[i1], S->wave_ptr[i2], float);
88 SWAP(S->wave_step[i1], S->wave_step[i2], float);
89 SWAP(S->sample_ptr[i1], S->sample_ptr[i2], int);
93 void orgux_note_on(orgux_state* S, int chan, int note, int velocity){
95 int i=S->note_max;
97 if(i == MAX_NOTES) return;
99 S->note_on[i] = 1;
100 S->note_channel[i] = chan;
101 S->note_note[i] = note;
102 S->velocity[i] = ((float)velocity)/127;
103 S->antipop_flag[i] = -1;
104 S->antipop_ptr[i] = 0;
105 S->wave_ptr[i] = 0.0f;
106 S->sample_ptr[i] = 0;
107 //S->wave_step[i] = (int)((440*pow(2,(note-69)/12.0)*WAVEFORM_LENGTH)/S->sample_rate);
108 S->wave_step[i] = (440*pow(2,(note-69)/12.0)*WAVEFORM_LENGTH)/S->sample_rate;
109 S->note_max++;
111 //printf("note on i=%d\n",i);
112 for(int j=0; j<S->note_max; j++){
113 //printf("[%d %d %d %d]\n",S->note_on[j], S->note_channel[j], S->note_note[j], S->antipop_flag[j]);
118 void orgux_note_off(orgux_state* S, int chan, int note){
120 for(int i=0; i < S->note_max; i++){
121 if(S->note_on[i]==1 && S->note_channel[i]==chan && S->note_note[i]==note && S->antipop_flag[i]<1){
123 S->antipop_flag[i] = 1;
125 //printf("note end\n");
126 for(int j=0; j<S->note_max; j++){
127 //printf("[%d %d %d %d]\n",S->note_on[j], S->note_channel[j], S->note_note[j], S->antipop_flag[j]);
130 break;
136 void orgux_change_volume(orgux_state* S, int chan, int value){
137 //printf("change volume %d %d\n", chan, value);
138 S->volume[chan] = ((float)value)/127;
141 void orgux_change_pan(orgux_state* S, int chan, int value){
142 //printf("change pan %d %d\n", chan, value);
143 float P = (((float)value)/127) * 2 - 1;
145 if(P > 0){
146 S->pan_l[chan] = 1.0f - P;
147 S->pan_r[chan] = 1.0f;
149 else{
150 S->pan_l[chan] = 1.0f;
151 S->pan_r[chan] = P + 1.0f;
155 void orgux_change_instrument(orgux_state* S, int chan, int value){
156 //printf("change instrument %d %d\n", chan, value);
157 S->instrument[chan] = value;
160 void orgux_pitch_bend(orgux_state* S, int chan, int bend){
161 S->bend[chan] = ((((float)bend)/16383) * 2 - 1) * 1;
167 void orgux_process(orgux_state* S, float* lbuf, float* rbuf, int len){
168 int C=0;
170 int swap_ok = 0;
172 for(int i=0; i<len; i++){
174 while(i == S->command_queue[C][0] && C < S->command_count){
175 orgux_control(S, S->command_queue[C][1],
176 S->command_queue[C][2],
177 S->command_queue[C][3],
178 S->command_queue[C][4]);
179 C++;
182 lbuf[i] = 0.0f;
183 rbuf[i] = 0.0f;
185 int jmax = S->note_max;
186 for(int j=0; ;j++){
188 if(j >= jmax) break;
190 if(!S->note_on[j]) continue;
192 if(S->note_channel[j] == 9){
193 int index = S->note_note[j] - SAMPLE_NOTE_ZERO;
194 if(index < 0){index=0;}
195 if(index >= SAMPLE_COUNT){index=SAMPLE_COUNT-1;}
196 float y = samples[index][S->sample_ptr[j]++];
197 if(S->sample_ptr[j] == SAMPLE_LENGTH || S->sample_ptr[j] == sample_len[j]){
198 swap_ok = 1;
201 float V = S->volume[9];
202 float A = S->velocity[j];
203 lbuf[i] += V*A*S->pan_l[9]*y;
204 rbuf[i] += V*A*S->pan_r[9]*y;
206 //lbuf[i] += y;
207 //rbuf[i] += y;
209 if(swap_ok){
210 note_swap(S, j, S->note_max-1);
211 S->note_max--;
212 j--;
213 jmax--;
214 swap_ok = 0;
217 continue;
219 //continue;
221 int I = S->instrument[S->note_channel[j]];
222 /* hard computations */
223 /* float x = S->wave_ptr[j];
224 float x1 = floor(x);
225 float x2 = x1 + 1.0f;
226 int X1 = (int)x1;
227 int X2 = X1 + 1;
228 if(X2 == WAVEFORM_LENGTH) X2 = 0;
229 float y1 = waveform[I][X1];
230 float y2 = waveform[I][X2];
231 float m = (y2-y1)/(x2-x1);
232 float y = m*(x-x1) + y1;
235 float x = S->wave_ptr[j];
236 int X0 = (int)floor(x);
237 float y = waveform_Z[I][X0] + waveform_M[I][X0]*x;
239 //float y = 0;
242 int I = S->instrument[S->note_channel[j]];
243 int X = S->wave_ptr[j];
244 float y = S->waveform[I][X];
247 //float y0 = S->lp_y[j];
248 //y = y0 + S->lp_alpha * (y - y0);
249 //S->lp_y[j] = y;
251 switch(S->antipop_flag[j]){
252 case -1:
253 y *= antipop[S->antipop_ptr[j]];
254 S->antipop_ptr[j]++;
256 if(S->antipop_ptr[j] == ANTIPOP_LENGTH){
257 S->antipop_ptr[j] = ANTIPOP_LENGTH-1;
258 S->antipop_flag[j] = 0;
260 break;
261 case 1:
262 y *= antipop[S->antipop_ptr[j]];
263 S->antipop_ptr[j]--;
264 if(S->antipop_ptr[j] < 0){
265 swap_ok = 1;
267 break;
271 int chan = S->note_channel[j];
272 float volume = S->volume[chan];
273 float velocity = S->velocity[j];
274 lbuf[i] += volume*velocity*S->pan_l[chan]*y;
275 rbuf[i] += volume*velocity*S->pan_r[chan]*y;
277 if(lbuf[i]> 1.0 || lbuf[i] < -1.0){
278 printf("ehh lbuf[%d] = %f\n",i,lbuf[i]);
279 printf("%f %f %f %f %f\n",y,volume, velocity, S->pan_l[chan], S->pan_r[chan]);
282 S->wave_ptr[j] += S->wave_step[j];
283 while(S->wave_ptr[j] >= WAVEFORM_LENGTH){
284 S->wave_ptr[j] -= WAVEFORM_LENGTH;
287 if(swap_ok){ /* kills note */
288 note_swap(S, j, S->note_max-1);
289 S->note_max--;
290 j--;
291 jmax--;
292 swap_ok = 0;
293 //printf("note off\n");
294 for(int z=0; z<S->note_max; z++){
295 //printf("[%d %d %d %d]\n",S->note_on[z], S->note_channel[z], S->note_note[z], S->antipop_flag[z]);
303 S->command_count = 0;
310 void orgux_schedule(orgux_state* S, int sample, unsigned char midi[3]){
311 //orgux_control(S, midi[0]&0xf0, midi[0]&0x0f, midi[1], midi[2]);
313 if(S->command_count == MAX_COMMANDS){
314 return;
317 switch(midi[0]&0xf0){
318 case 0xA0:
319 case 0xD0:
320 return;
323 the queue is sorted by time (sample)
324 soonest times are to the beginning of the queue
325 queue[0] is the first element
326 insert: move all later events right one
329 //printf("schedule %d %x %x %x\n",sample,midi[0],midi[1],midi[2]);
330 int i;
331 for(i=0; i<S->command_count; i++){
333 if(sample < S->command_queue[i][0]){
335 for(int j=S->command_count; j>i; j--){
336 S->command_queue[j][0] = S->command_queue[j-1][0];
337 S->command_queue[j][1] = S->command_queue[j-1][1];
338 S->command_queue[j][2] = S->command_queue[j-1][2];
339 S->command_queue[j][3] = S->command_queue[j-1][3];
340 S->command_queue[j][4] = S->command_queue[j-1][4];
343 S->command_queue[i][0] = sample;
344 S->command_queue[i][1] = midi[0]&0xf0;
345 S->command_queue[i][2] = midi[0]&0x0f;
346 S->command_queue[i][3] = midi[1];
347 S->command_queue[i][4] = midi[2];
349 break;
353 if(i==S->command_count){//end of queue
354 S->command_queue[i][0] = sample;
355 S->command_queue[i][1] = midi[0]&0xf0;
356 S->command_queue[i][2] = midi[0]&0x0f;
357 S->command_queue[i][3] = midi[1];
358 S->command_queue[i][4] = midi[2];
361 S->command_count++;
362 /*for(int i=0; i<S->command_count; i++){
363 printf("%d %d %d %d %d\n",
364 S->command_queue[i][0],
365 S->command_queue[i][1],
366 S->command_queue[i][2],
367 S->command_queue[i][3],
368 S->command_queue[i][4]);
374 void orgux_control(orgux_state* S, int type, int chan, int val1, int val2){
376 int bend = (val1 << 7) + val2;
378 //printf("control %d %d %d %d\n", chan, type, val1, val2);
380 switch(type){
381 case 0x90:
382 orgux_note_on(S, chan, val1, val2);
383 return;
384 case 0x80:
385 orgux_note_off(S, chan, val1);
386 return;
387 case 0xC0:
388 orgux_change_instrument(S, chan, val1);
389 return;
390 case 0xB0:
391 if(val1 == 7){
392 orgux_change_volume(S, chan, val2);
394 else if(val1 == 10){
395 orgux_change_pan(S, chan, val2);
397 return;
398 case 0xE0:
399 orgux_pitch_bend(S, chan, bend);
400 return;
406 orgux_state* orgux_init(int sample_rate){
407 orgux_state* S = malloc(sizeof(orgux_state));
408 if(!S) return NULL;
412 /*precompute waveforms*/
413 if(!precompute_ok){
415 precompute(sample_rate);
416 precompute_ok = 1;
420 /* setup oscillator states */
422 for(int i=0; i<16; i++){
423 S->volume[i] = 1.0f;
424 S->pan_l[i] = 1.0f;
425 S->pan_r[i] = 1.0f;
428 for(int i=0; i<MAX_NOTES; i++){
429 S->wave_ptr[i] = 0.0f;
430 S->antipop_ptr[i] = 0;
431 S->antipop_flag[i] = 0;
432 S->note_on[i] = 0;
433 S->sample_ptr[i] = 0;
434 S->lp_y[i] = 0;
437 S->sample_rate = sample_rate;
439 S->command_count = 0;
440 S->note_max = 0;
442 //S->lp_alpha = dt/(dt+0.001);
444 return S;
448 void orgux_free(orgux_state* S){
449 free(S);