Refactored precomputation code.
[orgux.git] / core.c
blob89fad1dc020731490f5cdea04b6dc044acc00613
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 samples[SAMPLE_COUNT][SAMPLE_LENGTH];
46 float antipop[ANTIPOP_LENGTH];
48 struct orgux_state{
49 float volume[16];
50 float pan_l[16];
51 float pan_r[16];
52 float bend[16];
53 int instrument[16];
55 int sample_rate;
56 float lp_alpha;
58 int command_queue[512][5]; /* sample type chan val1 val2 */
59 int command_count;
61 int note_on[MAX_NOTES];
62 int note_channel[MAX_NOTES];
63 int note_note[MAX_NOTES];
64 float velocity[MAX_NOTES];
65 int antipop_flag[MAX_NOTES];
66 int antipop_ptr[MAX_NOTES];
67 float wave_ptr[MAX_NOTES];
68 float wave_step[MAX_NOTES];
69 int sample_ptr[MAX_NOTES];
70 float lp_y[MAX_NOTES];
71 int note_max;
74 void orgux_note_on(orgux_state* S, int chan, int note, int velocity){
76 for(int i=0; i < MAX_NOTES; i++){
77 if(S->note_on[i] == 0){
78 S->note_on[i] = 1;
79 S->note_channel[i] = chan;
80 S->note_note[i] = note;
81 S->velocity[i] = ((float)velocity)/127;
82 S->antipop_flag[i] = -1;
83 S->antipop_ptr[i] = 0;
84 S->wave_ptr[i] = 0.0f;
85 S->sample_ptr[i] = 0;
86 //S->wave_step[i] = (int)((440*pow(2,(note-69)/12.0)*WAVEFORM_LENGTH)/S->sample_rate);
87 S->wave_step[i] = (440*pow(2,(note-69)/12.0)*WAVEFORM_LENGTH)/S->sample_rate;
88 if(i == S->note_max){
89 S->note_max++;
91 break;
97 void orgux_note_off(orgux_state* S, int chan, int note){
99 for(int i=0; i < S->note_max; i++){
100 if(S->note_on[i]==1 && S->note_channel[i]==chan && S->note_note[i]==note && S->antipop_flag[i]<1){
102 //S->note_on[i][1] = chan;
103 //S->note_on[i][2] = note;
104 S->antipop_flag[i] = 1;
105 //S->wave_ptr[i] = 0.0f;
106 //S->wave_step[i] = (440*pow(2,(note-57)/12.0)*WAVEFORM_LENGTH)/S->sample_rate;
107 //S->note_count++;
108 break;
114 void orgux_change_volume(orgux_state* S, int chan, int value){
115 //printf("change volume %d %d\n", chan, value);
116 S->volume[chan] = ((float)value)/127;
119 void orgux_change_pan(orgux_state* S, int chan, int value){
120 //printf("change pan %d %d\n", chan, value);
121 float P = (((float)value)/127) * 2 - 1;
123 if(P > 0){
124 S->pan_l[chan] = 1.0f - P;
125 S->pan_r[chan] = 1.0f;
127 else{
128 S->pan_l[chan] = 1.0f;
129 S->pan_r[chan] = P + 1.0f;
133 void orgux_change_instrument(orgux_state* S, int chan, int value){
134 //printf("change instrument %d %d\n", chan, value);
135 S->instrument[chan] = value;
138 void orgux_pitch_bend(orgux_state* S, int chan, int bend){
139 S->bend[chan] = ((((float)bend)/16383) * 2 - 1) * 1;
143 void orgux_process(orgux_state* S, float* lbuf, float* rbuf, int len){
144 int C=0;
146 /* determine on notes, dont search each time */
147 int note_ons[MAX_NOTES];
148 int N = 0;
149 for(int i=0; i<S->note_max; i++){
150 if(S->note_on[i]){
151 note_ons[N] = i;
152 N++;
156 for(int i=0; i<len; i++){
158 while(i == S->command_queue[C][0] && C < S->command_count){
159 orgux_control(S, S->command_queue[C][1],
160 S->command_queue[C][2],
161 S->command_queue[C][3],
162 S->command_queue[C][4]);
163 C++;
166 lbuf[i] = 0.0f;
167 rbuf[i] = 0.0f;
170 //render playing samples
171 /*for(int j = 0; j<SAMPLE_COUNT; j++){
172 if(!S->sample_on[j]) continue;
173 float y = S->samples[j][S->sample_ptr[j]++];
174 if(S->sample_ptr[j] == SAMPLE_LENGTH){
175 S->sample_on[j] = 0;
177 float V = S->volume[9];
178 float A = S->sample_velocity[j];
179 lbuf[i] += V*A*S->pan_l[9]*y;
180 rbuf[i] += V*A*S->pan_r[9]*y;
184 int jmax = S->note_max;
185 for(int j=0; j < jmax; j++){
186 //for(int n=0; n < N; n++){
187 //int j = note_ons[n];
189 if(!S->note_on[j]) continue;
191 if(S->note_channel[j] == 9){
192 int index = S->note_note[j] - SAMPLE_NOTE_ZERO;
193 if(index < 0){index=0;}
194 if(index >= SAMPLE_COUNT){index=SAMPLE_COUNT-1;}
195 float y = samples[index][S->sample_ptr[j]++];
196 if(S->sample_ptr[j] == SAMPLE_LENGTH){
197 S->note_on[j] = 0;
200 float V = S->volume[9];
201 float A = S->velocity[j];
202 lbuf[i] += V*A*S->pan_l[9]*y;
203 rbuf[i] += V*A*S->pan_r[9]*y;
205 continue;
207 //continue;
208 /* hard computations */
209 float x = S->wave_ptr[j];
210 float x1 = floor(x);
211 float x2 = x1 + 1.0f;
212 int X1 = (int)x1;
213 int X2 = X1 + 1;
214 if(X2 == WAVEFORM_LENGTH) X2 = 0;
215 int I = S->instrument[S->note_channel[j]];
216 float y1 = waveform[I][X1];
217 float y2 = waveform[I][X2];
218 float m = (y2-y1)/(x2-x1);
219 float y = m*(x-x1) + y1;
221 //float y = 0;
224 int I = S->instrument[S->note_channel[j]];
225 int X = S->wave_ptr[j];
226 float y = S->waveform[I][X];
229 //float y0 = S->lp_y[j];
230 //y = y0 + S->lp_alpha * (y - y0);
231 //S->lp_y[j] = y;
233 switch(S->antipop_flag[j]){
234 case -1:
235 y *= antipop[S->antipop_ptr[j]];
236 S->antipop_ptr[j]++;
238 if(S->antipop_ptr[j] == ANTIPOP_LENGTH){
239 S->antipop_ptr[j] = ANTIPOP_LENGTH-1;
240 S->antipop_flag[j] = 0;
242 break;
243 case 1:
244 y *= antipop[S->antipop_ptr[j]];
245 S->antipop_ptr[j]--;
246 if(S->antipop_ptr[j] < 0){
247 //printf("note dead! j = %d, max = %d\n",j, S->note_max);
248 S->antipop_flag[j] = 0;
249 S->note_on[j] = 0;
250 if(j+1==S->note_max){
251 S->note_max--;
254 break;
258 int chan = S->note_channel[j];
259 float volume = S->volume[chan];
260 float velocity = S->velocity[j];
261 lbuf[i] += volume*velocity*S->pan_l[chan]*y;
262 rbuf[i] += volume*velocity*S->pan_r[chan]*y;
264 if(lbuf[i]> 1.0 || lbuf[i] < -1.0){
265 printf("ehh lbuf[%d] = %f\n",i,lbuf[i]);
266 printf("%f %f %f %f %f\n",y,volume, velocity, S->pan_l[chan], S->pan_r[chan]);
269 S->wave_ptr[j] += S->wave_step[j];
270 while(S->wave_ptr[j] >= WAVEFORM_LENGTH){
271 S->wave_ptr[j] -= WAVEFORM_LENGTH;
278 S->command_count = 0;
285 void orgux_schedule(orgux_state* S, int sample, unsigned char midi[3]){
286 //orgux_control(S, midi[0]&0xf0, midi[0]&0x0f, midi[1], midi[2]);
288 if(S->command_count == MAX_COMMANDS){
289 return;
292 switch(midi[0]&0xf0){
293 case 0xA0:
294 case 0xD0:
295 return;
298 the queue is sorted by time (sample)
299 soonest times are to the beginning of the queue
300 queue[0] is the first element
301 insert: move all later events right one
304 //printf("schedule %d %x %x %x\n",sample,midi[0],midi[1],midi[2]);
305 int i;
306 for(i=0; i<S->command_count; i++){
308 if(sample < S->command_queue[i][0]){
310 for(int j=S->command_count; j>i; j--){
311 S->command_queue[j][0] = S->command_queue[j-1][0];
312 S->command_queue[j][1] = S->command_queue[j-1][1];
313 S->command_queue[j][2] = S->command_queue[j-1][2];
314 S->command_queue[j][3] = S->command_queue[j-1][3];
315 S->command_queue[j][4] = S->command_queue[j-1][4];
318 S->command_queue[i][0] = sample;
319 S->command_queue[i][1] = midi[0]&0xf0;
320 S->command_queue[i][2] = midi[0]&0x0f;
321 S->command_queue[i][3] = midi[1];
322 S->command_queue[i][4] = midi[2];
324 break;
328 if(i==S->command_count){//end of queue
329 S->command_queue[i][0] = sample;
330 S->command_queue[i][1] = midi[0]&0xf0;
331 S->command_queue[i][2] = midi[0]&0x0f;
332 S->command_queue[i][3] = midi[1];
333 S->command_queue[i][4] = midi[2];
336 S->command_count++;
338 for(int i=0; i<S->command_count; i++){
339 /*printf("%d %d %d %d %d\n",
340 S->command_queue[i][0],
341 S->command_queue[i][1],
342 S->command_queue[i][2],
343 S->command_queue[i][3],
344 S->command_queue[i][4]);
350 void orgux_control(orgux_state* S, int type, int chan, int val1, int val2){
352 int bend = (val1 << 7) + val2;
354 //printf("control %d %d %d %d\n", chan, type, val1, val2);
356 switch(type){
357 case 0x90:
358 orgux_note_on(S, chan, val1, val2);
359 return;
360 case 0x80:
361 orgux_note_off(S, chan, val1);
362 return;
363 case 0xC0:
364 orgux_change_instrument(S, chan, val1);
365 return;
366 case 0xB0:
367 if(val1 == 7){
368 orgux_change_volume(S, chan, val2);
370 else if(val1 == 10){
371 orgux_change_pan(S, chan, val2);
373 return;
374 case 0xE0:
375 printf("pitch bend %d\n",bend);
376 orgux_pitch_bend(S, chan, bend);
377 return;
383 orgux_state* orgux_init(int sample_rate){
384 orgux_state* S = malloc(sizeof(orgux_state));
385 if(!S) return NULL;
389 /*precompute waveforms*/
390 if(!precompute_ok){
392 precompute(sample_rate);
393 precompute_ok = 1;
397 /* setup oscillator states */
399 for(int i=0; i<16; i++){
400 S->volume[i] = 1.0f;
401 S->pan_l[i] = 1.0f;
402 S->pan_r[i] = 1.0f;
405 for(int i=0; i<MAX_NOTES; i++){
406 S->wave_ptr[i] = 0.0f;
407 S->antipop_ptr[i] = 0;
408 S->antipop_flag[i] = 0;
409 S->note_on[i] = 0;
410 S->sample_ptr[i] = 0;
411 S->lp_y[i] = 0;
414 S->sample_rate = sample_rate;
416 S->command_count = 0;
417 S->note_max = 0;
419 //S->lp_alpha = dt/(dt+0.001);
421 return S;
425 void orgux_free(orgux_state* S){
426 free(S);