midi.c has better error checking and better error messages.
[cantaveria.git] / synth.c
blobaa28faec0332a6fc094f864c15e9f6426f4863eb
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;
58 int bpm = 120;
59 int tpb = 384;
61 int serr = 0; // 1/1000 of a sample
63 int tick;
64 int terr = 0; // 1/(bpm*tpb) of a sample
65 int terrd = 46080; //bpm * tpb
68 channel channels[16];
74 void set_bpm(int x){ bpm = x; }
80 void dummy_mix(void* v, float f[], int i){}
81 void dummy_control(void* v, int a, int b, int c, int d){}
82 void dummy_cleanup(void* v){}
84 channel make_dummy_channel(){
85 channel ch;
86 ch.L = 1;
87 ch.R = 1;
88 ch.V = 1;
89 ch.mix = dummy_mix;
90 ch.cleanup = dummy_cleanup;
91 ch.control = dummy_control;
92 ch.data = NULL;
93 return ch;
96 channel make_channel_from_instrument(enum instrument_name name){
97 channel ch = make_dummy_channel();
98 instrument ins = load_instrument(name);
99 ch.mix = ins.mix;
100 ch.control = ins.control;
101 ch.cleanup = ins.cleanup;
102 ch.data = ins.data;
103 return ch;
108 void mix(channel* ch, float in[], float left[], float right[], int count){
109 int i;
110 for(i=0; i<count; i++){
111 left[i] += in[i] * ch->L * ch->V;
112 right[i] += in[i] * ch->R * ch->V;
116 void zero(float buf[], int count){
117 int i;
118 for(i=0; i<count; i++){
119 buf[i] = 0;
123 void reduce(float buf[], int count, float factor){
124 int i;
125 for(i=0; i<count; i++){
126 buf[i] /= factor;
130 void generate(float left[], float right[], int count){
131 float buf[4096];
132 int i;
133 float V = 1.0f;
135 zero(left, count);
136 zero(right, count);
137 for(i=0; i<16; i++){
138 channel* ch = &(channels[i]);
139 zero(buf, count);
140 ch->mix(ch->data, buf, count);
141 mix(ch, buf, left, right, count);
143 reduce(left, count, 16.0f/V);
144 reduce(right, count, 16.0f/V);
147 void control(event* e){
148 if(e == NULL) return;
149 int chan = e->chan;
150 int type = e->type;
151 int val1 = e->val1;
152 int val2 = e->val2;
153 int val = (e->val2 << 7) | e->val1;
154 channel* ch = &(channels[chan]);
155 ch->control(ch->data, type, val1, val2, val);
158 void immediate_control(){
159 event* e = seq_get_immediate();
160 while(e){
161 control(e);
162 e = seq_get_immediate();
166 void synth_generate(float left[], float right[], int samples){
167 int i=0;
168 int remaining = samples;
169 int used = 0;
170 event* e = NULL;
172 immediate_control();
174 while(remaining > 0){
175 e = seq_advance(remaining, &used);
176 generate(left+i, right+i, used);
177 control(e);
178 i += used;
179 remaining -= used;
180 if(e == NULL && remaining > 0){
181 printf("synth: sequencer error. no event was returned, but unable to advance beyond %d samples (out of %d)\n", i, samples);
182 printf("synth: i will continue, but this caused a tick/sample drift of %d samples\n", remaining);
183 break;
189 void synth_init(){
190 int i;
191 printf(" synth: ... ");
193 channels[0] = make_channel_from_instrument(ORG_DEFAULT);
194 channels[1] = make_channel_from_instrument(ORG_KARPLUS);
195 for(i=2; i<16; i++){
196 channels[i] = make_dummy_channel();
199 //srate = sample_rate;
201 printf("OK\n");