#ifndef SYNTH_H #define SYNTH_H #include #define VOICE_COUNT 8 #define OSC_COUNT 2 #define LFO_COUNT 2 #define OSC_MAX_GAIN 4.0f typedef enum { WAVE_SINE, WAVE_TRIANGLE, WAVE_SAW, WAVE_RAMP, WAVE_PULSE, WAVE_NOISE, WAVE_COUNT // handy for the modulo wrap on waveform switching } Waveform; // Envelope structures: typedef enum { ENV_IDLE, ENV_ATTACK, ENV_DECAY, ENV_SUSTAIN, ENV_RELEASE } EnvStage; typedef enum { MOD_SOURCE_NONE = 0, MOD_SOURCE_AMP_ENV = 1, MOD_SOURCE_MOD_ENV = 2, MOD_SOURCE_LFO = 3, MOD_SOURCE_LFO2 = 4 } ModSource; typedef struct { EnvStage stage; float value; // current output value, 0.0 to 1.0 float attackSec; float decaySec; float sustainLevel; float releaseSec; } Envelope; typedef struct { float phase; float rate; // Hz Waveform waveform; int active; float noiseHeld; float noisePhase; } LFO; typedef enum { FILTER_LOWPASS, FILTER_HIGHPASS, FILTER_BANDPASS, FILTER_COUNT } FilterType; typedef struct { float cutoff; // Hz float resonance; // 0.0 (flat) to 0.99 (near self-oscillation) FilterType type; int active; float low, band; // TPT integrator states s1, s2 int modRouting; float modDepth; // Hz int resModRouting; float resModDepth; // resonance units (-0.99..0.99) } Filter; typedef struct { float phase; float dutyCycle; Waveform waveform; float detune; // cents, 0 = no detune float noiseHeld; // last drawn random value for clocked noise float noisePhase; // tracks when to draw a new noise value float gain; int active; // whether this oscillator contributes to output int octave; // transposition in octaves, -2 to +2 // Modulation routing: one source per destination by design. // Each parameter (pwm, detune, gain) has exactly one mod source and one depth. int modRouting[3]; // 0=off, 1=env0, 2=env1, 3=lfo0, 4=lfo1 float modDepth[3]; // Depth of modulation parameter } Oscillator; typedef struct { Oscillator oscillators[OSC_COUNT]; float freqHz; int active; int midiNote; Envelope ampEnv; Envelope modEnv; Filter filter; } Voice; typedef struct { float sampleRate; float pitchBend; float pitchBendRange; int lastStolenVoice; Voice voices[VOICE_COUNT]; float volume; // 0.0 to 1.0, master output level LFO lfos[LFO_COUNT]; } Synth; // Envelope functions: void envelopeInit(Envelope *e, float attackSec, float decaySec, float sustainLevel, float releaseSec); void envelopeNoteOn(Envelope *e); void envelopeNoteOff(Envelope *e); float envelopeTick(Envelope *e, float sampleRate); // Oscillator functions: void oscillatorInit(Oscillator *o, Waveform waveform, float dutyCycle, float detune, float gain); float oscillatorTick(Oscillator *o, float freqHz, float bendMultiplier, float sampleRate, float dutyCycle, float detune, float gain); // Synth functions: void synthInit(Synth *s, float sampleRate); void synthResetPatch(Synth *s); void synthNoteOn(Synth *s, int midiNote); void synthNoteOff(Synth *s, int midiNote); void synthFillBuffer(Synth *s, int16_t *out, int frames); void synthSyncVoices(Synth *s); // LFO functions: float lfoTick(LFO *l, float sampleRate); // Filter functions: float filterTick(Filter *f, float input, float cutoff, float resonance, float sampleRate); const char *filterTypeName(FilterType t); // Waveform functions: float waveformSample(Waveform w, float phase, float dutyCycle, float noiseHeld); const char *waveformName(Waveform w); #endif