|
|
|
@ -11,29 +11,25 @@
|
|
|
|
|
#include "engine.h"
|
|
|
|
|
#include "psyn.h"
|
|
|
|
|
|
|
|
|
|
static double _freqs[128];
|
|
|
|
|
|
|
|
|
|
struct engine_t _engine;
|
|
|
|
|
|
|
|
|
|
void engine_init()
|
|
|
|
|
void engine_init(struct engine_t *engine)
|
|
|
|
|
{
|
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 128; i++) {
|
|
|
|
|
_freqs[i] = 440.0 * pow(2.0, (i - 69.0) / 12.0);
|
|
|
|
|
engine->freqs[i] = 440.0 * pow(2.0, (i - 69.0) / 12.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
osc_init();
|
|
|
|
|
engine_load_program();
|
|
|
|
|
engine_load_program(engine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void engine_load_program()
|
|
|
|
|
void engine_load_program(struct engine_t *engine)
|
|
|
|
|
{
|
|
|
|
|
FILE *f = fopen("program.txt", "r");
|
|
|
|
|
|
|
|
|
|
while (!feof(f)) {
|
|
|
|
|
char buf[1024];
|
|
|
|
|
size_t l = fgets(buf, sizeof buf, f);
|
|
|
|
|
fgets(buf, sizeof buf, f);
|
|
|
|
|
|
|
|
|
|
if (!strncmp(buf, "voice", 5)) {
|
|
|
|
|
// Ignore voice
|
|
|
|
@ -42,8 +38,8 @@ void engine_load_program()
|
|
|
|
|
float freq;
|
|
|
|
|
int r = sscanf(buf, "lfo %d %f", &lfo, &freq);
|
|
|
|
|
if (r >= 2 && lfo >= 0 && lfo < NUM_LFO) {
|
|
|
|
|
osc_setfreq(&_engine.lfo[lfo], freq);
|
|
|
|
|
_engine.lfo[lfo].level = 1.0;
|
|
|
|
|
osc_setfreq(&engine->lfo[lfo], freq);
|
|
|
|
|
engine->lfo[lfo].level = 1.0;
|
|
|
|
|
}
|
|
|
|
|
} else if (!strncmp(buf, "osc", 3)) {
|
|
|
|
|
int osc;
|
|
|
|
@ -61,10 +57,10 @@ void engine_load_program()
|
|
|
|
|
else if (!strcmp(sshape, "MOOGSAW")) shape = OSC_MOOGSAW;
|
|
|
|
|
else if (!strcmp(sshape, "EXP")) shape = OSC_EXP;
|
|
|
|
|
|
|
|
|
|
_engine.params[osc].shape.value = shape;
|
|
|
|
|
_engine.params[osc].level.value = level;
|
|
|
|
|
_engine.params[osc].freq_mult.value = freq;
|
|
|
|
|
_engine.params[osc].phase.value = phase;
|
|
|
|
|
engine->params[osc].shape.value = shape;
|
|
|
|
|
engine->params[osc].level.value = level;
|
|
|
|
|
engine->params[osc].freq_mult.value = freq;
|
|
|
|
|
engine->params[osc].phase.value = phase;
|
|
|
|
|
}
|
|
|
|
|
} else if (!strncmp(buf, "pan", 3)) {
|
|
|
|
|
int pan;
|
|
|
|
@ -75,17 +71,17 @@ void engine_load_program()
|
|
|
|
|
if (r >= 4 && pan >= 0 && pan <= VOICE_OSCILLATORS) {
|
|
|
|
|
int source = 0;
|
|
|
|
|
if (!strcmp(ssource, "FIXED")) {
|
|
|
|
|
_engine.params[pan].pan_type = PAN_FIXED;
|
|
|
|
|
_engine.params[pan].pan_level = parm1;
|
|
|
|
|
_engine.params[pan].pan_level_r = parm2;
|
|
|
|
|
engine->params[pan].pan_type = PAN_FIXED;
|
|
|
|
|
engine->params[pan].pan_level = parm1;
|
|
|
|
|
engine->params[pan].pan_level_r = parm2;
|
|
|
|
|
} else if (!strcmp(ssource, "OSC")) {
|
|
|
|
|
_engine.params[pan].pan_type = PAN_OSC;
|
|
|
|
|
_engine.params[pan].pan_source = parm1;
|
|
|
|
|
_engine.params[pan].pan_level = parm2;
|
|
|
|
|
engine->params[pan].pan_type = PAN_OSC;
|
|
|
|
|
engine->params[pan].pan_source = parm1;
|
|
|
|
|
engine->params[pan].pan_level = parm2;
|
|
|
|
|
} else if (!strcmp(ssource, "LFO")) {
|
|
|
|
|
_engine.params[pan].pan_type = PAN_LFO;
|
|
|
|
|
_engine.params[pan].pan_source = parm1;
|
|
|
|
|
_engine.params[pan].pan_level = parm2;
|
|
|
|
|
engine->params[pan].pan_type = PAN_LFO;
|
|
|
|
|
engine->params[pan].pan_source = parm1;
|
|
|
|
|
engine->params[pan].pan_level = parm2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (!strncmp(buf, "env", 3)) {
|
|
|
|
@ -97,7 +93,7 @@ void engine_load_program()
|
|
|
|
|
float release;
|
|
|
|
|
int r = sscanf(buf, "env %d %f %f %f %f %f", &env, &attack, &hold, &decay, &sustain, &release);
|
|
|
|
|
if (r >= 6 && env >= 0 && env < VOICE_OSCILLATORS) {
|
|
|
|
|
env_init(&_engine.params[env].env, attack, hold, decay, sustain, release);
|
|
|
|
|
env_init(&engine->params[env].env, attack, hold, decay, sustain, release);
|
|
|
|
|
}
|
|
|
|
|
} else if (!strncmp(buf, "cutoff_env", 10)) {
|
|
|
|
|
int env;
|
|
|
|
@ -108,7 +104,7 @@ void engine_load_program()
|
|
|
|
|
float release;
|
|
|
|
|
int r = sscanf(buf, "cutoff_env %d %f %f %f %f %f", &env, &attack, &hold, &decay, &sustain, &release);
|
|
|
|
|
if (r >= 6 && env >= 0 && env < 1) {
|
|
|
|
|
env_init(&_engine.cutoff_env, attack, hold, decay, sustain, release);
|
|
|
|
|
env_init(&engine->cutoff_env, attack, hold, decay, sustain, release);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -122,20 +118,20 @@ void engine_run(struct engine_t *engine, uint32_t samples, float *left, float *r
|
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
|
|
for (pos = 0; pos < samples; pos++) {
|
|
|
|
|
control_tick(&_engine.lowpass);
|
|
|
|
|
control_tick(&engine->lowpass);
|
|
|
|
|
|
|
|
|
|
left[pos] = 0.0;
|
|
|
|
|
right[pos] = 0.0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_LFO; i++) {
|
|
|
|
|
osc_tick(&_engine.lfo[i]);
|
|
|
|
|
osc_tick(&engine->lfo[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v = _engine.voice;
|
|
|
|
|
v = engine->voice;
|
|
|
|
|
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
|
|
|
|
|
if (!v->playing) continue;
|
|
|
|
|
|
|
|
|
|
voice_run(v, 1, left + pos, right + pos);
|
|
|
|
|
voice_run(v, engine, 1, left + pos, right + pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -154,7 +150,7 @@ void engine_startvoice(struct engine_t *engine, uint8_t note, uint8_t velocity)
|
|
|
|
|
v->velocity = velocity / 127.0;
|
|
|
|
|
|
|
|
|
|
/* Voice parameters which determine sound */
|
|
|
|
|
voice_init(v, _freqs[note]);
|
|
|
|
|
voice_init(v, engine, engine->freqs[note]);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -169,7 +165,7 @@ void engine_startvoice(struct engine_t *engine, uint8_t note, uint8_t velocity)
|
|
|
|
|
v->velocity = velocity / 127.0;
|
|
|
|
|
|
|
|
|
|
/* Voice parameters which determine sound */
|
|
|
|
|
voice_init(v, _freqs[note]);
|
|
|
|
|
voice_init(v, engine, engine->freqs[note]);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|