Fixed output level probe.
[cantaveria.git] / synth.c
blob53cb797185642f74f27d2a66f227e7dc4be00faf
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 <util.h>
30 #include <list.h>
31 #include <org.h>
32 #include <synth.h>
33 #include <seq.h>
36 timing stuff
38 ticks - 384 per beat (tpb)
39 beats - 120 per minute (bpm)
40 samples - 22050 per second (srate)
42 control happens on tick boundaries
43 control must take effect on nearest sample boundary
45 samples per tick = (srate*60) / (bpm*tpb)
46 which in the above example = 28 and 32760/46080
50 typedef struct {
51 float L, R, V;
52 mix_callback mix;
53 control_callback control;
54 cleanup_callback cleanup;
55 void* data;
56 } channel;
58 int srate;
60 int serr = 0; // 1/1000 of a sample
62 int tick;
63 int terr = 0; // 1/(bpm*tpb) of a sample
64 int terrd = 46080; //bpm * tpb
67 channel channels[16];
78 void dummy_mix(void* v, float f[], int i){}
79 void dummy_control(void* v, int a, int b, int c, int d){}
80 void dummy_cleanup(void* v){}
82 channel make_dummy_channel(){
83 channel ch;
84 ch.L = 1;
85 ch.R = 1;
86 ch.V = 1;
87 ch.mix = dummy_mix;
88 ch.cleanup = dummy_cleanup;
89 ch.control = dummy_control;
90 ch.data = NULL;
91 return ch;
94 channel make_channel_from_instrument(enum instrument_name name){
95 channel ch = make_dummy_channel();
96 instrument ins = load_instrument(name);
97 ch.mix = ins.mix;
98 ch.control = ins.control;
99 ch.cleanup = ins.cleanup;
100 ch.data = ins.data;
101 return ch;
106 void set_music_volume(int percent){
110 void cut_music(){
114 void fade_clear(){
118 void fadeout(int seconds){
124 void mix(channel* ch, float in[], float left[], float right[], int count){
125 int i;
126 for(i=0; i<count; i++){
127 left[i] += in[i] * ch->L * ch->V;
128 right[i] += in[i] * ch->R * ch->V;
132 void zero(float buf[], int count){
133 int i;
134 for(i=0; i<count; i++){
135 buf[i] = 0;
139 void reduce(float buf[], int count, float factor){
140 int i;
141 for(i=0; i<count; i++){
142 buf[i] /= factor;
146 void clip(float buf[], int count){
147 int i;
148 int clipped = 0;
149 float avg = 0;
150 for(i=0; i<count; i++){
151 avg += buf[i]*buf[i];
152 if(buf[i] > 1.0){
153 clipped = 1;
154 buf[i] = 1.0;
156 else if(buf[i] < -1.0) buf[i] = -1.0;
159 if(clipped){
160 printf("synth: clipping distortion due to output overload\n");
163 avg /= count?count:1;
164 avg = sqrt(avg);
167 void generate(float left[], float right[], int count){
168 float buf[4096];
169 int i;
170 float V = 1.0f;
172 zero(left, count);
173 zero(right, count);
174 for(i=0; i<16; i++){
175 channel* ch = &(channels[i]);
176 zero(buf, count);
177 ch->mix(ch->data, buf, count);
178 mix(ch, buf, left, right, count);
180 reduce(left, count, 16.0f/V);
181 reduce(right, count, 16.0f/V);
182 clip(left, count);
183 clip(right, count);
186 void control(event* e){
187 if(e == NULL) return;
188 int chan = e->chan;
189 int type = e->type;
190 int val1 = e->val1;
191 int val2 = e->val2;
192 int val = (e->val2 << 7) | e->val1;
193 channel* ch = &(channels[chan]);
195 switch(type){
196 case EVX_MUSICVOLUME: set_music_volume(val1); break;
197 case EVX_MUSICCUT: cut_music(); break;
198 case EVX_FADECLEAR: fade_clear(); break;
199 case EVX_FADEOUT: fadeout(val1); break;
200 default: ch->control(ch->data, type, val1, val2, val); break;
204 void immediate_control(){
205 event* e = seq_get_immediate();
206 while(e){
207 control(e);
208 e = seq_get_immediate();
212 void synth_generate(float left[], float right[], int samples){
213 int i=0;
214 int remaining = samples;
215 int used = 0;
216 event* e = NULL;
218 immediate_control();
220 while(remaining > 0){
221 e = seq_advance(remaining, &used);
222 generate(left+i, right+i, used);
223 control(e);
224 i += used;
225 remaining -= used;
226 if(e == NULL && used == 0){
227 error_msg("synth: sequencer failed to advance or provide a control event.");
228 break;
234 void synth_init(){
235 int i;
236 printf(" synth: ... ");
238 for(i=0; i<16; i++){
239 channels[i] = make_dummy_channel();
242 //channels[0] = make_channel_from_instrument(ORG_KARPLUS);
243 //channels[1] = make_channel_from_instrument(ORG_KARPLUS);
244 //channels[2] = make_channel_from_instrument(ORG_KARPLUS);
245 //channels[3] = make_channel_from_instrument(ORG_KARPLUS);
246 channels[0] = make_channel_from_instrument(ORG_DEFAULT);
247 channels[1] = make_channel_from_instrument(ORG_DEFAULT);
248 channels[2] = make_channel_from_instrument(ORG_DEFAULT);
249 channels[3] = make_channel_from_instrument(ORG_DEFAULT);
252 //srate = sample_rate;
254 printf("OK\n");