Added alternative bases square, triangle, and sawtooth.
[orgux.git] / core.c
blobf2b5a38a35fec4565a4398b8d56ed5fcca6df54a
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>
24 #define PI 3.141592653589
25 #define PI2 PI*2
27 #include "orgux.h"
29 #include "instruments.h"
32 #define SAMPLE_LENGTH 1<<16
33 #define SAMPLE_COUNT 16
34 #define SAMPLE_NOTE_ZERO 60
36 #define ANTIPOP_LENGTH 512
37 #define WAVEFORM_LENGTH (1<<10)
39 #define MAX_COMMANDS 256
40 #define MAX_NOTES 128
42 #define RANDF() (((float)rand())/RAND_MAX)
44 #define SINE_BASE 128
45 #define SQUARE_BASE 129
46 #define TRIANGLE_BASE 130
47 #define SAW_BASE 131
50 int precompute_ok = 0;
51 float square_wave[WAVEFORM_LENGTH];
52 float saw_wave[WAVEFORM_LENGTH];
53 float triangle_wave[WAVEFORM_LENGTH];
55 float linterp(float x, int k, float wave[]){
56 int X0 = (int)floor(x-floor(x/WAVEFORM_LENGTH));
57 int X1 = X0+1;
58 if(X1 == WAVEFORM_LENGTH) X1 = 0;
60 float y1 = wave[X1];
61 float y0 = wave[X0];
62 float m = (y1-y0)/(X1-X0);
64 return m*(x-X0)+y0;
68 struct orgux_state{
69 float volume[16];
70 float pan_l[16];
71 float pan_r[16];
72 float bend[16];
73 int instrument[16];
75 //float velocity[16][128];
76 unsigned char onbits[16][16];
78 float waveform[128][WAVEFORM_LENGTH];
79 float antipop[ANTIPOP_LENGTH];
80 //float wave_ptr[16][128];
81 //float wave_step[16][128];
83 //int env_ptr[16][128];
84 //int env_flag[16][128];
86 //need to redo the samples
87 float samples[SAMPLE_COUNT][SAMPLE_LENGTH];
88 //int sample_ptr[SAMPLE_COUNT];
89 //int sample_on[SAMPLE_COUNT];
90 //float sample_velocity[SAMPLE_COUNT];
92 int sample_rate;
93 float lp_alpha;
95 int command_queue[512][5]; /* sample type chan val1 val2 */
96 int command_count;
98 int note_on[MAX_NOTES];
99 int note_channel[MAX_NOTES];
100 int note_note[MAX_NOTES];
101 float velocity[MAX_NOTES];
102 int antipop_flag[MAX_NOTES];
103 int antipop_ptr[MAX_NOTES];
104 float wave_ptr[MAX_NOTES];
105 float wave_step[MAX_NOTES];
106 int sample_ptr[MAX_NOTES];
107 float lp_y[MAX_NOTES];
108 int note_max;
111 void orgux_note_on(orgux_state* S, int chan, int note, int velocity){
113 for(int i=0; i < MAX_NOTES; i++){
114 if(S->note_on[i] == 0){
115 S->note_on[i] = 1;
116 S->note_channel[i] = chan;
117 S->note_note[i] = note;
118 S->velocity[i] = ((float)velocity)/127;
119 S->antipop_flag[i] = -1;
120 S->antipop_ptr[i] = 0;
121 S->wave_ptr[i] = 0.0f;
122 S->sample_ptr[i] = 0;
123 //S->wave_step[i] = (int)((440*pow(2,(note-69)/12.0)*WAVEFORM_LENGTH)/S->sample_rate);
124 S->wave_step[i] = (440*pow(2,(note-69)/12.0)*WAVEFORM_LENGTH)/S->sample_rate;
125 if(i == S->note_max){
126 S->note_max++;
128 break;
134 void orgux_note_off(orgux_state* S, int chan, int note){
136 for(int i=0; i < S->note_max; i++){
137 if(S->note_on[i]==1 && S->note_channel[i]==chan && S->note_note[i]==note && S->antipop_flag[i]<1){
139 //S->note_on[i][1] = chan;
140 //S->note_on[i][2] = note;
141 S->antipop_flag[i] = 1;
142 //S->wave_ptr[i] = 0.0f;
143 //S->wave_step[i] = (440*pow(2,(note-57)/12.0)*WAVEFORM_LENGTH)/S->sample_rate;
144 //S->note_count++;
145 break;
151 void orgux_change_volume(orgux_state* S, int chan, int value){
152 //printf("change volume %d %d\n", chan, value);
153 S->volume[chan] = ((float)value)/127;
156 void orgux_change_pan(orgux_state* S, int chan, int value){
157 //printf("change pan %d %d\n", chan, value);
158 float P = (((float)value)/127) * 2 - 1;
160 if(P > 0){
161 S->pan_l[chan] = 1.0f - P;
162 S->pan_r[chan] = 1.0f;
164 else{
165 S->pan_l[chan] = 1.0f;
166 S->pan_r[chan] = P + 1.0f;
170 void orgux_change_instrument(orgux_state* S, int chan, int value){
171 //printf("change instrument %d %d\n", chan, value);
172 S->instrument[chan] = value;
175 void orgux_pitch_bend(orgux_state* S, int chan, int bend){
176 S->bend[chan] = ((((float)bend)/16383) * 2 - 1) * 1;
180 void orgux_process(orgux_state* S, float* lbuf, float* rbuf, int len){
181 int C=0;
183 /* determine on notes, dont search each time */
184 int note_ons[MAX_NOTES];
185 int N = 0;
186 for(int i=0; i<S->note_max; i++){
187 if(S->note_on[i]){
188 note_ons[N] = i;
189 N++;
193 for(int i=0; i<len; i++){
195 while(i == S->command_queue[C][0] && C < S->command_count){
196 orgux_control(S, S->command_queue[C][1],
197 S->command_queue[C][2],
198 S->command_queue[C][3],
199 S->command_queue[C][4]);
200 C++;
203 lbuf[i] = 0.0f;
204 rbuf[i] = 0.0f;
207 //render playing samples
208 /*for(int j = 0; j<SAMPLE_COUNT; j++){
209 if(!S->sample_on[j]) continue;
210 float y = S->samples[j][S->sample_ptr[j]++];
211 if(S->sample_ptr[j] == SAMPLE_LENGTH){
212 S->sample_on[j] = 0;
214 float V = S->volume[9];
215 float A = S->sample_velocity[j];
216 lbuf[i] += V*A*S->pan_l[9]*y;
217 rbuf[i] += V*A*S->pan_r[9]*y;
221 int jmax = S->note_max;
222 for(int j=0; j < jmax; j++){
223 //for(int n=0; n < N; n++){
224 //int j = note_ons[n];
226 if(!S->note_on[j]) continue;
228 if(S->note_channel[j] == 9){
229 int index = S->note_note[j] - SAMPLE_NOTE_ZERO;
230 if(index < 0){index=0;}
231 if(index >= SAMPLE_COUNT){index=SAMPLE_COUNT-1;}
232 float y = S->samples[index][S->sample_ptr[j]++];
233 if(S->sample_ptr[j] == SAMPLE_LENGTH){
234 S->note_on[j] = 0;
237 float V = S->volume[9];
238 float A = S->velocity[j];
239 lbuf[i] += V*A*S->pan_l[9]*y;
240 rbuf[i] += V*A*S->pan_r[9]*y;
242 continue;
244 //continue;
245 /* hard computations */
246 float x = S->wave_ptr[j];
247 float x1 = floor(x);
248 float x2 = x1 + 1.0f;
249 int X1 = (int)x1;
250 int X2 = X1 + 1;
251 if(X2 == WAVEFORM_LENGTH) X2 = 0;
252 int I = S->instrument[S->note_channel[j]];
253 float y1 = S->waveform[I][X1];
254 float y2 = S->waveform[I][X2];
255 float m = (y2-y1)/(x2-x1);
256 float y = m*(x-x1) + y1;
258 //float y = 0;
261 int I = S->instrument[S->note_channel[j]];
262 int X = S->wave_ptr[j];
263 float y = S->waveform[I][X];
266 //float y0 = S->lp_y[j];
267 //y = y0 + S->lp_alpha * (y - y0);
268 //S->lp_y[j] = y;
270 switch(S->antipop_flag[j]){
271 case -1:
272 y *= S->antipop[S->antipop_ptr[j]];
273 S->antipop_ptr[j]++;
275 if(S->antipop_ptr[j] == ANTIPOP_LENGTH){
276 S->antipop_ptr[j] = ANTIPOP_LENGTH-1;
277 S->antipop_flag[j] = 0;
279 break;
280 case 1:
281 y *= S->antipop[S->antipop_ptr[j]];
282 S->antipop_ptr[j]--;
283 if(S->antipop_ptr[j] < 0){
284 //printf("note dead! j = %d, max = %d\n",j, S->note_max);
285 S->antipop_flag[j] = 0;
286 S->note_on[j] = 0;
287 if(j+1==S->note_max){
288 S->note_max--;
291 break;
295 int chan = S->note_channel[j];
296 float volume = S->volume[chan];
297 float velocity = S->velocity[j];
298 lbuf[i] += volume*velocity*S->pan_l[chan]*y;
299 rbuf[i] += volume*velocity*S->pan_r[chan]*y;
301 if(lbuf[i]> 1.0 || lbuf[i] < -1.0){
302 printf("ehh lbuf[%d] = %f\n",i,lbuf[i]);
303 printf("%f %f %f %f %f\n",y,volume, velocity, S->pan_l[chan], S->pan_r[chan]);
306 S->wave_ptr[j] += S->wave_step[j];
307 while(S->wave_ptr[j] >= WAVEFORM_LENGTH){
308 S->wave_ptr[j] -= WAVEFORM_LENGTH;
315 S->command_count = 0;
322 void orgux_schedule(orgux_state* S, int sample, unsigned char midi[3]){
323 //orgux_control(S, midi[0]&0xf0, midi[0]&0x0f, midi[1], midi[2]);
325 if(S->command_count == MAX_COMMANDS){
326 return;
329 switch(midi[0]&0xf0){
330 case 0xA0:
331 case 0xD0:
332 return;
335 the queue is sorted by time (sample)
336 soonest times are to the beginning of the queue
337 queue[0] is the first element
338 insert: move all later events right one
341 //printf("schedule %d %x %x %x\n",sample,midi[0],midi[1],midi[2]);
342 int i;
343 for(i=0; i<S->command_count; i++){
345 if(sample < S->command_queue[i][0]){
347 for(int j=S->command_count; j>i; j--){
348 S->command_queue[j][0] = S->command_queue[j-1][0];
349 S->command_queue[j][1] = S->command_queue[j-1][1];
350 S->command_queue[j][2] = S->command_queue[j-1][2];
351 S->command_queue[j][3] = S->command_queue[j-1][3];
352 S->command_queue[j][4] = S->command_queue[j-1][4];
355 S->command_queue[i][0] = sample;
356 S->command_queue[i][1] = midi[0]&0xf0;
357 S->command_queue[i][2] = midi[0]&0x0f;
358 S->command_queue[i][3] = midi[1];
359 S->command_queue[i][4] = midi[2];
361 break;
365 if(i==S->command_count){//end of queue
366 S->command_queue[i][0] = sample;
367 S->command_queue[i][1] = midi[0]&0xf0;
368 S->command_queue[i][2] = midi[0]&0x0f;
369 S->command_queue[i][3] = midi[1];
370 S->command_queue[i][4] = midi[2];
373 S->command_count++;
375 for(int i=0; i<S->command_count; i++){
376 /*printf("%d %d %d %d %d\n",
377 S->command_queue[i][0],
378 S->command_queue[i][1],
379 S->command_queue[i][2],
380 S->command_queue[i][3],
381 S->command_queue[i][4]);
387 void orgux_control(orgux_state* S, int type, int chan, int val1, int val2){
389 int bend = (val1 << 7) + val2;
391 //printf("control %d %d %d %d\n", chan, type, val1, val2);
393 switch(type){
394 case 0x90:
395 orgux_note_on(S, chan, val1, val2);
396 return;
397 case 0x80:
398 orgux_note_off(S, chan, val1);
399 return;
400 case 0xC0:
401 orgux_change_instrument(S, chan, val1);
402 return;
403 case 0xB0:
404 if(val1 == 7){
405 orgux_change_volume(S, chan, val2);
407 else if(val1 == 10){
408 orgux_change_pan(S, chan, val2);
410 return;
411 case 0xE0:
412 printf("pitch bend %d\n",bend);
413 orgux_pitch_bend(S, chan, bend);
414 return;
420 orgux_state* orgux_init(int sample_rate){
421 orgux_state* S = malloc(sizeof(orgux_state));
422 if(!S) return NULL;
424 float dt = 1.0/sample_rate;
426 /*precompute square, saw, and triangle wave*/
427 if(!precompute_ok){
428 for(int i=0; i<WAVEFORM_LENGTH; i++){
429 square_wave[i] = 0;
430 triangle_wave[i] = 0;
431 saw_wave[i] = 0;
432 for(int j=0; j<7; j++){
433 square_wave[i] += (4/PI)*sin(i*(2*j+1)*PI2/WAVEFORM_LENGTH)/(2*j+1);
434 triangle_wave[i] += (8/(PI*PI))*(j&1?1:-1)*sin(i*(2*j+1)*PI2/WAVEFORM_LENGTH)/((2*j+1)*(2*j+1));
435 saw_wave[i] += (2/PI)*sin(i*j*PI2/WAVEFORM_LENGTH)/j;
440 /* setup oscillator states */
442 for(int i=0; i<16; i++){
443 S->volume[i] = 1.0f;
444 S->pan_l[i] = 1.0f;
445 S->pan_r[i] = 1.0f;
448 for(int i=0; i<MAX_NOTES; i++){
449 S->wave_ptr[i] = 0.0f;
450 S->antipop_ptr[i] = 0;
451 S->antipop_flag[i] = 0;
452 S->note_on[i] = 0;
453 S->sample_ptr[i] = 0;
454 S->lp_y[i] = 0;
457 //for(int i=0; i<SAMPLE_COUNT; i++){
458 // S->sample_on[i] = 0;
459 // S->sample_ptr[i] = 0;
462 S->sample_rate = sample_rate;
464 S->command_count = 0;
465 S->note_max = 0;
467 S->lp_alpha = dt/(dt+0.001);
469 /* setup wave tables */
471 for(int i=0; i<128; i++){
473 int max = 0;
474 float N = 0;
476 for(int j=0; j<BASIS_COUNT; j++){
477 if(spectra[i][j] > max){ max = spectra[i][j]; }
481 for(int j=0; j<WAVEFORM_LENGTH; j++){
482 S->waveform[i][j] = 0.0f;
483 N = 0;
484 for(int k=0; k<BASIS_COUNT; k++){
485 float M = ((float)spectra[i][k])/max;
486 M = M*M;
487 N += M;
489 float y;
490 switch(SINE_BASE){
491 case SINE_BASE: y = sin(j*(1<<k)*PI2/WAVEFORM_LENGTH); break;
492 //case SQUARE_BASE: y = ((2*j*(1<<k)/WAVEFORM_LENGTH)&1)?1:-1; break;
493 case SQUARE_BASE: y = linterp(j,k,square_wave); break;
494 case TRIANGLE_BASE: y = linterp(j,k,triangle_wave); break;
495 case SAW_BASE: y = linterp(j,k,saw_wave); break;
496 default: y = 0;//use previously defined waveform
499 S->waveform[i][j] += M * y;
501 if(N>0){ S->waveform[i][j] /= N*10; }
502 //if(S->waveform[i][j] > max){ max = S->waveform[i][j]; }
504 //printf("max[%d] = %f, %d\n",i,max, N);
507 //generate antipop cosine
508 for(int i=0; i<ANTIPOP_LENGTH; i++){
509 S->antipop[i] = -cos(i*PI2/(2.0*ANTIPOP_LENGTH))/2.0+0.5;
513 //generate samples
515 float par[16][8] = {/**/
516 {50, 500, 0.5, 10000, 0, 0, 0, 0},
517 {200, 200, 0.5, 10000, 0, 0, 0, 0},
518 {100, 500, 0.5, 10000, 0, 0, 0, 0},
519 {100, 1000, 0.5, 10000, 0, 0, 0, 0},
521 {100, 500, 0.5, 3000, 0, 0, 0, 0},
522 {200, 500, 0.5, 3000, 0, 0, 0, 0},
523 {300, 500, 0.5, 3000, 0, 0, 0, 0},
524 {400, 500, 0.5, 3000, 0, 0, 0, 0},
526 {400, 200, 0.5, 3000, 0, 0, 0, 0},
527 {400, 100, 0.5, 3000, 0, 0, 0, 0},
528 {400, 50, 0.5, 3000, 0, 0, 0, 0},
529 {400, 20, 0.5, 3000, 0, 0, 0, 0},
531 {100, 500, 0.5, 10000, 0, 0, 0, 0},
532 {100, 500, 0.5, 10000, 0, 0, 0, 0},
533 {100, 500, 0.5, 10000, 0, 0, 0, 0},
534 {100, 500, 0.5, 10000, 0, 0, 0, 0}
537 double K = PI2 / sample_rate;
539 for(int i=0; i<SAMPLE_LENGTH; i++){
540 for(int j=0; j<SAMPLE_COUNT; j++){
541 double F_i = par[j][0];
542 double F_r = par[j][1];
543 double A_i = par[j][2];
544 double A_r = par[j][3];
546 if(F_r < 1){F_r = 1;}
547 double f = F_i - i/F_r;
548 if(f < 0) f = 0;
550 if(A_r < 1){A_r = 1;}
551 double A = A_i - i/A_r;
552 if(A < 0) A = 0;
554 double E = 1;
555 if(i < 64){
556 E = -cos((i/64.0) * PI2 / 2)/2+0.5;
559 S->samples[j][i] = E*A*sin(i*f*K);
563 float y_l;
564 float y_h0=0;
565 float y_h1=0;
568 notes
570 cool hit
571 tau2 = 0.0001 / (1 + i/50.0)
572 alpha2 = tau2 / (tau2 + dt)
573 A = 0.2 - (i/10000.0)
581 for(int i=0; i<SAMPLE_LENGTH; i++){
583 float tau1 = (i/200.0)*0.0001;
584 float alpha1 = dt/(tau1+dt);
586 float tau2 = 0.0001 / (1 + i/50.0);
587 float alpha2 = tau2/(tau2+dt);
589 float y = (RANDF()*2 - 1);
591 //y = y_l0 + alpha1*(y - y_l0);
592 //y_l0 = y;
594 float temp = y;
595 y = alpha2*(y - y_h0 + y_h1);
596 y_h0 = temp;
597 y_h1 = y;
599 float A = 0.2 - (i/10000.0);
600 if(A<0) A = 0;
602 double E = 1;
603 if(i < 64){
604 E = -cos((i/64.0) * PI2 / 2)/2+0.5;
607 S->samples[15][i] = A*E*y;
611 return S;
615 void orgux_free(orgux_state* S){
616 free(S);