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