Removed ending pop completely in ORG_DEFAULT.
[cantaveria.git] / synth.c
blob45c9a6c95f5b67b83f5e966685b14c657e5d24e2
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 <org.h>
30 #include <synth.h>
31 #include <seq.h>
32 #include <list.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 int chan = e->chan;
149 int type = e->type;
150 int val1 = e->val1;
151 int val2 = e->val2;
152 int val = (e->val2 << 7) | e->val1;
153 channel* ch = &(channels[chan]);
154 ch->control(ch->data, type, val1, val2, val);
157 void immediate_control(){
158 event* e = seq_get_immediate();
159 while(e){
160 control(e);
161 e = seq_get_immediate();
165 void synth_generate(float left[], float right[], int samples){
166 int i=0;
168 immediate_control();
170 for(;;){
171 int next = seq_lookahead(samples);
172 generate(left+i, right+i, next-i);
173 i = next;
174 if(i == samples) break;
175 control(seq_get_event());
177 // seq_advance(samples);
181 void synth_init(){
182 int i;
183 printf(" synth: ... ");
185 channels[0] = make_channel_from_instrument(ORG_DEFAULT);
186 for(i=1; i<16; i++){
187 channels[i] = make_dummy_channel();
190 //srate = sample_rate;
192 printf("OK\n");