Testing of song playback.
[cantaveria.git] / synth.c
blob48f280b6e1573bd4ee833e2eaf8904d23d01489d
1 /*
2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 2010 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
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
22 evanrinehart@gmail.com
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <math.h>
29 #include <list.h>
30 #include <org.h>
31 #include <synth.h>
32 #include <seq.h>
35 timing stuff
37 ticks - 384 per beat (tpb)
38 beats - 120 per minute (bpm)
39 samples - 22050 per second (srate)
41 control happens on tick boundaries
42 control must take effect on nearest sample boundary
44 samples per tick = (srate*60) / (bpm*tpb)
45 which in the above example = 28 and 32760/46080
49 typedef struct {
50 float L, R, V;
51 mix_callback mix;
52 control_callback control;
53 cleanup_callback cleanup;
54 void* data;
55 } channel;
57 int srate;
59 int serr = 0; // 1/1000 of a sample
61 int tick;
62 int terr = 0; // 1/(bpm*tpb) of a sample
63 int terrd = 46080; //bpm * tpb
66 channel channels[16];
77 void dummy_mix(void* v, float f[], int i){}
78 void dummy_control(void* v, int a, int b, int c, int d){}
79 void dummy_cleanup(void* v){}
81 channel make_dummy_channel(){
82 channel ch;
83 ch.L = 1;
84 ch.R = 1;
85 ch.V = 1;
86 ch.mix = dummy_mix;
87 ch.cleanup = dummy_cleanup;
88 ch.control = dummy_control;
89 ch.data = NULL;
90 return ch;
93 channel make_channel_from_instrument(enum instrument_name name){
94 channel ch = make_dummy_channel();
95 instrument ins = load_instrument(name);
96 ch.mix = ins.mix;
97 ch.control = ins.control;
98 ch.cleanup = ins.cleanup;
99 ch.data = ins.data;
100 return ch;
105 void mix(channel* ch, float in[], float left[], float right[], int count){
106 int i;
107 for(i=0; i<count; i++){
108 left[i] += in[i] * ch->L * ch->V;
109 right[i] += in[i] * ch->R * ch->V;
113 void zero(float buf[], int count){
114 int i;
115 for(i=0; i<count; i++){
116 buf[i] = 0;
120 void reduce(float buf[], int count, float factor){
121 int i;
122 for(i=0; i<count; i++){
123 buf[i] /= factor;
127 void clip(float buf[], int count){
128 int i;
129 int clipped = 0;
130 float avg = 0;
131 for(i=0; i<count; i++){
132 avg += buf[i]*buf[i];
133 if(buf[i] > 1.0){
134 clipped = 1;
135 buf[i] = 1.0;
137 else if(buf[i] < -1.0) buf[i] = -1.0;
140 if(clipped){
141 printf("synth: out of range output was clipped in this buffer\n");
144 avg /= count?count:1;
145 avg = sqrt(avg);
148 void generate(float left[], float right[], int count){
149 float buf[4096];
150 int i;
151 float V = 1.0f;
153 zero(left, count);
154 zero(right, count);
155 for(i=0; i<16; i++){
156 channel* ch = &(channels[i]);
157 zero(buf, count);
158 ch->mix(ch->data, buf, count);
159 mix(ch, buf, left, right, count);
161 reduce(left, count, 16.0f/V);
162 reduce(right, count, 16.0f/V);
163 clip(left, count);
164 clip(right, count);
167 void control(event* e){
168 if(e == NULL) return;
169 int chan = e->chan;
170 int type = e->type;
171 int val1 = e->val1;
172 int val2 = e->val2;
173 int val = (e->val2 << 7) | e->val1;
174 channel* ch = &(channels[chan]);
175 ch->control(ch->data, type, val1, val2, val);
178 void immediate_control(){
179 event* e = seq_get_immediate();
180 while(e){
181 control(e);
182 e = seq_get_immediate();
186 void synth_generate(float left[], float right[], int samples){
187 int i=0;
188 int remaining = samples;
189 int used = 0;
190 event* e = NULL;
192 immediate_control();
194 while(remaining > 0){
195 e = seq_advance(remaining, &used);
196 generate(left+i, right+i, used);
197 control(e);
198 i += used;
199 remaining -= used;
200 if(e == NULL && remaining > 0){
201 printf("synth: sequencer error. no event was returned, but unable to advance beyond %d samples (out of %d)\n", i, samples);
202 printf("synth: i will continue, but this caused a tick/sample drift of %d samples\n", remaining);
203 break;
209 void synth_init(){
210 int i;
211 printf(" synth: ... ");
213 for(i=0; i<16; i++){
214 channels[i] = make_dummy_channel();
217 channels[0] = make_channel_from_instrument(ORG_DEFAULT);
218 channels[1] = make_channel_from_instrument(ORG_DEFAULT);
219 channels[2] = make_channel_from_instrument(ORG_DEFAULT);
220 channels[3] = make_channel_from_instrument(ORG_DEFAULT);
223 //srate = sample_rate;
225 printf("OK\n");