Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403// gm_synth.h — Standalone, dependency-free General-MIDI synthesis module.//// Extracted from audio.c so the algorithmic GM voice set (modal-additive piano,// FM electric piano, extended Karplus-Strong plucked strings, modal-bank// chromatic/percussive, subtractive synth bass / reed approximations) can be// built and tested WITHOUT the ALSA/engine dependencies of audio.c — and later// shared into the Menu Band macOS app.//// This header pulls in ONLY standard C (stdint, math, string). It does NOT// include audio.h, alsa, or any engine header. A GMVoice owns ALL per-voice GM// state (partial arrays, FM operators, KS string state, modal bank, subtractive// filter state, its own KS delay buffers, its own noise biquad + attack/secondary// burst envelopes, and its own xorshift RNG seed). The host engine supplies only// the amplitude envelope and the (smoothed) current frequency at render time.//// DSP math is byte-for-byte the same as the original audio.c implementation —// this is a MOVE + DECOUPLE, not a redesign. No per-sample sinf(): sustained// tones read the shared wt_sin wavetable (phase-increment rule).//// Public API:// void gm_synth_init(void); // build wt_sin once (idempotent)// void gm_set_organic(double amt); // global organic knob (0..1)// int gm_program_implemented(int program); // 1 if program 0..127 has a voice// int gm_voice_init(GMVoice*, int program, double freq, double sr, uint32_t seed);// double gm_voice_render(GMVoice*, double sr, double env, double frequency);
#ifndef GM_SYNTH_H#define GM_SYNTH_H
#include <stdint.h>
#ifdef __cplusplusextern "C" {#endif
// ── Compile-time sizes (must match the original ACVoice GM scratch) ──#define GM_MAX_PARTIALS 12 // modal-additive partial cap#define GM_KS_BIG_N 8192 // long KS delay line (guitar/bass — low notes)#define GM_BORE_N 2048 // short KS delay line (harpsichord/clavi)#define GM_FX_DELAY_N 8192 // per-voice FX echo ring (~170 ms @ 48k, ~43 @ 192k)
// gm_synth's own engine enum. The host engine no longer needs to know which// WaveType a program maps to — gm_voice_init() stores the chosen engine here and// gm_voice_render() dispatches on it internally.typedef enum { GM_ENGINE_NONE = 0, GM_ENGINE_GMPIANO, // modal additive + inharmonicity (acoustic pianos) GM_ENGINE_EPIANO, // 2-op FM tine/reed (electric pianos) GM_ENGINE_PLUCK, // extended Karplus-Strong (harpsichord/clavi/guitar/bass/ethnic) GM_ENGINE_MODAL, // modal bank (chromatic perc / kalimba / percussive / timpani) GM_ENGINE_SYNTHBASS, // subtractive (synth bass / reed approximations / synth brass) GM_ENGINE_WAVEGUIDE, // bidirectional digital waveguide (bowed/brass/reed/flute) GM_ENGINE_ORGAN, // additive Hammond drawbars + Leslie; free-reed accordion/harmonica GM_ENGINE_SUPERSAW, // detuned multi-osc subtractive: ensemble / synth lead / synth pad GM_ENGINE_FORMANT, // source-filter vocal formant bank: choir / voice / synth-voice GM_ENGINE_SYNTHFX, // layered sound-design FX: rain/soundtrack/crystal/atmosphere/... GM_ENGINE_SOUNDFX // stochastic/noise sound effects: seashore/bird/applause/gunshot/...} GMEngine;
// Sub-mode inside GM_ENGINE_SYNTHFX (GM 96-103). Each shares the generic// tonal-core + texture-bed + time-effect chain; the mode selects which time// effect and texture flavor dominate.typedef enum { GM_FX_RAIN = 0, // 96 FX1 — PhISEM droplets + S&H'd shimmer pair GM_FX_SOUNDTRACK, // 97 FX2 — detuned-saw pad, slow LFO-swept LPF GM_FX_CRYSTAL, // 98 FX3 — inharmonic FM bell + feedback delay GM_FX_ATMOSPHERE, // 99 FX4 — pad + filtered-noise bed GM_FX_BRIGHTNESS, // 100 FX5 — bright rising-FM pad GM_FX_GOBLINS, // 101 FX6 — dark ring-modded saw + S&H cutoff GM_FX_ECHOES, // 102 FX7 — bright source + regenerating dark delay GM_FX_SCIFI // 103 FX8 — swept osc + resonant filter + noise burst} GMSynthFxMode;
// Sub-mode inside GM_ENGINE_SOUNDFX (GM 120-127).typedef enum { GM_SFX_FRET = 0, // 120 Guitar Fret Noise — swept filtered-noise squeak GM_SFX_BREATH, // 121 Breath Noise — band-passed noise puff (+PhISEM grain) GM_SFX_SEASHORE, // 122 Seashore — PhISEM surf + slow swell LFOs GM_SFX_BIRD, // 123 Bird Tweet — pitch-swept FM chirps, trilled syllables GM_SFX_TELEPHONE, // 124 Telephone Ring — gated dual sine (440+480) cadence GM_SFX_HELICOPTER, // 125 Helicopter — periodic-AM broadband noise + rumble GM_SFX_APPLAUSE, // 126 Applause — PhISEM crowd claps + swell GM_SFX_GUNSHOT // 127 Gunshot — noise crack burst + low boom decay} GMSoundFxMode;
// Nonlinearity / excitation mode inside GM_ENGINE_WAVEGUIDE. The shared// bidirectional bore delay line is constant; the junction physics differ:// BOWED — stick-slip friction (McIntyre-Schumacher-Woodhouse / STK BowTable)// LIP — pressure-controlled lip valve (STK Brass), quadratic NL// REED — saturating reed reflection (STK ReedTable); clarinet inverts bore// JET — Cook flute jet delay + cubic + blowing noisetypedef enum { GM_WG_BOWED = 0, GM_WG_LIP, GM_WG_REED, GM_WG_JET} GMWaveguideMode;
// Per-voice GM synthesis state. Self-contained: holds every field the GM voices// touched in ACVoice plus its own copies of the buffers/biquad/burst envelopes// that previously aliased shared ACVoice scratch (whistle_bore_buf, the noise// biquad, gun_click_*, gun_secondary_*). The engine embeds one of these per voice.typedef struct { GMEngine engine; // which generator renders this voice int program; // GM program (0-based) — debug / routing
// Own randomness — xorshift32 stream seeded per-trigger from the host seed. uint32_t rng_seed;
// -- Modal additive partials (gmpiano + modal bank) -- int p_count; double p_phase[GM_MAX_PARTIALS]; double p_amp[GM_MAX_PARTIALS]; double p_finc[GM_MAX_PARTIALS]; double p_dec_mult[GM_MAX_PARTIALS]; int gm_dual; // honky-tonk: 2nd detuned string set double p2_phase[GM_MAX_PARTIALS]; double p2_finc[GM_MAX_PARTIALS]; double gm_drive; // per-voice tanh drive (electric grand) double gm_hammer_env; // hammer/strike noise-burst envelope double gm_hammer_dec; double gm_hammer_amp; double gm_hammer_lp; // 1-pole LPF state for hammer noise
// -- FM tine/reed operators (epiano) -- double fm_cphase, fm_cinc; double fm_mphase, fm_minc; double fm_index, fm_index_dec; double fm_tphase, fm_tinc; double fm_tindex, fm_tindex_dec; double fm_pickup_bias; double fm_hp_x1, fm_hp_y1; // DC blocker after pickup nonlinearity
// -- Extended Karplus-Strong string state (pluck) -- double harp_lp1; // loop-LPF state double ks_stretch; double ks_loop_b; double ks_beta; double ks_pick_amt; double ks_drive; float bore_buf[GM_BORE_N]; // short delay line (harpsichord/clavi) int bore_w; float ks_buf[GM_KS_BIG_N]; // long delay line (guitar/bass/ethnic) int ks_w; int ks_use_big; // 1 = render from ks_buf int ks_hard_clip; // 1 = hard waveshaper (distortion guitar) double ks_jawari_depth; // buzzing-bridge nonlinearity depth double ks_jawari_thresh; double ks_body_a1[3], ks_body_a2[3]; // body-resonance biquad coeffs double ks_body_g[3]; double ks_body_y1[3], ks_body_y2[3]; // body-resonance biquad state int ks_body_n; // -- Rich modal body (bowed strings): a dense bank of resonant modes that // approximates the instrument corpus's volumetric eigenmodes (air cavity // + plate modes + bridge hill), so it reads as a real resonant body // rather than a few isolated peaks. Parallel resonators on the output. -- double rbody_a1[24], rbody_a2[24]; double rbody_g[24]; double rbody_y1[24], rbody_y2[24]; double rbody_dry; // dry passthrough (1 = full string + body on top) int rbody_n;
// Attack-noise burst (finger thump / pick click / slap clack) — own biquad + // envelope (these aliased the engine noise biquad + gun_click_* in audio.c). double atk_env; // burst amplitude envelope double atk_dec; // per-sample decay multiplier double nb0, nb1, nb2, na1, na2; // burst biquad coefficients double nx1, nx2, ny1, ny2; // burst biquad state // Secondary excitation (slap snap-back) — own countdown (aliased gun_secondary_*). double sec_trig; // sample countdown (<=0 = fired/idle) double sec_amp;
// -- Modal-bank extras (modal) -- double gm_trem_phase; double gm_trem_inc; double gm_trem_depth; double gm_modal_bloom; double gm_modal_fund; int gm_modal_pitched;
// -- Subtractive synth bass / reed-as-saw (synthbass) -- double sb_o1_phase, sb_o1_inc; double sb_o2_phase, sb_o2_inc; int sb_o2_square; double sb_o2_mix; double sb_sub_phase, sb_sub_inc; double sb_sub_mix; double sb_fm_index, sb_fm_dec; double sb_lp1, sb_lp2; double sb_bp1, sb_bp2; double sb_cut, sb_cut_target; double sb_cut_dec; double sb_res; double sb_pitch_mult, sb_pitch_dec; int sb_sustain; double sb_drone_phase, sb_drone_inc; double sb_drone_mix; double sb_breath_lp; double sb_breath_amt; double sb_vib_phase, sb_vib_inc; double sb_vib_depth;
// -- Digital waveguide (GM_ENGINE_WAVEGUIDE): bowed / brass / reed / flute -- GMWaveguideMode wg_mode; // Shared bore delay line. Reuses ks_buf (GM_KS_BIG_N) so low brass/strings // (contrabass ~33 Hz, tuba ~D1) fit at 192 kHz. wg_w is its write index. int wg_w; double wg_base_delay; // bore length in samples (sr/f or sr/f*2+3) double wg_loop_lp; // 1-pole loop-loss LPF state double wg_loop_damp; // loop-loss coefficient (darker = larger) double wg_hp_x1, wg_hp_y1; // DC blocker after the junction double wg_breath; // smoothed breath/bow pressure target follower double wg_breath_max; // pressure/velocity ceiling (loudness+brightness) double wg_noise_gain; // turbulence / bow-grind / chiff amount double wg_attack_ms; // pressure ramp time (slow bow / soft horn onset) double wg_attack_env; // 0..1 onset ramp, climbs to 1 double wg_attack_inc; // per-sample onset ramp increment // Vibrato (all modes) — phase-increment LFO baked rate, depth in delay frac. double wg_vib_phase, wg_vib_inc, wg_vib_depth; // BOWED — friction junction. double wg_bow_beta; // bow position 0..1 (bridge..nut split ratio) double wg_bow_slope; // bow force / pressure (steeper = more pressure) // LIP (brass) — lip resonance biquad tracking f0 + scatter gains. double wg_lip_b0, wg_lip_b1, wg_lip_b2, wg_lip_a1, wg_lip_a2; double wg_lip_x1, wg_lip_x2, wg_lip_y1, wg_lip_y2; double wg_lip_gain; // REED — STK reed table affine map + bore-reflection sign. double wg_reed_offset, wg_reed_slope; int wg_bore_invert; // 1 = clarinet (cylindrical, odd harmonics) // JET (flute) — jet delay ratio (jet length / bore length). double wg_jet_ratio; // Output formant/mute/bell shaping: one biquad bandpass + a 1-pole tilt. double wg_fmt_b0, wg_fmt_b2, wg_fmt_a1, wg_fmt_a2; double wg_fmt_x1, wg_fmt_x2, wg_fmt_y1, wg_fmt_y2; double wg_fmt_gain; // 0 = no output formant biquad double wg_out_lp; // output LP state (mute / dark bell) double wg_out_lp_g; // output LP coefficient (0 = bypass) double wg_out_scale; // output gain // Section shimmer (brass section / tremolo strings) — amplitude LFO. double wg_trem_phase, wg_trem_inc, wg_trem_depth;
// -- Additive Hammond drawbars + free-reed (GM_ENGINE_ORGAN) -- // 9 sine drawbars at fixed footage ratios; or detuned saw/pulse reed banks. int org_nbars; // active drawbar / reed-bank count double org_phase[9]; // per-bar oscillator phase double org_inc[9]; // per-bar phase increment (f0*ratio/sr) double org_amp[9]; // per-bar registration amplitude int org_freereed; // 1 = saw/pulse reed banks (accordion/harmonica) int org_bar_square[9]; // free-reed: 1 = pulse, 0 = saw for this bank double org_drive; // rock-organ overdrive (tanh) double org_perc_env, org_perc_dec, org_perc_amp; // percussive-organ 2nd-harm ping double org_perc_phase, org_perc_inc; double org_click_env, org_click_dec, org_click_amp; // key-click HF noise burst double org_click_lp; // 1-pole HP-ish state for click double org_leslie_phase, org_leslie_inc, org_leslie_depth; // Leslie amp+pitch LFO double org_breath_lp, org_breath_amt; // free-reed breath noise double org_lp; // free-reed gentle output LPF state double org_lp_g; // free-reed LPF coefficient (0 = bypass)
// -- Detuned multi-osc subtractive (GM_ENGINE_SUPERSAW): ensemble/lead/pad -- int ss_nosc; // active oscillator count (1..7) double ss_phase[7]; // per-osc phase double ss_inc[7]; // per-osc phase increment double ss_gain[7]; // per-osc gain (Szabo center/side or unity) int ss_square[7]; // 1 = pulse/square osc, 0 = saw double ss_pwm_phase, ss_pwm_inc, ss_pwm_depth; // PWM LFO (square width) double ss_hp_x1, ss_hp_y1; // pitch-tracked 1-pole HP (supersaw mud cut) double ss_hp_g; // HP coefficient // State-variable LPF (Chamberlin) + slow cutoff sweep LFO + attack env. double ss_svf_lp, ss_svf_bp; // SVF integrator state double ss_cut, ss_cut_base; // current + base cutoff (Hz) double ss_cut_env, ss_cut_env_dec, ss_cut_env_amt; // attack filter-envelope (Hz add) double ss_res; // resonance (0..~0.98) double ss_sweep_phase, ss_sweep_inc, ss_sweep_depth; // slow cutoff LFO (octaves) double ss_attack_env, ss_attack_inc; // slow amplitude attack ramp 0..1 double ss_vib_phase, ss_vib_inc, ss_vib_depth; // collective vibrato float ss_chorus_buf[1024]; // short modulated chorus delay line int ss_chorus_w; double ss_chorus_phase, ss_chorus_inc, ss_chorus_depth, ss_chorus_mix; double ss_drive; // charang/overdrive tanh double ss_sub_phase, ss_sub_inc, ss_sub_mix; // bass+lead sub-octave int ss_sub_square; double ss_chiff_env, ss_chiff_dec, ss_chiff_amt; // chiff/transient noise burst double ss_chiff_nb0, ss_chiff_nb2, ss_chiff_na1, ss_chiff_na2; // chiff BPF double ss_chiff_x1, ss_chiff_x2, ss_chiff_y1, ss_chiff_y2; double ss_trem_phase, ss_trem_inc, ss_trem_depth; // halo amplitude tremolo double ss_body_dec; // orchestra-hit body decay (1 = sustained) double ss_body_amp; // orchestra-hit body amplitude env double ss_pitch_mult, ss_pitch_dec; // orchestra-hit downward pitch blip double ss_out_scale; // output gain
// -- Vocal formant bank (GM_ENGINE_FORMANT): choir / voice / synth-voice -- // Up to 3 detuned saw/pulse glottal sources → 3 parallel formant biquads. int fmt_nsrc; // source-oscillator count (1=solo, 3=choir) double fmt_src_phase[3]; // per-source phase double fmt_src_inc[3]; // per-source phase increment double fmt_nbands; // active formant band count (3) double fmt_b0[3], fmt_b2[3], fmt_a1[3], fmt_a2[3]; // 3 formant bandpass biquads double fmt_x1[3], fmt_x2[3], fmt_y1[3], fmt_y2[3]; double fmt_g[3]; // per-formant linear gain double fmt_attack_env, fmt_attack_inc; // slow onset ramp double fmt_breath_lp, fmt_breath_amt; // aspiration noise into formants double fmt_vib_phase[3], fmt_vib_inc[3], fmt_vib_depth; // decorrelated per-source vibrato
// -- Shared FX primitives (GM_ENGINE_SYNTHFX / GM_ENGINE_SOUNDFX) -- // Per-voice delay/echo ring (crystal/echoes/atmosphere feedback repeats). float fx_delay[GM_FX_DELAY_N]; int fx_delay_w; double fx_delay_samps; // current delay length in samples double fx_delay_fb; // feedback gain (0..~0.85) double fx_delay_mix; // wet mix double fx_delay_damp; // 1-pole HF damping in the feedback path (0=bypass) double fx_delay_lp; // damping filter state // LFO + sample-and-hold (slow modulation of cutoff/pitch/shimmer). double fx_lfo_phase, fx_lfo_inc, fx_lfo_depth; double fx_sh_phase, fx_sh_inc; // S&H clock double fx_sh_value; // held random value [-1,1] // Ring-mod carrier (goblins/rain shimmer/sci-fi). double fx_ring_phase, fx_ring_inc, fx_ring_mix; // Generic tonal-core oscillators (saw/sine/FM) shared by the FX engines. double fx_o1_phase, fx_o1_inc; double fx_o2_phase, fx_o2_inc; // detuned partner / FM modulator / 2nd sine double fx_o3_phase, fx_o3_inc; // 3rd saw / shimmer partner double fx_fm_index, fx_fm_index_env, fx_fm_index_dec; // FM mod depth + env int fx_fm_rising; // 1 = index ramps UP into the note (brightness) // State-variable LPF (Chamberlin) for pad/sci-fi sweeps. double fx_svf_lp, fx_svf_bp; double fx_cut, fx_cut_base, fx_res; double fx_cut_env, fx_cut_env_dec; // pitch/cutoff sweep envelope (sci-fi) int fx_cut_sweep_down; // 1 = cutoff sweeps downward over the note // Filtered-noise texture bed (atmosphere/rain/seashore/breath/helicopter). double fx_noise_lp, fx_noise_lp2; // cascaded 1-pole LP state double fx_noise_hp_x1, fx_noise_hp_y1; // 1-pole HP state double fx_noise_amt; // texture/noise level double fx_noise_bp0, fx_noise_bp2, fx_noise_bpa1, fx_noise_bpa2; // BP biquad double fx_noise_bx1, fx_noise_bx2, fx_noise_by1, fx_noise_by2; int fx_noise_use_bp; // 1 = route noise through the BP biquad // Pitch / cutoff sweep multiplier (bird chirp, sci-fi zap, gunshot boom). double fx_pitch_mult, fx_pitch_dec, fx_pitch_target; // Amplitude envelopes internal to a trigger (bird syllables, gunshot boom). double fx_amp_env, fx_amp_dec; // self-decaying internal AD envelope double fx_amp_env2, fx_amp_dec2; // 2nd internal envelope (crack vs boom) // Gate/cadence counter (telephone ring on/off, bird syllable gating). double fx_gate_phase, fx_gate_inc; // phase-increment cadence clock double fx_gate_on_frac; // duty fraction that is "on" int fx_gate_n, fx_gate_max; // syllable/event counters // Periodic-AM pulse (helicopter rotor blade-passage). double fx_am_phase, fx_am_inc, fx_am_sharp, fx_am_depth; // Boom oscillator (sci-fi / gunshot low thump). double fx_boom_phase, fx_boom_inc; double fx_out_scale;
// -- PhISEM particle engine (rain / seashore / applause / breath grains) -- double ph_energy; // shake energy, leaks each sample double ph_sys_decay; // systemDecay (energy leak per sample) double ph_snd_decay; // soundDecay (per-collision ring decay) double ph_num; // numObjects (collision-probability scale) double ph_snd_level; // accumulated collision sound level double ph_gain; // output gain // Up to 3 collision resonators (clap/drop/shore band-passes). int ph_nres; double ph_res_a1[3], ph_res_a2[3], ph_res_b0[3]; double ph_res_y1[3], ph_res_y2[3]; // Slow swell LFOs that re-pump energy (seashore waves / applause swell). int ph_nswell; double ph_swell_phase[3], ph_swell_inc[3]; double ph_swell_depth; double ph_energy_floor; // sustained density floor (rain/seashore vs one-shot)} GMVoice;
// Build the wt_sin wavetable. Idempotent; safe to call repeatedly. gm_voice_init// calls it internally so callers need not, but it is exposed for explicit setup.void gm_synth_init(void);
// Global "organic" amount: 0 = bit-identical, 1 = max tasteful spread. Default 0.6.void gm_set_organic(double amt);
// 1 if `program` (0-based GM) has a bespoke algorithmic voice in this build.// Implemented: ALL 128 GM programs 0-127. Families: Piano 0-7, Chromatic Perc// 8-15, Organ 16-23, Guitar 24-31, Bass 32-39, Strings 40-47, Ensemble 48-55,// Brass 56-63, Reed 64-71, Pipe 72-79, Synth Lead 80-87, Synth Pad 88-95,// Synth FX 96-103, Ethnic 104-111, Percussive 112-119, Sound FX 120-127.int gm_program_implemented(int program);
// Note-on init. Selects the engine, fills per-voice state from the matching// program row, and applies bounded per-trigger stochasticism drawn from `seed`// (every voice probabilistic — the same note never renders identically). Returns// 0 on success, -1 for an unimplemented program (leaves engine = GM_ENGINE_NONE).int gm_voice_init(GMVoice *v, int program, double freq, double sample_rate, uint32_t seed);
// Render one sample. The host engine supplies the amplitude envelope `env`// (0..1) and the current (smoothed) `frequency` in Hz — gm_synth owns everything// else. Dispatches on the voice's stored engine. Returns the mono sample.double gm_voice_render(GMVoice *v, double sample_rate, double env, double frequency);
#ifdef __cplusplus}#endif
#endif // GM_SYNTH_H