psyn/voice.c

135 lines
3.2 KiB
C

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "osc.h"
#include "env.h"
#include "filter.h"
#include "control.h"
#include "voice.h"
#include "engine.h"
#include "psyn.h"
#include "rng.h"
static inline double max(double a, double b)
{
return a > b ? a : b;
}
void voice_init(struct voice_t *voice, const struct engine_t *engine, double freq)
{
uint8_t i;
// filter_init_rc(&voice->fil[0], 1000.0, 0.000000047);
// filter_init_rc(&voice->fil[1], 47000.0, 0.000000047);
// filter_init_freq(&voice->fil[0], freq);
// filter_init_freq(&voice->fil[1], 150.0);
// bw_filter_init_lp(&voice->bw[0], _engine.lowpass.value, 1.0);
for (i = 0; i < VOICE_OSCILLATORS; i++) {
voice->osc[i].shape = engine->params[i].shape.value;
voice->osc[i].level = engine->params[i].level.value;
osc_setfreq(&voice->osc[i], freq * engine->params[i].freq_mult.value);
osc_setphase(&voice->osc[i], engine->params[i].phase.value);
}
}
static inline void voice_tick(struct voice_t *voice)
{
unsigned i;
for (i = 0; i < VOICE_OSCILLATORS; i++) {
osc_tick(voice->osc + i);
}
voice->sample++;
}
void voice_run(struct voice_t *voice, const struct engine_t *engine, uint32_t samples, float *left, float *right)
{
// uint32_t pos;
int i;
double a[VOICE_OSCILLATORS];
double l = 0.0;
double r = 0.0;
//for (pos = 0; pos < samples; pos++) {
voice_tick(voice);
double amplitude = 0.0;
for (i = 0; i < VOICE_OSCILLATORS; i++) {
a[i] = env_getamplitude(&engine->params[i].env, voice->sample, voice->released);
amplitude += a[i];
a[i] *= voice->velocity;
}
if (amplitude <= 0.0001) {
voice->playing = false;
return;
}
for (i = 0; i < VOICE_OSCILLATORS; i++) {
const struct voice_param_t *params = &engine->params[i];
float ss;
float pl = osc_getsample(&voice->osc[i]);
float pr = pl;
// Mix
switch (params->pan_type) {
case PAN_FIXED:
pl *= params->pan_level;
pr *= params->pan_level_r;
break;
case PAN_OSC:
ss = osc_getsample(&voice->osc[params->pan_source]) * params->pan_level * 0.5;
pl *= 0.5 + ss;
pr *= 0.5 - ss;
break;
case PAN_LFO:
ss = osc_getsample(&engine->lfo[params->pan_source]) * params->pan_level * 0.5;
pl *= 0.5 + ss;
pr *= 0.5 - ss;
break;
}
l += a[i] * pl;
r += a[i] * pr;
}
// Amplitude mod
// l *= 1.0 + s;
// r *= 1.0 + s;
// l = s * (1.0 + l);
// r = s * (1.0 + r);
// Ring mod
// l *= s;
// r *= s;
// amplitude = env_getamplitude(&_env2, voice->sample, voice->released) * voice->velocity * voice->velocity * 1.5;
// if (amplitude > 0.0) {
// float s1 = osc_getsample(&voice->osc[1]);
// float s2 = osc_getsample(&voice->osc[2]);
// l += amplitude * s1 * (1.0 + s2 * 0.25);
// r += amplitude * s1 * (1.0 + s2 * 0.25);
// }
// *left += l;
// *right += r;
double out_l, out_r;
double cutoff = max(env_getamplitude(&engine->cutoff_env, voice->sample, 0), engine->aftertouch.value) * 8000.0;
bw_filter_init_lp(&voice->bw[0], engine->lowpass.value + cutoff, 1.0);
bw_filter_run(&voice->bw[0], l, r, &out_l, &out_r);
// filter_run_lp(&voice->fil[0], l, r);
// filter_run_hp(&voice->fil[1], voice->fil[0].last_out_l, voice->fil[0].last_out_r);
*left += out_l;
*right += out_r;
// *left += voice->fil[0].last_out_l;
// *right += voice->fil[0].last_out_r;
// }
}