bad char
[vg.git] / projects / birds.c
1 #include "stdint.h"
2 #include "stdio.h"
3 #include "stdlib.h"
4 #include "math.h"
5
6 #define SYNTH_BIRD_STDLIB
7 #include "vg_audio_synth_bird.h"
8
9 #define WRAP1S( X ) (X)%44100
10
11 /*
12 * clang birds.c -lm -o birds && ./birds | aplay -f cd /dev/stdin
13 *
14 * Performance measurements: (generate 30seconds audio)
15 *
16 * DSP SINE_ACCURATE -O3 x Realtime
17 *
18 * on yes 0.182s 164x
19 * on no 0.134s 223x
20 * off yes 0.113s 265x
21 * off no 0.074s 405x
22 *
23 */
24
25 static double rand_float( double min, double max )
26 {
27 double r = (double)(rand()&(4096-1))*(1.0/4096.0);
28 return min + r*(max-min);
29 }
30
31 static int rand_seconds( double min, double max )
32 {
33 return rand_float( min*44100.0, max*44100.0 );
34 }
35
36 static void vg_dsp_init( void );
37 static void vg_dsp_process( float *stereo_in, float *stereo_out );
38
39 static void write_profile( FILE *fp, struct synth_bird_settings *settings,
40 struct synth_bird_signature *pattern,
41 u32 pattern_count, const char *name )
42 {
43 struct synth_bird *bird =
44 synth_bird_create( settings, pattern, pattern_count );
45
46 u32 size = synth_bird_save_size( bird );
47 char save[ size*2 ];
48 synth_bird_save( bird, save );
49
50 fprintf( fp, "%s:\n%.*s\n\n", name, size*2, save );
51 }
52
53 #define _PROFILE( FP, SETTINGS, ARRAY ) \
54 write_profile( FP, SETTINGS, ARRAY, sizeof(ARRAY)/sizeof(ARRAY[0]), \
55 #ARRAY )
56
57 static void export_all_profiles(void)
58 {
59 FILE *fp = fopen( "bird_profiles.txt", "w" );
60
61 struct synth_bird_settings *settings = &synth_bird__default_settings;
62
63 _PROFILE( fp, settings, synth_bird__warbling_vireo );
64 _PROFILE( fp, settings, synth_bird__pied_monarch );
65 _PROFILE( fp, settings, synth_bird__bridled_honeyeater );
66 _PROFILE( fp, settings, synth_bird__cricket );
67 _PROFILE( fp, settings, synth_bird__gray_shrikethrush );
68 _PROFILE( fp, settings, synth_bird__boobook );
69 _PROFILE( fp, settings, synth_bird__shrike_tit );
70
71 fclose( fp );
72 }
73
74 int main( int argc, char *argv[] )
75 {
76 vg_dsp_init();
77
78 export_all_profiles();
79
80 struct synth_bird *warbling_vireo =
81 synth_bird_create( &synth_bird__default_settings,
82 synth_bird__warbling_vireo,
83 sizeof(synth_bird__warbling_vireo)/
84 sizeof(struct synth_bird_signature) );
85
86 for(;;){
87 float stereo[2] = { 0.0f, 0.0f };
88
89 float b[2];
90
91 synth_bird_generate_samples( warbling_vireo, b, 1 );
92 stereo[0] += b[0];
93 stereo[1] += b[1];
94
95 #if 0
96 vg_dsp_process( stereo, stereo );
97 #endif
98
99 int16_t l = stereo[0] * 14000.0f,
100 r = stereo[1] * 14000.0f;
101
102 fwrite( &l, 2,1, stdout );
103 fwrite( &r, 2,1, stdout );
104 }
105 }
106
107
108 static float dsp_buffer[(1024*1024)/4];
109 static int dsp_allocations = 0;
110
111 struct dsp_delay
112 {
113 int length, cur;
114 float *buffer;
115 };
116
117 struct dsp_lpf
118 {
119 float exponent;
120 float *buffer;
121 };
122
123 struct dsp_schroeder
124 {
125 struct dsp_delay M;
126 float gain;
127 };
128
129 static float *dsp_allocate( int l )
130 {
131 float *buf = &dsp_buffer[ dsp_allocations ];
132 dsp_allocations += l;
133 return buf;
134 }
135
136 static inline void dsp_read_delay( struct dsp_delay *delay, float *s )
137 {
138 int index = delay->cur+1;
139 if( index >= delay->length ) index = 0;
140 *s = delay->buffer[ index ];
141 }
142
143 static inline void dsp_write_delay( struct dsp_delay *delay, float *s )
144 {
145 int index = delay->cur;
146 delay->buffer[ index ] = *s;
147 delay->cur ++;
148 if( delay->cur >= delay->length ) delay->cur = 0;
149 }
150
151 static void dsp_init_delay( struct dsp_delay *delay, float length )
152 {
153 delay->length = 44100.0f * length;
154 delay->cur = 0;
155 delay->buffer = dsp_allocate( delay->length );
156
157 for( int i=0; i<delay->length; i++ )
158 delay->buffer[i] = 0.0f;
159 }
160
161 static void dsp_update_lpf( struct dsp_lpf *lpf, float freq )
162 {
163 lpf->exponent = 1.0f-expf( -(1.0f/44100.0f) *2.0f*3.1415926535897f*freq );
164 }
165
166 static void dsp_init_lpf( struct dsp_lpf *lpf, float freq )
167 {
168 lpf->buffer = dsp_allocate( 4 );
169 lpf->buffer[0] = 0.0f;
170 dsp_update_lpf( lpf, freq );
171 }
172
173 static inline void dsp_write_lpf( struct dsp_lpf *lpf, float *s )
174 {
175 float diff = *s - lpf->buffer[0];
176 lpf->buffer[0] += diff * lpf->exponent;
177 }
178
179 static inline void dsp_read_lpf( struct dsp_lpf *lpf, float *s )
180 {
181 *s = lpf->buffer[0];
182 }
183
184 static void dsp_init_schroeder( struct dsp_schroeder *sch, float length,
185 float gain )
186 {
187 dsp_init_delay( &sch->M, length );
188 sch->gain = gain;
189 }
190
191 static inline void dsp_process_schroeder( struct dsp_schroeder *sch,
192 float *input, float *output )
193 {
194 float dry = *input;
195
196 float delay_output;
197 dsp_read_delay( &sch->M, &delay_output );
198
199 float feedback_attenuated = delay_output * sch->gain,
200 input_feedback_sum = dry + feedback_attenuated;
201
202 dsp_write_delay( &sch->M, &input_feedback_sum );
203
204 *output = delay_output - input_feedback_sum*sch->gain;
205 }
206
207 /* temporary global design */
208 static struct dsp_lpf __lpf_mud_free,
209 __hpf_mud_free;
210
211 static struct dsp_delay __echos[8];
212 static struct dsp_lpf __echos_lpf[8];
213 static struct dsp_schroeder __diffusion_chain[8];
214
215 static inline float vg_lerpf( float a, float b, float t )
216 {
217 return a + t*(b-a);
218 }
219
220 static void vg_dsp_init( void )
221 {
222 /* temporary global design */
223
224
225 dsp_init_lpf( &__lpf_mud_free, 125.0f );
226 dsp_init_lpf( &__hpf_mud_free, 500.0f );
227
228 float sizes[] =
229 { 2.0f, 4.0f, 8.0f, 16.0f, 32.0f, 64.0f, 128.0f, 256.0f };
230
231 float reflection_variance = 0.04f;
232
233 for( int i=0; i<8; i++ )
234 {
235 float reflection_time = ((sizes[i])/343.0f) * 1000.0f;
236
237 float var = 1.0f + rand_float(-1.0,1.0) * reflection_variance,
238 total = reflection_time * var;
239
240 dsp_init_delay( &__echos[i], total / 1000.0f );
241
242 float freq = vg_lerpf( 800.0f, 350.0f, sizes[i] / 256.0f );
243 dsp_init_lpf( &__echos_lpf[i], freq );
244 }
245
246 float diffusions[] = { 187.0f, 159.0f, 143.0f, 121.0f,
247 79.0f, 57.0f, 27.0f, 11.0f };
248
249 for( int i=0; i<8; i++ )
250 {
251 dsp_init_schroeder( __diffusion_chain+i, diffusions[i]/1000.0f, 0.7f );
252 }
253 }
254
255 static void vg_dsp_process( float *stereo_in, float *stereo_out )
256 {
257 float in_total = (stereo_in[0]+stereo_in[1])*0.5f;
258 float recieved = 0.0f;
259
260 float echo_tunings[] = { 0.05f, 0.05f, 0.1f, 0.1f,
261 0.1f, 0.1f, 0.2f, 0.3f };
262
263 for( int i=0; i<8; i++ )
264 {
265 float echo;
266 dsp_read_delay( __echos+i, &echo );
267 dsp_write_lpf( __echos_lpf+i, &echo );
268 dsp_read_lpf( __echos_lpf+i, &echo );
269
270 recieved += echo * echo_tunings[i]*0.9;
271 }
272
273 float diffused = recieved;
274
275 for( int i=0; i<8; i++ )
276 {
277 dsp_process_schroeder( __diffusion_chain+i, &diffused, &diffused );
278 }
279
280 float total = in_total + (diffused*0.5f + recieved*0.5f);
281
282 dsp_write_lpf( &__hpf_mud_free, &total );
283 dsp_read_lpf( &__hpf_mud_free, &total );
284
285 float low_mud;
286 dsp_write_lpf( &__lpf_mud_free, &total );
287 dsp_read_lpf( &__lpf_mud_free, &low_mud );
288
289 total -= low_mud;
290
291 for( int i=0; i<8; i++ )
292 dsp_write_delay( __echos+i, &total );
293
294 stereo_out[0] = stereo_in[0]*0.5f;
295 stereo_out[1] = stereo_in[1]*0.5f;
296 stereo_out[0] += diffused*0.8f+recieved*0.9f;
297 stereo_out[1] += diffused*0.8f+recieved*0.9f;
298 }
299