Browse Source

added simpler filter, split code into files

vampirefrog 3 years ago
parent
commit
432d5e421a
11 changed files with 291 additions and 430 deletions
  1. 53
    0
      envelope.c
  2. 26
    0
      envelope.h
  3. 30
    0
      filter.c
  4. 14
    0
      filter.h
  5. 17
    0
      oscillator.c
  6. 23
    0
      oscillator.h
  7. 56
    349
      synth.c
  8. 11
    81
      synth.h
  9. 7
    0
      types.h
  10. 31
    0
      voice.c
  11. 23
    0
      voice.h

+ 53
- 0
envelope.c View File

@@ -0,0 +1,53 @@
1
+#include "envelope.h"
2
+#include "config.h"
3
+
4
+void envelope_start(struct Envelope *env) {
5
+	env->state = Attack;
6
+	env->time = 0;
7
+}
8
+
9
+void envelope_stop(struct Envelope *env) {
10
+	env->state = Release;
11
+	env->time = 0;
12
+}
13
+
14
+float envelope_sample(struct Envelope *env) {
15
+	if(env->state == None) return 0;
16
+
17
+	float ret = 0;
18
+
19
+	uint32_t ms_time = env->time * 1000 / SAMPLE_RATE;
20
+	switch(env->state) {
21
+		case Attack:
22
+			if(ms_time > env->attack) {
23
+				env->state = Decay;
24
+				env->time = 0;
25
+			} else if(env->attack > 0) {
26
+				ret = (float)ms_time / (float)env->attack;
27
+			}
28
+			break;
29
+		case Decay:
30
+			if(ms_time > env->decay) {
31
+				env->state = Sustain;
32
+				env->time = 0;
33
+			} else if(env->decay > 0) {
34
+				ret = ((env->decay - ms_time) + env->sustain * ms_time / 100.0) / (float)env->decay;
35
+			}
36
+			break;
37
+		case Sustain:
38
+			ret = (float)env->sustain / 100.0;
39
+			break;
40
+		case Release:
41
+			if(ms_time > env->release) {
42
+				env->state = None;
43
+				env->time = 0;
44
+			} else if(env->release > 0) {
45
+				ret = (env->release - ms_time) * env->sustain / env->release / 100.0;
46
+			}
47
+			break;
48
+	}
49
+
50
+	env->time++;
51
+
52
+	return ret;
53
+}

+ 26
- 0
envelope.h View File

@@ -0,0 +1,26 @@
1
+#ifndef ENVELOPE_H_
2
+#define ENVELOPE_H_
3
+
4
+#include <stdint.h>
5
+
6
+struct Envelope {
7
+	// public
8
+	uint16_t attack, decay, release; // in ms
9
+	uint16_t sustain; // percentage
10
+
11
+	// private
12
+	enum {
13
+		None,
14
+		Attack,
15
+		Decay,
16
+		Sustain,
17
+		Release
18
+	} state;
19
+
20
+	uint32_t time;
21
+};
22
+void envelope_start(struct Envelope *env);
23
+void envelope_stop(struct Envelope *env);
24
+float envelope_sample(struct Envelope *env);
25
+
26
+#endif /* ENVELOPE_H_ */

+ 30
- 0
filter.c View File

@@ -0,0 +1,30 @@
1
+#include <math.h>
2
+
3
+#include "filter.h"
4
+
5
+void filter_init(struct Filter *filter, float cutoff, float resonance) {
6
+	filter->v0 = filter->v1 = 0;
7
+	filter->cutoff = cutoff;
8
+	filter->resonance = resonance;
9
+}
10
+
11
+void filter_set_cutoff(struct Filter *filter, float cutoff) {
12
+	filter->cutoff = cutoff;
13
+}
14
+
15
+void filter_set_resonance(struct Filter *filter, float resonance) {
16
+	filter->resonance = resonance;
17
+}
18
+
19
+float filter_sample(struct Filter *filter, float input) {
20
+	float c = pow(0.5, (128-filter->cutoff)   / 16.0);
21
+	float r = pow(0.5, (filter->resonance+24) / 16.0);
22
+
23
+	float outputs[2]; // oversample
24
+	for(int i = 0; i < 2; i++) {
25
+		filter->v0 =  (1-r*c)*filter->v0  -  (c)*filter->v1  + (c)*input;
26
+		outputs[i] = filter->v1 = (1-r*c)*filter->v1  +  (c)*filter->v0;
27
+	}
28
+
29
+	return (outputs[0] + outputs[1]) / 2;
30
+}

+ 14
- 0
filter.h View File

@@ -0,0 +1,14 @@
1
+#ifndef FILTER_H_
2
+#define FILTER_H_
3
+
4
+struct Filter {
5
+	float v0, v1;
6
+	float cutoff, resonance;
7
+};
8
+void filter_init(struct Filter *filter, float cutoff, float q);
9
+void filter_set_cutoff(struct Filter *filter, float cutoff); // frequency in Hz
10
+void filter_set_resonance(struct Filter *filter, float q);
11
+void filter_set_cutoff_and_resonance(struct Filter *filter, float cutoff, float q); // both
12
+float filter_sample(struct Filter *filter, float input);
13
+
14
+#endif /* FILTER_H_ */

+ 17
- 0
oscillator.c View File

@@ -0,0 +1,17 @@
1
+#include "oscillator.h"
2
+
3
+int16_t oscillator_render_sample(struct Oscillator *osc) {
4
+	if(osc->period == 0) return 0;
5
+
6
+	osc->phase += 0x10000; // add one sample in fixed
7
+	osc->sub_phase += 0x10000;
8
+
9
+	fixed sub_period = osc->period << 1;
10
+
11
+	while(osc->phase > osc->period)
12
+		osc->phase -= osc->period;
13
+	while(osc->sub_phase > sub_period)
14
+		osc->sub_phase -= sub_period;
15
+
16
+	return (1 << 13) - (osc->phase << 3) / (osc->period >> 11) + (osc->sub_phase - osc->period / 2 > osc->period ? 4096 : -4096);
17
+}

+ 23
- 0
oscillator.h View File

@@ -0,0 +1,23 @@
1
+#ifndef OSCILLATOR_H_
2
+#define OSCILLATOR_H_
3
+
4
+#include "types.h"
5
+
6
+struct Oscillator {
7
+	fixed phase, sub_phase; // fixed 16.16
8
+	fixed freq; // fixed 16.16
9
+	fixed period; // period in samples, fixed 16.16
10
+
11
+	enum {
12
+		Rectangle,
13
+		Triangle
14
+	} type;
15
+
16
+	uint8_t sub_oct; // 0-2
17
+	uint8_t pulse_width; // 0 - 127
18
+};
19
+
20
+int16_t oscillator_render_sample(struct Oscillator *osc);
21
+void oscillator_set_freq(fixed freq); // fixed 16.16
22
+
23
+#endif /* OSCILLATOR_H_ */

+ 56
- 349
synth.c View File

@@ -1,5 +1,5 @@
1 1
 #include <stdio.h>
2
-#include <math.h>
2
+#include <string.h>
3 3
 
4 4
 #include "synth.h"
5 5
 #include "config.h"
@@ -13,388 +13,95 @@ static fixed freq2period(fixed freq) {
13 13
 }
14 14
 
15 15
 void synth_init(struct Synth *synth) {
16
-	synth_set_cutoff_freq(synth, 100);
17
-	synth_set_resonance(synth, 1);
16
+	synth_set_cutoff_freq(synth, 127);
17
+	synth_set_resonance(synth, 0);
18 18
 }
19 19
 
20 20
 uint8_t midi_notes[128];
21 21
 void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity) {
22
-	// find the first available voice, if any
23
-	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
24
-		struct Voice *voice = synth->voices + i;
25
-		if(voice->env_state == None) {
26
-			midi_notes[note & 0x7f] = i;
27
-			voice->attack = synth->attack;
28
-			voice->decay = synth->decay;
29
-			voice->sustain = synth->sustain;
30
-			voice->release = synth->release;
31
-			voice_note_start(voice, note, velocity);
32
-			break;
22
+	if(synth->monophonic) {
23
+		int freq = midi_note_freq_fixed[note];
24
+		int freq_below = freq - midi_note_freq_fixed[note - 1];
25
+		int freq_above = midi_note_freq_fixed[note + 1] - freq;
26
+		synth->voices[0].osc.freq = freq;
27
+		synth->voices[0].osc.period = freq2period(freq);
28
+		for(int i = 1; i <= 3; i++) {
29
+			struct Voice *voice = synth->voices + i;
30
+			voice->osc.freq = freq - synth->unison_spread * freq_below * i / 512;
31
+			voice->osc.period = freq2period(voice->osc.freq);
32
+		}
33
+		for(int i = 4; i < 7; i++) {
34
+			struct Voice *voice = synth->voices + i;
35
+			voice->osc.freq = freq + synth->unison_spread * freq_above * (i - 3) / 512;
36
+			voice->osc.period = freq2period(voice->osc.freq);
37
+		}
38
+
39
+		synth->voices[0].pan = 0;
40
+		for(int i = 1; i <= 7; i++) {
41
+			synth->voices[i].pan = ((i&1) * 2 - 1) * synth->stereo_spread * ((i + 1) / 2) / 3;
42
+		}
43
+
44
+		for(int i = 0; i < 7; i++) {
45
+			struct Voice *voice = synth->voices + i;
46
+			voice->osc.phase = random();
47
+
48
+			voice->osc_env.attack = synth->osc_env.attack;
49
+			voice->osc_env.decay = synth->osc_env.decay;
50
+			voice->osc_env.sustain = synth->osc_env.sustain;
51
+			voice->osc_env.release = synth->osc_env.release;
52
+
53
+			voice->filter_env.attack = synth->filter_env.attack;
54
+			voice->filter_env.decay = synth->filter_env.decay;
55
+			voice->filter_env.sustain = synth->filter_env.sustain;
56
+			voice->filter_env.release = synth->filter_env.release;
57
+
58
+			voice_note_start(voice, note, i == 0 ? velocity : velocity / 4);
33 59
 		}
34 60
 	}
35 61
 }
36 62
 
37 63
 void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity) {
38 64
 	(void)velocity;
39
-	struct Voice *voice = synth->voices + midi_notes[note & 0x7f];
40
-	voice_stop(voice);
65
+	for(int i = 0; i < 7; i++) {
66
+		struct Voice *voice = synth->voices + i;
67
+		voice_stop(voice);
68
+	}
41 69
 }
42 70
 
43
-void synth_render_sample(struct Synth *synth, int16_t *out) {
44
-	int32_t smpl[2] = { 0, 0 };
71
+void synth_render_sample(struct Synth *synth, float *out) {
72
+	float smpl[2] = { 0, 0 };
73
+
45 74
 	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
46 75
 		struct Voice *v = synth->voices + i;
47
-		if(v->env_state == None)
48
-			continue;
49
-		int16_t vsmpl[2];
76
+		float vsmpl[2];
50 77
 		voice_render_sample(v, vsmpl);
51 78
 		for(int j = 0; j < 2; j++) {
52
-			smpl[j] += vsmpl[j];
53
-			if(smpl[j] > 32767) smpl[j] = 32767;
54
-			if(smpl[j] < -32768) smpl[j] = -32768;
79
+			smpl[j] += vsmpl[j] / 2.0;
80
+			if(smpl[j] > 1) smpl[j] = 1;
81
+			else if(smpl[j] < -1) smpl[j] = -1;
55 82
 		}
56 83
 	}
84
+
57 85
 	out[0] = smpl[0];
58 86
 	out[1] = smpl[1];
59 87
 }
60 88
 
61
-void synth_set_pulse_width(struct Synth *synth, uint8_t w) {
62
-	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
63
-		for(int j = 0; j < 7; j++)
64
-			synth->voices[i].osc[j].pulse_width = w;
65
-	}
66
-}
67
-
68 89
 void synth_set_cutoff_freq(struct Synth *synth, uint8_t f) {
69
-	float freq = 20.0 + pow(2, f * 14.0 / 127.0);
70
-	//float freq = 20 + 20000*sqrt(f/127.0);
71 90
 	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
72
-		filter_set_cutoff(&synth->voices[i].filter[0], freq);
73
-		filter_set_cutoff(&synth->voices[i].filter[1], freq);
91
+		filter_set_cutoff(&synth->voices[i].filter, f);
74 92
 	}
75 93
 }
76 94
 
77 95
 void synth_set_resonance(struct Synth *synth, uint8_t f) {
78
-	float q = 1 + f / 100.0;
79 96
 	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
80
-		filter_set_q(&synth->voices[i].filter[0], q);
81
-		filter_set_q(&synth->voices[i].filter[1], q);
97
+		filter_set_resonance(&synth->voices[i].filter, f);
82 98
 	}
83 99
 }
84 100
 
85
-void voice_calc_unison(struct Voice *voice);
86 101
 void synth_set_unison_spread(struct Synth *synth, uint8_t w) {
87
-	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
88
-		struct Voice *v = synth->voices + i;
89
-		v->unison_spread = w;
90
-		if(v->env_state == None)
91
-			continue;
92
-		voice_calc_unison(v);
93
-	}
102
+	synth->unison_spread = w;
94 103
 }
95 104
 
96
-void voice_calc_stereo_spread(struct Voice *voice);
97 105
 void synth_set_stereo_spread(struct Synth *synth, uint8_t w) {
98
-	for(int i = 0; i < SYNTH_NUM_VOICES; i++) {
99
-		struct Voice *v = synth->voices + i;
100
-		v->stereo_spread = w;
101
-		if(v->env_state == None)
102
-			continue;
103
-		voice_calc_stereo_spread(v);
104
-	}
105
-}
106
-
107
-int16_t oscillator_render_sample(struct Oscillator *osc) {
108
-	osc->phase += 0x10000; // add one sample in fixed
109
-	if(osc->period > 0) // avoid a infinite loop below
110
-		while(osc->phase > osc->period)
111
-			osc->phase -= osc->period;
112
-	uint32_t edge = osc->pulse_width * osc->period / 127;
113
-	if(osc->type == Rectangle) {
114
-		if(osc->phase >= edge)
115
-			return -(1 << 11);
116
-		else
117
-			return (1 << 11) - 1;
118
-	} else if(osc->type == Triangle) {
119
-		if(osc->phase < edge) {
120
-			return (osc->phase << 3) / (edge >> 11) - (1 << 13);
121
-		} else if(osc->pulse_width < 127) {
122
-			return ((osc->period - osc->phase) << 3) / ((osc->period - edge) >> 11) - (1 << 13);
123
-		} else {
124
-			return 0;
125
-		}
126
-	}
127
-}
128
-
129
-void voice_render_sample(struct Voice *v, int16_t *out) {
130
-//	if(v->env_state == None)
131
-//		return 0;
132
-
133
-	int32_t amplitude = 0; // calculate based on velocity and envelope
134
-	uint32_t ms_time = v->time * 1000 / SAMPLE_RATE;
135
-	switch(v->env_state) {
136
-		case Attack:
137
-			if(v->attack > 0)
138
-				amplitude = v->volume * ms_time / v->attack;
139
-			if(ms_time > v->attack) {
140
-				v->env_state = Decay;
141
-				v->time = 0;
142
-			}
143
-			break;
144
-		case Decay:
145
-			if(v->decay > 0)
146
-				amplitude = (100 * v->volume * (v->decay - ms_time) + v->sustain * v->volume * ms_time) / v->decay / 100;
147
-			if(ms_time > v->decay) {
148
-				v->env_state = Sustain;
149
-				v->time = 0;
150
-			}
151
-			break;
152
-		case Sustain:
153
-			amplitude = v->volume * v->sustain / 100;
154
-			break;
155
-		case Release:
156
-			if(v->release > 0)
157
-				amplitude = v->volume * (v->release - ms_time) * v->sustain / v->release / 100;
158
-			if(ms_time > v->release) {
159
-				v->time = 0;
160
-				v->env_state = None;
161
-			}
162
-			break;
163
-	}
164
-
165
-	v->time++;
166
-
167
-	int32_t ret[2] = { 0, 0 };
168
-	for(int i = 0; i < 7; i++) {
169
-		int32_t s = oscillator_render_sample(&v->osc[i]);
170
-		ret[0] +=  (127 + v->osc[i].pan) * s / 255;
171
-		ret[1] += (127 - v->osc[i].pan) * s / 255;
172
-	}
173
-	out[0] = filter_sample(&v->filter[0], amplitude * ret[0] / 32767.0);
174
-	out[1] = filter_sample(&v->filter[1], amplitude * ret[1] / 32767.0);
175
-}
176
-
177
-void voice_calc_unison(struct Voice *voice) {
178
-	voice->osc[0].freq = voice->freq;
179
-	int freq_below = voice->osc[0].freq - midi_note_freq_fixed[voice->note - 1];
180
-	int freq_above = midi_note_freq_fixed[voice->note + 1] - voice->osc[0].freq;
181
-	voice->osc[0].period = freq2period(voice->osc[0].freq);
182
-	for(int i = 1; i <= 3; i++) {
183
-		voice->osc[i].type = voice->osc[0].type;
184
-		voice->osc[i].freq = voice->osc[0].freq - voice->unison_spread * freq_below * i / 3 / 127;
185
-		voice->osc[i].period = freq2period(voice->osc[i].freq);
186
-	}
187
-	for(int i = 4; i < 7; i++) {
188
-		voice->osc[i].type = voice->osc[0].type;
189
-		voice->osc[i].freq = voice->osc[0].freq + voice->unison_spread * freq_above * (i - 3) / 3 / 127;
190
-		voice->osc[i].period = freq2period(voice->osc[i].freq);
191
-	}
192
-}
193
-
194
-void voice_calc_stereo_spread(struct Voice *voice) {
195
-	voice->osc[0].pan = 0;
196
-	for(int i = 1; i <= 7; i++) {
197
-		voice->osc[i].pan = ((i&1) * 2 - 1) * voice->stereo_spread * ((i + 1) / 2) / 3;
198
-	}
199
-	printf(
200
-		"Stereo spread %d -> %d  %d %d %d  %d %d %d\n",
201
-		voice->stereo_spread,
202
-		voice->osc[0].pan,
203
-		voice->osc[1].pan,
204
-		voice->osc[2].pan,
205
-		voice->osc[3].pan,
206
-		voice->osc[4].pan,
207
-		voice->osc[5].pan,
208
-		voice->osc[6].pan
209
-	);
210
-}
211
-
212
-void voice_note_start(struct Voice *voice, uint8_t note, uint8_t velocity) {
213
-	voice->time = 0;
214
-	voice->volume = velocity * 128;
215
-	voice->env_state = Attack;
216
-
217
-	note &= 0x7f;
218
-	voice->osc[0].type = Triangle;
219
-	voice->freq = midi_note_freq_fixed[note];
220
-	voice->note = note;
221
-	for(int i = 0; i < 7; i++) voice->osc[0].phase = 0;
222
-	voice_calc_unison(voice);
223
-}
224
-
225
-void voice_stop(struct Voice *voice) {
226
-	voice->time = 0;
227
-	voice->env_state = Release;
228
-}
229
-
230
-
231
-struct Biquad {
232
-	double a0, a1, a2;
233
-	double b0, b1, b2;
234
-};
235
-static struct Biquad ProtoCoef[IIR_LENGTH] = {{
236
-	.a0 = 1.0,
237
-	.a1 = 0,
238
-	.a2 = 0,
239
-	.b0 = 1.0,
240
-	.b1 = 0.765367,
241
-	.b2 = 1.0
242
-}, {
243
-	.a0 = 1.0,
244
-	.a1 = 0,
245
-	.a2 = 0,
246
-	.b0 = 1.0,
247
-	.b1 = 1.847759,
248
-	.b2 = 1.0
249
-}};
250
-
251
-void prewarp(double *a0, double *a1, double *a2, double fc, double fs) {
252
-	double wp;
253
-
254
-	wp = 2.0 * fs * tan(M_PI * fc / fs);
255
-
256
-	*a2 = (*a2) / (wp * wp);
257
-	*a1 = (*a1) / wp;
258
-}
259
-
260
-void bilinear(
261
-	double a0, double a1, double a2,    /* numerator coefficients */
262
-	double b0, double b1, double b2,    /* denominator coefficients */
263
-	double *k,           /* overall gain factor */
264
-	double fs,           /* sampling rate */
265
-	float *coef         /* pointer to 4 iir coefficients */
266
-) {
267
-	double ad, bd;
268
-
269
-				 /* alpha (Numerator in s-domain) */
270
-	ad = 4. * a2 * fs * fs + 2. * a1 * fs + a0;
271
-				 /* beta (Denominator in s-domain) */
272
-	bd = 4. * b2 * fs * fs + 2. * b1* fs + b0;
273
-				 /* update gain constant for this section */
274
-	*k *= ad/bd;
275
-
276
-				 /* Denominator */
277
-	*coef++ = (2. * b0 - 8. * b2 * fs * fs)
278
-						   / bd;         /* beta1 */
279
-	*coef++ = (4. * b2 * fs * fs - 2. * b1 * fs + b0)
280
-						   / bd; /* beta2 */
281
-
282
-				 /* Nominator */
283
-	*coef++ = (2. * a0 - 8. * a2 * fs * fs)
284
-						   / ad;         /* alpha1 */
285
-	*coef = (4. * a2 * fs * fs - 2. * a1 * fs + a0)
286
-						   / ad;   /* alpha2 */
287
-}
288
-
289
-
290
-/*
291
- * ----------------------------------------------------------
292
- * Transform from s to z domain using bilinear transform
293
- * with prewarp.
294
- *
295
- * Arguments:
296
- *      For argument description look at bilinear()
297
- *
298
- *      coef - pointer to array of floating point coefficients,
299
- *                     corresponding to output of bilinear transofrm
300
- *                     (z domain).
301
- *
302
- * Note: frequencies are in Hz.
303
- * ----------------------------------------------------------
304
- */
305
-void szxform(
306
-	double *a0, double *a1, double *a2, /* numerator coefficients */
307
-	double *b0, double *b1, double *b2, /* denominator coefficients */
308
-	double fc,         /* Filter cutoff frequency */
309
-	double fs,         /* sampling rate */
310
-	double *k,         /* overall gain factor */
311
-	float *coef        /* pointer to 4 iir coefficients */
312
-) {
313
-		/* Calculate a1 and a2 and overwrite the original values */
314
-		prewarp(a0, a1, a2, fc, fs);
315
-		prewarp(b0, b1, b2, fc, fs);
316
-		bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, fs, coef);
317
-}
318
-
319
-void filter_init(struct Filter *filter, float cutoff, float q) {
320
-	filter_set_cutoff_q(filter, cutoff, q);
321
-}
322
-
323
-void filter_set_cutoff(struct Filter *filter, float cutoff) {
324
-	filter_set_cutoff_q(filter, cutoff, filter->q);
325
-}
326
-void filter_set_q(struct Filter *filter, float q) {
327
-	filter_set_cutoff_q(filter, filter->cutoff, q);
328
-}
329
-void filter_set_cutoff_q(struct Filter *filter, float cutoff, float q) {
330
-	float    *coef;
331
-	unsigned nInd;
332
-	double   a0, a1, a2, b0, b1, b2;
333
-	double   k;           /* overall gain factor */
334
-
335
-	filter->cutoff = cutoff;
336
-	filter->q = q;
337
-
338
-	k = 1.0;                /* Set overall filter gain */
339
-	coef = filter->coef + 1; /* Skip k, or gain */
340
-
341
-	/*
342
-	 * Compute z-domain coefficients for each biquad section
343
-	 * for new Cutoff Frequency and Resonance
344
-	 */
345
-	for (nInd = 0; nInd < IIR_LENGTH; nInd++) {
346
-		a0 = ProtoCoef[nInd].a0;
347
-		a1 = ProtoCoef[nInd].a1;
348
-		a2 = ProtoCoef[nInd].a2;
349
-
350
-		b0 = ProtoCoef[nInd].b0;
351
-		b1 = ProtoCoef[nInd].b1 / q;      /* Divide by resonance or Q */
352
-		b2 = ProtoCoef[nInd].b2;
353
-		szxform(&a0, &a1, &a2, &b0, &b1, &b2, cutoff, SAMPLE_RATE, &k, coef);
354
-		coef += 4;                       /* Point to next filter section */
355
-	}
356
-
357
-	/* Update overall filter gain in coef array */
358
-	filter->coef[0] = k;
359
-
360
-	printf("%f,%f,%f,%f,%f,%f,%f,%f,%f\n",
361
-		cutoff, q,
362
-		filter->coef[0],
363
-		filter->coef[1], filter->coef[2], filter->coef[3],
364
-		filter->coef[4], filter->coef[5], filter->coef[6]);
365
-}
366
-
367
-float filter_sample(struct Filter *filter, float input) {
368
-	unsigned int i;
369
-	float *hist1_ptr, *hist2_ptr, *coef_ptr;
370
-	float output, new_hist, history1, history2;
371
-
372
-	/* allocate history array if different size than last call */
373
-
374
-	coef_ptr = filter->coef;                /* coefficient pointer */
375
-
376
-	hist1_ptr = filter->history;            /* first history */
377
-	hist2_ptr = hist1_ptr + 1;           /* next history */
378
-
379
-	/* 1st number of coefficients array is overall input scale factor,
380
-	 * or filter gain */
381
-	output = input * (*coef_ptr++);
382
-
383
-	for (i = 0 ; i < IIR_LENGTH; i++) {
384
-		history1 = *hist1_ptr;           /* history values */
385
-		history2 = *hist2_ptr;
386
-
387
-		output = output - history1 * (*coef_ptr++);
388
-		new_hist = output - history2 * (*coef_ptr++);    /* poles */
389
-
390
-		output = new_hist + history1 * (*coef_ptr++);
391
-		output = output + history2 * (*coef_ptr++);      /* zeros */
392
-
393
-		*hist2_ptr++ = *hist1_ptr;
394
-		*hist1_ptr++ = new_hist;
395
-		hist1_ptr++;
396
-		hist2_ptr++;
397
-	}
398
-
399
-	return output;
106
+	synth->stereo_spread = w;
400 107
 }

+ 11
- 81
synth.h View File

@@ -2,98 +2,28 @@
2 2
 #define SYNTH_H_
3 3
 
4 4
 #include <stdint.h>
5
-
6
-#define SYNTH_NUM_VOICES 64
7
-#define TUNING 440
8
-
9 5
 typedef uint32_t fixed;
10 6
 
11
-struct Oscillator {
12
-	fixed phase; // fixed 16.16
13
-	fixed freq; // fixed 16.16
14
-	fixed period; // period in samples, fixed 16.16
15
-
16
-	enum {
17
-		Rectangle,
18
-		Triangle
19
-	} type;
20
-
21
-	uint8_t pulse_width; // 0 - 127
22
-	int8_t pan;
23
-};
24
-
25
-int16_t oscillator_render_sample(struct Oscillator *osc);
26
-void oscillator_set_freq(fixed freq); // fixed 16.16
27
-
28
-struct Sampler {
29
-	fixed phase; // fixed 16.16
30
-	fixed freq; // fixed 16.16
31
-	fixed period; // period in samples, fixed 16.16
32
-
33
-	uint32_t length;
34
-	uint16_t length_log2; // length = 1 << length_log2;
35
-	int16_t *data;
36
-	enum {
37
-		Nearest,
38
-		Linear
39
-	} interpolation;
40
-};
41
-
42
-int16_t sampler_sample(struct Sampler *sampler);
43
-void sampler_set_freq(fixed freq);
44
-
45
-#define IIR_LENGTH 2
46
-struct Filter {
47
-	float history[IIR_LENGTH * 2];
48
-	float coef[4 * IIR_LENGTH + 1];
49
-	float cutoff, q;
50
-};
51
-void filter_init(struct Filter *filter, float cutoff, float q);
52
-void filter_set_cutoff(struct Filter *filter, float cutoff); // frequency in Hz
53
-void filter_set_q(struct Filter *filter, float q);
54
-void filter_set_cutoff_q(struct Filter *filter, float cutoff, float q); // both
55
-float filter_sample(struct Filter *filter, float input);
56
-
57
-struct Voice {
58
-	uint32_t time;
59
-	uint16_t volume;
60
-
61
-	// Envelope
62
-	enum {
63
-		None,
64
-		Attack,
65
-		Decay,
66
-		Sustain,
67
-		Release
68
-	} env_state;
69
-
70
-	uint16_t attack, decay, release; // in ms
71
-	uint16_t sustain; // percentage
72
-
73
-	fixed freq;
74
-	uint8_t note;
75
-
76
-	uint8_t unison_spread;
77
-	uint8_t stereo_spread;
78
-	struct Oscillator osc[7];
79
-
80
-	struct Filter filter[2];
81
-};
7
+#define SYNTH_NUM_VOICES 16
8
+#define TUNING 440
82 9
 
83
-struct Synth;
84
-void voice_note_start(struct Voice *voice, uint8_t note, uint8_t velocity);
85
-void voice_stop(struct Voice *voice);
86
-void voice_render_sample(struct Voice *voice, int16_t *out);
10
+#include "envelope.h"
11
+#include "filter.h"
12
+#include "oscillator.h"
13
+#include "voice.h"
87 14
 
88 15
 struct Synth {
89 16
 	struct Voice voices[SYNTH_NUM_VOICES];
90
-	uint16_t attack, decay, sustain, release; // in ms
17
+	struct Envelope osc_env, filter_env;
18
+	uint8_t unison_spread;
19
+	uint8_t stereo_spread;
20
+	uint8_t monophonic;
91 21
 };
92 22
 
93 23
 void synth_init(struct Synth *synth);
94 24
 void synth_note_on(struct Synth *synth, uint8_t note, uint8_t velocity);
95 25
 void synth_note_off(struct Synth *synth, uint8_t note, uint8_t velocity);
96
-void synth_render_sample(struct Synth *synth, int16_t *out);
26
+void synth_render_sample(struct Synth *synth, float *out);
97 27
 void synth_set_pulse_width(struct Synth *s, uint8_t width);
98 28
 void synth_set_unison_spread(struct Synth *s, uint8_t spread);
99 29
 void synth_set_stereo_spread(struct Synth *s, uint8_t spread);

+ 7
- 0
types.h View File

@@ -0,0 +1,7 @@
1
+#ifndef TYPES_H_
2
+#define TYPES_H_
3
+
4
+#include <stdint.h>
5
+typedef uint32_t fixed;
6
+
7
+#endif /* TYPES_H_ */

+ 31
- 0
voice.c View File

@@ -0,0 +1,31 @@
1
+#include "voice.h"
2
+
3
+void voice_render_sample(struct Voice *v, float *out) {
4
+	//if(v->osc_env.state == None) return;
5
+	float amplitude = envelope_sample(&v->osc_env); // calculate based on key velocity and envelope
6
+	float cutoff = envelope_sample(&v->filter_env);
7
+
8
+	int32_t ret[2] = { 0, 0 };
9
+	float s = oscillator_render_sample(&v->osc);
10
+	filter_set_cutoff(&v->filter, cutoff * 127);
11
+	float f = filter_sample(&v->filter, v->volume * amplitude * s / 32768.0);
12
+	out[0] = (127 + v->pan) * f / 255.0;
13
+	out[1] = (127 - v->pan) * f / 255.0;
14
+}
15
+
16
+void voice_note_start(struct Voice *voice, uint8_t note, uint8_t velocity) {
17
+	voice->volume = (1+velocity) / 128.0; // in the range (0, 1]
18
+
19
+	envelope_start(&voice->osc_env);
20
+	envelope_start(&voice->filter_env);
21
+
22
+	note &= 0x7f;
23
+	voice->note = note;
24
+	voice->osc.sub_phase = voice->osc.phase;
25
+	voice->osc.sub_oct = 1;
26
+}
27
+
28
+void voice_stop(struct Voice *voice) {
29
+	envelope_stop(&voice->osc_env);
30
+	envelope_stop(&voice->filter_env);
31
+}

+ 23
- 0
voice.h View File

@@ -0,0 +1,23 @@
1
+#ifndef VOICE_H_
2
+#define VOICE_H_
3
+
4
+#include "types.h"
5
+#include "envelope.h"
6
+#include "oscillator.h"
7
+#include "filter.h"
8
+
9
+struct Voice {
10
+	uint8_t note;
11
+	float volume;
12
+	int8_t pan;
13
+
14
+	struct Envelope osc_env, filter_env;
15
+	struct Oscillator osc;
16
+	struct Filter filter;
17
+};
18
+
19
+void voice_note_start(struct Voice *voice, uint8_t note, uint8_t velocity);
20
+void voice_stop(struct Voice *voice);
21
+void voice_render_sample(struct Voice *voice, float *out);
22
+
23
+#endif /* VOICE_H_ */

Loading…
Cancel
Save