You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
psyn/engine.c

206 lines
5.2 KiB

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "env.h"
#include "osc.h"
#include "filter.h"
#include "control.h"
#include "voice.h"
#include "engine.h"
#include "psyn.h"
void engine_init(struct engine_t *engine)
{
uint32_t i;
for (i = 0; i < 128; i++) {
engine->freqs[i] = 440.0 * pow(2.0, (i - 69.0) / 12.0);
}
osc_init();
engine_load_program(engine);
}
void engine_load_program(struct engine_t *engine)
{
FILE *f = fopen("program.txt", "r");
while (!feof(f)) {
char buf[1024];
fgets(buf, sizeof buf, f);
if (!strncmp(buf, "voice", 5)) {
// Ignore voice
} else if (!strncmp(buf, "lfo", 3)) {
int lfo;
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;
}
} else if (!strncmp(buf, "osc", 3)) {
int osc;
char sshape[1024];
float level;
float freq;
float phase;
int r = sscanf(buf, "osc %d %s %f %f %f", &osc, sshape, &level, &freq, &phase);
if (r >= 5 && osc >= 0 && osc < VOICE_OSCILLATORS) {
int shape = 0;
if (!strcmp(sshape, "SINE")) shape = OSC_SINE;
else if (!strcmp(sshape, "SAW")) shape = OSC_SAW;
else if (!strcmp(sshape, "TRIANGLE")) shape = OSC_TRIANGLE;
else if (!strcmp(sshape, "SQUARE")) shape = OSC_SQUARE;
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;
}
} else if (!strncmp(buf, "pan", 3)) {
int pan;
char ssource[1024];
float parm1;
float parm2;
int r = sscanf(buf, "pan %d %s %f %f", &pan, ssource, &parm1, &parm2);
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;
} else if (!strcmp(ssource, "OSC")) {
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;
}
}
} else if (!strncmp(buf, "env", 3)) {
int env;
float attack;
float hold;
float decay;
float sustain;
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);
}
} else if (!strncmp(buf, "cutoff_env", 10)) {
int env;
float attack;
float hold;
float decay;
float sustain;
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);
}
}
}
fclose(f);
}
void engine_run(struct engine_t *engine, uint32_t samples, float *left, float *right)
{
struct voice_t *v;
uint32_t pos;
uint32_t i;
for (pos = 0; pos < samples; pos++) {
control_tick(&engine->lowpass);
left[pos] = 0.0;
right[pos] = 0.0;
for (i = 0; i < NUM_LFO; i++) {
osc_tick(&engine->lfo[i]);
}
v = engine->voice;
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
if (!v->playing) continue;
voice_run(v, engine, 1, left + pos, right + pos);
}
}
}
void engine_startvoice(struct engine_t *engine, uint8_t note, uint8_t velocity)
{
struct voice_t *v = engine->voice;
uint32_t i;
if (engine->monosynth > 0) {
/* Constant voice parameters */
v->playing = true;
if (v->released || engine->monosynth == 1) v->sample = 0;
v->released = 0;
v->note = note;
v->velocity = velocity / 127.0;
/* Voice parameters which determine sound */
voice_init(v, engine, engine->freqs[note]);
return;
}
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
if (v->playing) continue;
/* Constant voice parameters */
v->playing = true;
v->sample = 0;
v->released = 0;
v->note = note;
v->velocity = velocity / 127.0;
/* Voice parameters which determine sound */
voice_init(v, engine, engine->freqs[note]);
return;
}
}
void engine_endvoice(struct engine_t *engine, uint8_t note, uint8_t velocity)
{
struct voice_t *v = engine->voice;
uint32_t i;
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
if (v->released > 0 || v->note != note) continue;
v->released = v->sample;
}
}
void engine_controlchange(struct engine_t *engine, uint8_t controller, uint8_t value)
{
printf("Control change %u -> %u\n", controller, value);
}
void engine_programchange(struct engine_t *engine, uint8_t value)
{
printf("Program change %u\n", value);
}
void engine_aftertouch(struct engine_t *engine, uint8_t value)
{
// printf("Aftertouch %u\n", value);
engine->aftertouch.value = value / 127.0;
}
void engine_pitchchange(struct engine_t *engine, int16_t value)
{
printf("Pitch %d\n", value);
engine->pitchbend.value = value;
}