X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_audio_synth_bird.c;fp=vg_audio_synth_bird.c;h=eecad3bd5d414a9e459995153dbad5eee96cd148;hp=0000000000000000000000000000000000000000;hb=3b14f3dcd5bf9dd3c85144f2123d667bfa4bb63f;hpb=fce86711735b15bff37de0f70716808410fcf269 diff --git a/vg_audio_synth_bird.c b/vg_audio_synth_bird.c new file mode 100644 index 0000000..eecad3b --- /dev/null +++ b/vg_audio_synth_bird.c @@ -0,0 +1,419 @@ +#include "vg_audio_synth_bird.h" +#include "vg_binstr.h" + +#define DEFAULT_VOL 1.0f,0.5f,0.2f,0.125f +#define DEFAULT_TONES { {1,1}, {6,5}, {8,7}, {13,12} } +#define DEFAULT_RISE 0.00090702947f +#define DEFAULT_FALL 0.00226757369f + +static struct synth_bird_settings synth_bird__default_settings = +{ + .tones = DEFAULT_TONES, + .type = k_bird_lfo_sine_approx, + .adsr_rise = DEFAULT_RISE, + .adsr_fall = DEFAULT_FALL +}; + +static struct synth_bird_signature synth_bird__warbling_vireo[] = +{ + /* timing fundemental volumes lfo hz,depth */ + {0.13,0.10, 4000,100,100,0, DEFAULT_VOL, 60,200 }, + {0.10,0.05, 4200,-500,1700,0, DEFAULT_VOL, 60,96 }, + {0.10,0.00, 2400,-1200,1000,1700, DEFAULT_VOL, 60,96 }, + {0.06,0.04, 3100,200,-10,-1100, DEFAULT_VOL, 60,90 }, + {0.13,0.07, 4600,-2000,0,1300, DEFAULT_VOL, 60,10 }, + {0.05,0.00, 2700,-300,700,800, DEFAULT_VOL, 60,10 }, + {0.09,0.07, 3600,-300,0,0, DEFAULT_VOL, 60,20 }, + {0.05,0.07, 4800,1240,300,0, DEFAULT_VOL, 60,20 }, + {0.08,0.02, 2700,-800,150,1000, DEFAULT_VOL, 60,160 }, + {0.12,0.08, 2700,-800,150,1000, DEFAULT_VOL, 60,160 }, + {0.10,0.04, 6300,-100,-3200,1000, DEFAULT_VOL, 60,100 }, + {0.16,0.10, 4260,-200,300,1100, DEFAULT_VOL, 60,20 } +}; + +static struct synth_bird_signature synth_bird__pied_monarch[] = +{ + /* timing fundemental volumes lfo hz,depth */ + {0.18,0.13, 2200,700,-300,0, 0.6,0.05,0,0, 60,0 }, + {0.17,0.12, 2200,700,-300,0, 0.8,0.05,0,0, 60,0 }, + {0.16,0.11, 2200,700,-300,0, 0.9,0.05,0,0, 60,0 }, + {0.14,0.09, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.12,0.07, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.11,0.06, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.10,0.05, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.10,0.05, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.10,0.05, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.10,0.05, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.10,0.05, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 }, + {0.10,0.10, 2200,700,-300,0, 1.0,0.05,0,0, 60,0 } +}; + +static struct synth_bird_signature synth_bird__bridled_honeyeater[] = +{ + /* timing fundemental volumes lfo hz,depth */ + {0.10,0.10, 2000,-1000,600,0, 1.00,0.00,0.00,0.00, 30,60}, + {0.10,0.10, 4000,0,-200,-200, 0.80,0.25,0.25,0.25, 30,60}, + {0.06,0.01, 4000,0,-700,-800, 0.90,0.10,0.00,0.00, 60,20}, + {0.07,0.01, 3950,0,-700,-800, 0.90,0.10,0.00,0.00, 60,20}, + {0.08,0.01, 3900,0,-700,-800, 0.90,0.10,0.00,0.00, 60,20}, + {0.09,0.01, 3850,0,-700,-800, 0.90,0.10,0.00,0.00, 60,20}, + {0.10,0.02, 3800,0,-700,-800, 0.90,0.20,0.10,0.00, 60,20}, + {0.11,0.05, 3750,0,-700,-800, 0.90,0.40,0.20,0.00, 60,20}, + {0.12,0.20, 3700,0,-700,-800, 0.30,0.10,0.00,0.00, 60,20}, + {0.10,0.10, 2600,1300,600,0, 0.97,0.03,0.00,0.00, 60,20}, +}; + +static struct synth_bird_signature synth_bird__cricket[] = +{ + /* timing fundemental volumes lfo hz, depth */ + {0.10,0.15, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.11,0.14, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.13,0.15, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.09,0.16, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.10,0.12, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.10,0.15, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.11,0.14, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.13,0.15, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.09,0.16, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200}, + {0.10,0.12, 5000,0,0,100, 0.25,0.25,0.25,0.25, 40,200} +}; + +static struct synth_bird_signature synth_bird__gray_shrikethrush[] = +{ + /* timing fundemental volumes lfo hz, depth */ + { 0.13,0.1, 2600,-200,-100,200, 0.9,0.1,0.05,0.001, 60,10 } +}; + +static struct synth_bird_signature synth_bird__boobook[] = +{ + /* timing fundemental volumes lfo hz, depth */ + {0.3,0.14, 700,0,-100,100, 0.9,0.14,0.0,0.2, 30,18}, + {0.3,1.20, 630,0,-100,100, 0.9,0.00,0.3,0.0, 30,18} +}; + +static struct synth_bird_signature synth_bird__shrike_tit[] = +{ + /* timing fundemental volumes lfo hz, depth */ + {0.6,1.4, 2300,-300,-100,100, 1.0,0.14,0.0,0.1, 60,5 } +}; + +/* sine functions over the range [0, 44100] : [-pi, pi]. + * Not accurate! */ + +static float sine_1second_1( int o ) +{ + float s = (o<(BIRD_SAMPLE_RATE/2))?-1.0f:1.0f; + float t = ((float)o*(1.0f/(float)(BIRD_SAMPLE_RATE/2)))-1.0f - s*0.5f; + float t2 = t*t; + float t4 = t2*t2; + return s*(5.0f*t2-4.0f*t4-1.0f); +} + +static void sine_1second_4( int o[4], float v[4] ) +{ + float s[4],t[4],t2[4],t4[4]; + s[0] = (o[0]<(BIRD_SAMPLE_RATE/2))?-1.0f:1.0f; + s[1] = (o[1]<(BIRD_SAMPLE_RATE/2))?-1.0f:1.0f; + s[2] = (o[2]<(BIRD_SAMPLE_RATE/2))?-1.0f:1.0f; + s[3] = (o[3]<(BIRD_SAMPLE_RATE/2))?-1.0f:1.0f; + + t[0] = ((float)o[0]*(1.0f/(float)(BIRD_SAMPLE_RATE/2)))-1.0f - s[0]*0.5f; + t[1] = ((float)o[1]*(1.0f/(float)(BIRD_SAMPLE_RATE/2)))-1.0f - s[1]*0.5f; + t[2] = ((float)o[2]*(1.0f/(float)(BIRD_SAMPLE_RATE/2)))-1.0f - s[2]*0.5f; + t[3] = ((float)o[3]*(1.0f/(float)(BIRD_SAMPLE_RATE/2)))-1.0f - s[3]*0.5f; + + t2[0] = t[0]*t[0]; + t2[1] = t[1]*t[1]; + t2[2] = t[2]*t[2]; + t2[3] = t[3]*t[3]; + + t4[0] = t2[0]*t2[0]; + t4[1] = t2[1]*t2[1]; + t4[2] = t2[2]*t2[2]; + t4[3] = t2[3]*t2[3]; + + v[0] = s[0]*(5.0f*t2[0]-4.0f*t4[0]-1.0f); + v[1] = s[1]*(5.0f*t2[1]-4.0f*t4[1]-1.0f); + v[2] = s[2]*(5.0f*t2[2]-4.0f*t4[2]-1.0f); + v[3] = s[3]*(5.0f*t2[3]-4.0f*t4[3]-1.0f); +} + +static float saw_1second_1( int o ) +{ + float t = ((float)o*(1.0f/(float)(BIRD_SAMPLE_RATE/2)))-1.0f, + tt = t*t, + ttt = tt*t; + + return -2.5f*ttt+2.5f*t; +} + +u32 synth_bird_get_length_in_samples( struct synth_bird *bird ) +{ + u32 total = 0; + + for( int i=0; isettings.pattern_length; i ++ ){ + struct synth_bird_signature *sig = &bird->settings.pattern[i]; + + u32 l = sig->length * (float)BIRD_SAMPLE_RATE, + p = sig->pause * (float)BIRD_SAMPLE_RATE; + + total += l+p; + } + + return total; +} + +void synth_bird_reset( struct synth_bird *bird ) +{ + bird->rt.osc_main[0] = 0; + bird->rt.osc_main[1] = 0; + bird->rt.osc_main[2] = 0; + bird->rt.osc_main[3] = 0; + bird->rt.osc_lfo = 0; + + bird->rt.volume[0] = 0.0f; + bird->rt.volume[1] = 0.0f; + bird->rt.volume[2] = 0.0f; + bird->rt.volume[3] = 0.0f; + + bird->rt.fundamental = 0.0f; + bird->rt.x = 0; + bird->rt.length = bird->settings.pattern[0].length * (float)BIRD_SAMPLE_RATE; + bird->rt.gate = 1; + bird->rt.adsr = 0; + bird->rt.frame = 0; + bird->rt.lfo_hz = 0; + bird->rt.fm_depth = 0.0f; + + bird->rt.adsr_rise = bird->settings.adsr_rise * (float)BIRD_SAMPLE_RATE; + bird->rt.adsr_fall = bird->settings.adsr_fall * (float)BIRD_SAMPLE_RATE; +} + +static u32 synth_bird_save_size( struct synth_bird *bird ) +{ + return sizeof(struct synth_bird_signature) * bird->settings.pattern_length + + sizeof(struct synth_bird_settings); +} + +static void synth_bird_save( struct synth_bird *bird, void *txt ) +{ + void *src = &bird->settings; + vg_bin_str( src, txt, synth_bird_save_size( bird ) ); +} + +#if 0 +static void synth_bird_load( struct synth_bird *bird, + const char *txt, u32 length ) +{ + vg_str_bin( txt, &bird->settings, length ); + synth_bird_reset( bird ); +} + +/* expects a null terminated string */ +static u32 synth_bird_memory_requirement( u32 string_length ) +{ + return (string_length/2) + + sizeof(struct synth_bird) - sizeof(struct synth_bird_settings); +} +#endif + +#ifdef SYNTH_BIRD_STDLIB +#include "stdlib.h" +#include "string.h" + +static struct synth_bird *synth_bird_create( + struct synth_bird_settings *settings, + struct synth_bird_signature *pattern, + u32 pattern_length ) +{ + u32 pattern_size = sizeof( struct synth_bird_signature ) * pattern_length; + u32 total_size = sizeof( struct synth_bird ) + pattern_size; + struct synth_bird *bird = malloc( total_size ); + + bird->settings = *settings; + + memcpy( bird->settings.pattern, pattern, pattern_size ); + bird->settings.pattern_length = pattern_length; + + synth_bird_reset( bird ); + return bird; +} + +#endif + +static void synth_bird_think( struct synth_bird *bird ) +{ + struct synth_bird_signature *sig = &bird->settings.pattern[ bird->rt.frame ]; + + bird->rt.x ++; + if( bird->rt.x >= bird->rt.length ) + { + if( bird->rt.gate && (sig->pause != 0.0f) ) + { + bird->rt.gate = 0; + bird->rt.length = sig->pause * (float)BIRD_SAMPLE_RATE; + } + else + { + bird->rt.frame ++; + + if( bird->rt.frame >= bird->settings.pattern_length ) + bird->rt.frame = 0; + + sig = &bird->settings.pattern[ bird->rt.frame ]; + + bird->rt.gate = 1; + bird->rt.length = sig->length * (float)BIRD_SAMPLE_RATE; + } + + bird->rt.x = 0; + } + + if( bird->rt.gate ) + { + bird->rt.adsr += bird->rt.adsr_rise; + if( bird->rt.adsr > BIRD_SAMPLE_RATE ) + bird->rt.adsr = BIRD_SAMPLE_RATE; + } + else + { + bird->rt.adsr -= bird->rt.adsr_fall; + if( bird->rt.adsr < 0 ) + bird->rt.adsr = 0; + } + + if( bird->rt.gate ) + { + float l = (float)bird->rt.length, + t = ((float)bird->rt.x * (1.0f/l))*2.0f - 1.0f, + tt = t*t, + ttt = tt*t; + + bird->rt.fundamental = sig->x0 + t*sig->x1 + tt*sig->x2 + ttt*sig->x3; + } + + float vol = (float)bird->rt.adsr * (1.0f/(float)BIRD_SAMPLE_RATE); + + bird->rt.fm_depth = sig->fm; + bird->rt.lfo_hz = sig->lfo_hz; + bird->rt.volume[0] = sig->v0 * vol; + bird->rt.volume[1] = sig->v1 * vol; + bird->rt.volume[2] = sig->v2 * vol; + bird->rt.volume[3] = sig->v3 * vol; +} + +static inline void int_add_mod( int *a, int const b ) +{ + *a += b; + + if( *a > BIRD_SAMPLE_RATE ) + *a -= BIRD_SAMPLE_RATE; +} + +void synth_bird_generate_samples( struct synth_bird *bird, + float *stereo_buffer, int samples ) +{ + for( int _=0; _rt.osc_lfo, bird->rt.lfo_hz ); + float fm = sine_1second_1( bird->rt.osc_lfo ) * bird->rt.fm_depth; + + int freq = bird->rt.fundamental + fm; + int hz[4] = + { + (freq * bird->settings.tones[0][0]) / bird->settings.tones[0][1], + (freq * bird->settings.tones[1][0]) / bird->settings.tones[1][1], + (freq * bird->settings.tones[2][0]) / bird->settings.tones[2][1], + (freq * bird->settings.tones[3][0]) / bird->settings.tones[3][1], + }; + + int_add_mod( bird->rt.osc_main + 0, hz[0] ); + int_add_mod( bird->rt.osc_main + 1, hz[1] ); + int_add_mod( bird->rt.osc_main + 2, hz[2] ); + int_add_mod( bird->rt.osc_main + 3, hz[3] ); + + float v[4]; + sine_1second_4( bird->rt.osc_main, v ); + + float s = v[0] * bird->rt.volume[0] + + v[1] * bird->rt.volume[1] + + v[2] * bird->rt.volume[2] + + v[3] * bird->rt.volume[3] ; + + stereo_buffer[ _*2+0 ] = s; + stereo_buffer[ _*2+1 ] = s; + } +} + +#ifdef SYNTH_BIRD_STDLIB +#include "stdio.h" + +#define KNRM "\x1B[00m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KYEL "\x1B[33m" +#define KBLU "\x1B[34m" +#define KMAG "\x1B[35m" +#define KCYN "\x1B[36m" +#define KWHT "\x1B[37m" + +#define LOG_BAR0 " . |" +#define LOG_BAR1 "-------+-------+-------+-------+" +#define LOG_BAR2 " " + +static void synth_bird_log_pattern( struct synth_bird *bird ) +{ + synth_bird_reset( bird ); + + char output[][400]= { +KNRM "9k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KNRM " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KNRM "8k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KNRM " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KNRM "7k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KNRM " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KMAG "6k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KMAG " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KCYN "5k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KCYN " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KBLU "4k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KBLU " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KGRN "3k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KGRN " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KYEL "2k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KYEL " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KRED "1k-" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KRED " -" LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0 LOG_BAR0, +KWHT " +" LOG_BAR1 LOG_BAR1 LOG_BAR1 LOG_BAR1 LOG_BAR1 +KWHT " 0.0s"LOG_BAR2"0.5s"LOG_BAR2"1.0s"LOG_BAR2"1.5s"LOG_BAR2"2.0s"LOG_BAR2 + }; + + for( int i=0; i<190*8; i++ ) + { + for( int j=0; jrt.fundamental / 500.0f; + int j = hz; + + if( j < 0 ) j = 0; + if( j > 18 ) j = 18; + j = 18-j; + + float level = bird->rt.adsr; + level *= (1.0f/(float)BIRD_SAMPLE_RATE); + + int ch = level*3.0f; + + if( ch ) + output[j][(i/8)+7] = " *###"[ch]; + } + + for( int i=0; i<20; i++ ) + { + puts( output[i] ); + } +} +#endif