#include #include #include "daisysp.h" #include "state.h" #include "const.h" #include "vco.h" #include "dsp.h" #include "synth.h" using namespace daisysp; Oscillator osc; Svf filter; AdEnv vco_env; AdEnv filter_env; DelayLine comb0; DelayLine comb1; DelayLine comb2; DelayLine comb3; DelayLine ap0; DelayLine ap1; float clock_phase = 0.0f; bool clock_trig = false; float amen_phase = 0.0f; float amen_length = 0.0f; static inline auto vco_mode_to_daisy(vco_mode_t mode) { switch (mode) { case VCO_SQUARE: return daisysp::Oscillator::WAVE_SQUARE; case VCO_TRIANGLE: return daisysp::Oscillator::WAVE_TRI; case VCO_SAW: return daisysp::Oscillator::WAVE_SAW; case VCO_SINE: default: return daisysp::Oscillator::WAVE_SIN; } } static inline float pot_to_freq(float v, float min, float max) { return min * powf(max / min, v); } static inline float pot_to_time(float v, float min, float max) { return min * powf(max / min, v); } static inline float quantize(float freq, float temp) { float midi = temp * log2f(freq / 440.0f) + 69.0f; float note = roundf(midi); return 440.0f * powf(2.0f, (note - 69.0f) / temp); } static inline float low_pass(float in, float* z, float coeff) { *z += coeff * (in - *z); return *z; } float reverb(float in, float amount) { static float damp0 = 0.0f, damp1 = 0.0f, damp2 = 0.0f, damp3 = 0.0f; float feedback = 0.84f; float damp = 0.3f; float c0 = comb0.Read(); low_pass(in + c0 * feedback, &damp0, damp); comb0.Write(damp0); float c1 = comb1.Read(); low_pass(in + c1 * feedback, &damp1, damp); comb1.Write(damp1); float c2 = comb2.Read(); low_pass(in + c2 * feedback, &damp2, damp); comb2.Write(damp2); float c3 = comb3.Read(); low_pass(in + c3 * feedback, &damp3, damp); comb3.Write(damp3); float wet = (c0 + c1 + c2 + c3) * 0.25f; const float g = 0.7f; float a0r = ap0.Read(); float a0in = wet + (-g * a0r); ap0.Write(a0in); wet = a0r + g * a0in; float a1r = ap1.Read(); float a1in = wet + (-g * a1r); ap1.Write(a1in); wet = a1r + g * a1in; return in + amount * (wet - in); } #include "amenbreak.h" float amenbreak(float beat_samples, float playback_rate) { amen_length = beat_samples * 4.0f * AMEN_BARS; uint32_t idx0 = (uint32_t)amen_phase % amen_sample_count; uint32_t idx1 = (idx0 + 1) % amen_sample_count; float frac = amen_phase - floorf(amen_phase); float s0 = amen_samples[idx0] * (1.0f / 32768.0f); float s1 = amen_samples[idx1] * (1.0f / 32768.0f); float amen_out = s0 + frac * (s1 - s0); amen_phase += playback_rate; if (amen_phase >= amen_length) amen_phase -= amen_length; return amen_out; } void synth_init(void) { osc.Init(SAMPLE_RATE); osc.SetWaveform(vco_mode_to_daisy(VCO_SAW)); osc.SetFreq(440.0f); osc.SetAmp(1.0f); filter.Init(SAMPLE_RATE); filter.SetFreq(2000.0f); filter.SetRes(0.0f); vco_env.Init(SAMPLE_RATE); vco_env.SetTime(ADENV_SEG_ATTACK, 0.01f); vco_env.SetTime(ADENV_SEG_DECAY, 0.8f); vco_env.SetMin(0.0f); vco_env.SetMax(1.0f); filter_env.Init(SAMPLE_RATE); filter_env.SetTime(ADENV_SEG_ATTACK, 0.01f); filter_env.SetTime(ADENV_SEG_DECAY, 0.5f); filter_env.SetMin(0.0f); filter_env.SetMax(2000.0f); state.clock_bpm = 0.1f; clock_phase = 0.0f; clock_trig = false; amen_phase = 0.0f; state.amen_enabled = true; state.reverb_amount = 1.0; } float get_sample(void) { float bpm = BPM_MIN + state.clock_bpm * (BPM_MAX - BPM_MIN); float beat_samples = SAMPLE_RATE * 60.0f / bpm; float playback_rate = bpm / AMEN_BPM; float clock_inc = bpm / 60.0f / SAMPLE_RATE; clock_phase += clock_inc; clock_trig = false; if (clock_phase >= 1.0f) { clock_phase -= 1.0f; clock_trig = true; } if (clock_trig) { vco_env.Trigger(); filter_env.Trigger(); } //vco_env.SetTime(ADENV_SEG_ATTACK, pot_to_time(state.env1_attack, ENV_ATTACK_MIN, ENV_ATTACK_MAX)); //vco_env.SetTime(ADENV_SEG_DECAY, pot_to_time(state.env1_release, ENV_RELEASE_MIN, ENV_RELEASE_MAX)); //filter_env.SetTime(ADENV_SEG_ATTACK, pot_to_time(state.env2_attack, ENV_ATTACK_MIN, ENV_ATTACK_MAX)); //filter_env.SetTime(ADENV_SEG_DECAY, pot_to_time(state.env2_release, ENV_RELEASE_MIN, ENV_RELEASE_MAX)); float vco_env_out = vco_env.Process(); float filter_env_out = filter_env.Process(); float vco_freq = pot_to_freq(state.vco_freq, VCO_FREQ_MIN, VCO_FREQ_MAX); if (state.quant_enabled) vco_freq = quantize(vco_freq, 12.0f); //osc.SetFreq(vco_freq); static int n = VCO_SINE; osc.SetWaveform(vco_mode_to_daisy((vco_mode_t)(n++ % 4))); //osc.SetAmp(1.0f); float vco_out = osc.Process(); float base_cutoff = pot_to_freq(state.filter_freq, FILTER_FREQ_MIN, FILTER_FREQ_MAX); float mod_cutoff = base_cutoff + filter_env_out * (FILTER_FREQ_MAX - FILTER_FREQ_MIN); mod_cutoff = fclamp(mod_cutoff, FILTER_FREQ_MIN, FILTER_FREQ_MAX); //filter.SetFreq(mod_cutoff); //filter.SetRes(state.filter_resonance); filter.Process(vco_out); float filtered = filter.Low(); float vca_out = filtered * vco_env_out;// * state.vco_volume; float reverb_out = vca_out; //reverb(vca_out, state.reverb_amount); float amen_out = 0.0f; if (state.amen_enabled) amen_out = amenbreak(beat_samples, playback_rate); float mix = reverb_out + amen_out; mix = fclamp(mix, -1.0f, 1.0f); return mix; }