114 lines
2.6 KiB
C++
114 lines
2.6 KiB
C++
#include <stdint.h>
|
|
|
|
#include "daisysp.h"
|
|
#include "state.h"
|
|
#include "const.h"
|
|
#include "vco.h"
|
|
|
|
#include "synth.h"
|
|
|
|
using namespace daisysp;
|
|
|
|
static state_t* state = NULL;
|
|
|
|
Oscillator osc;
|
|
Svf filter;
|
|
AdEnv vco_env;
|
|
AdEnv filter_env;
|
|
|
|
float clock_phase = 0.0f;
|
|
bool clock_trig = false;
|
|
|
|
uint32_t amen_phase_fp = 0;
|
|
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;
|
|
}
|
|
}
|
|
|
|
#include "amenbreak.h"
|
|
|
|
|
|
float amenbreak() {
|
|
amen_phase_fp += state->amen_inc_fp;
|
|
|
|
uint32_t idx0 = (amen_phase_fp >> 16) % amen_sample_count;
|
|
uint32_t idx1 = (idx0 + 1) % amen_sample_count;
|
|
|
|
float frac = (float)(amen_phase_fp & 0xFFFF) * 0.0000152588f;
|
|
|
|
const float INV_INT16 = 0.00003051757f;
|
|
float s0 = amen_samples[idx0] * INV_INT16;
|
|
float s1 = amen_samples[idx1] * INV_INT16;
|
|
|
|
return s0 + frac * (s1 - s0);
|
|
}
|
|
|
|
void synth_init(state_t* _state) {
|
|
state = _state;
|
|
osc.Init(SAMPLE_RATE);
|
|
filter.Init(SAMPLE_RATE);
|
|
vco_env.Init(SAMPLE_RATE);
|
|
vco_env.SetMin(0.0f);
|
|
vco_env.SetMax(VCO_VOLUME_MAX);
|
|
filter_env.Init(SAMPLE_RATE);
|
|
filter_env.SetMin(0.0f);
|
|
filter_env.SetMax(FILTER_FREQ_MAX);
|
|
clock_phase = 0.0f;
|
|
clock_trig = false;
|
|
amen_phase_fp = 0;
|
|
}
|
|
|
|
float get_sample(void) {
|
|
if (state == NULL) return 0.0f;
|
|
|
|
bool clock_trig = false;
|
|
|
|
clock_phase += state->clock_inc;
|
|
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, state->env1_attack);
|
|
vco_env.SetTime(ADENV_SEG_DECAY, state->env1_decay);
|
|
filter_env.SetTime(ADENV_SEG_ATTACK, state->env2_attack);
|
|
filter_env.SetTime(ADENV_SEG_DECAY, state->env2_decay);
|
|
|
|
float vco_env_out = vco_env.Process();
|
|
float filter_env_out = filter_env.Process();
|
|
|
|
osc.SetFreq(state->vco_freq);
|
|
osc.SetWaveform(vco_mode_to_daisy(state->vco_mode));
|
|
osc.SetAmp(1.0f);
|
|
float vco_out = osc.Process();
|
|
|
|
float cutoff = state->filter_freq + filter_env_out;
|
|
if (cutoff > 16000.0f) cutoff = 16000.0f;
|
|
|
|
filter.SetFreq(cutoff);
|
|
filter.SetRes(state->filter_resonance);
|
|
filter.Process(vco_out);
|
|
|
|
float vca_out = filter.Low() * vco_env_out * state->vco_volume;
|
|
float amen_out = state->amen_enabled ? amenbreak() : 0.0f;
|
|
float mix = vca_out + amen_out;
|
|
|
|
if (mix > 1.0f) return 1.0f;
|
|
if (mix < -1.0f) return -1.0f;
|
|
|
|
return mix;
|
|
}
|
|
|