Oops, lots of changes

master
Peter Nelson 2010-01-20 07:49:38 +00:00
parent a2f4261b7a
commit 2d4ffb346b
10 changed files with 391 additions and 47 deletions

View File

@ -6,11 +6,14 @@
#include "osc.h"
#include "filter.h"
#include "voice.h"
#include "control.h"
#include "engine.h"
#include "psyn.h"
static double _freqs[128];
struct engine_t _engine;
void engine_init()
{
uint32_t i;
@ -21,7 +24,14 @@ void engine_init()
osc_init();
env_init(&_env, 0.0125, 0.025, 5.0, 0.0, 0.25);
env_init(&_env2, 0.0125, 0.025, 0.5, 0.0, 0.25);
env_init(&_env2, 0.0, 0.0, 0.5, 0.0, 0.25);
osc_setfreq(&_engine.osc[0], 10.0);
osc_setfreq(&_engine.osc[1], 2.0);
osc_setfreq(&_engine.osc[2], 1.0);
_engine.osc[0].level = 1.0;
_engine.osc[1].level = 1.0;
_engine.osc[2].level = 1.0;
}
void engine_run(struct engine_t *engine, uint32_t samples, float *left, float *right)
@ -31,14 +41,16 @@ 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);
left[pos] = 0.0;
right[pos] = 0.0;
for (i = 0; i < NUM_LFO; i++) {
osc_tick(&engine->osc[i]);
osc_tick(&_engine.osc[i]);
}
v = engine->voice;
v = _engine.voice;
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
if (!v->playing) continue;
@ -52,6 +64,19 @@ 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, _freqs[note]);
return;
}
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
if (v->playing) continue;
@ -80,3 +105,25 @@ void engine_endvoice(struct engine_t *engine, uint8_t note, uint8_t velocity)
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;
}

View File

@ -4,11 +4,28 @@
struct engine_t
{
struct control_t lowpass;
struct control_t modwheel;
struct control_t pitchbend;
struct control_t aftertouch;
struct control_t osc_shape[4];
struct control_t osc_level[4];
int monosynth;
struct osc_t osc[NUM_LFO];
struct voice_t voice[NUM_POLYPHONY];
};
extern struct engine_t _engine;
void engine_init();
void engine_run(struct engine_t *engine, uint32_t samples, float *left, float *right);
void engine_startvoice(struct engine_t *engine, uint8_t note, uint8_t velocity);
void engine_endvoice(struct engine_t *engine, uint8_t note, uint8_t velocity);
void engine_controlchange(struct engine_t *engine, uint8_t controller, uint8_t value);
void engine_programchange(struct engine_t *engine, uint8_t value);
void engine_aftertouch(struct engine_t *engine, uint8_t value);
void engine_pitchchange(struct engine_t *engine, int16_t value);

View File

@ -1,15 +1,18 @@
#include <string.h>
#include <math.h>
#include "filter.h"
#include "psyn.h"
void filter_init_rc(struct filter_t *filter, double R, double C)
{
memset(filter, 0, sizeof *filter);
filter->k = 1.0 / (R * C) / _sample_rate;
filter->r = 1.0;
}
void filter_init_freq(struct filter_t *filter, double freq)
{
memset(filter, 0, sizeof *filter);
filter->k = (2.0 * M_PI * freq) / _sample_rate;
filter->r = 1.0;
}
@ -31,3 +34,52 @@ void filter_run_hp(struct filter_t *filter, double left, double right)
filter->last_in_l = left;
filter->last_in_r = right;
}
void bw_filter_init_lp(struct bw_filter_t *f, double freq, double resonance)
{
double c = 1.0 / tan(M_PI * freq / _sample_rate);
f->a1 = 1.0 / (1.0 + resonance * c + c * c);
f->a2 = 2 * f->a1;
f->a3 = f->a1;
f->b1 = 2.0 * (1.0 - c * c) * f->a1;
f->b2 = (1.0 - resonance * c + c * c) * f->a1;
}
void bw_filter_run(struct bw_filter_t *f, double in_l, double in_r, double *out_l, double *out_r)
{
*out_l = f->a1 * in_l + f->a2 * f->in1_l + f->a3 * f->in2_l - f->b1 * f->out1_l - f->b2 * f->out2_l;
*out_r = f->a1 * in_r + f->a2 * f->in1_r + f->a3 * f->in2_r - f->b1 * f->out1_r - f->b2 * f->out2_r;
f->in2_l = f->in1_l;
f->in1_l = in_l;
f->out2_l = f->out1_l;
f->out1_l = *out_l;
f->in2_r = f->in1_r;
f->in1_r = in_r;
f->out2_r = f->out1_r;
f->out1_r = *out_r;
}
/*
The filter algo:
out(n) = a1 * in + a2 * in(n-1) + a3 * in(n-2) - b1*out(n-1) - b2*out(n-2)
Lowpass:
c = 1.0 / tan(pi * f / sample_rate);
a1 = 1.0 / ( 1.0 + r * c + c * c);
a2 = 2* a1;
a3 = a1;
b1 = 2.0 * ( 1.0 - c*c) * a1;
b2 = ( 1.0 - r * c + c * c) * a1;
Hipass:
c = tan(pi * f / sample_rate);
a1 = 1.0 / ( 1.0 + r * c + c * c);
a2 = -2*a1;
a3 = a1;
b1 = 2.0 * ( c*c - 1.0) * a1;
b2 = ( 1.0 - r * c + c * c) * a1;
*/

View File

@ -1,5 +1,6 @@
struct filter_t {
struct filter_t
{
double k;
double r;
double v_l;
@ -10,7 +11,22 @@ struct filter_t {
double last_out_r;
};
struct bw_filter_t
{
double a1;
double a2;
double a3;
double b1;
double b2;
double in1_l, in2_l, out1_l, out2_l;
double in1_r, in2_r, out1_r, out2_r;
};
void filter_init_rc(struct filter_t *filter, double R, double C);
void filter_init_freq(struct filter_t *filter, double freq);
void filter_run_lp(struct filter_t *filter, double left, double right);
void filter_run_hp(struct filter_t *filter, double left, double right);
void bw_filter_init_lp(struct bw_filter_t *f, double freq, double resonance);
void bw_filter_run(struct bw_filter_t *f, double in_l, double in_r, double *out_l, double *out_r);

33
osc.c
View File

@ -3,24 +3,33 @@
#include "psyn.h"
#include "osc.h"
double _sin_table[LOOKUP_SAMPLES + 1];
double _saw_table[LOOKUP_SAMPLES + 1];
double _tri_table[LOOKUP_SAMPLES + 1];
double _lookup_table[6][LOOKUP_SAMPLES + 1];
void osc_init()
{
int i;
for (i = 0; i <= LOOKUP_SAMPLES; i++) {
_sin_table[i] = sin(2 * M_PI * (double)i / LOOKUP_SAMPLES);
}
for (i = 0; i <= LOOKUP_SAMPLES; i++) {
_saw_table[i] = 1.0 - ((double)i / (LOOKUP_SAMPLES / 2));
}
for (i = 0; i <= LOOKUP_SAMPLES; i++) {
_tri_table[i] = (double)i / (LOOKUP_SAMPLES / 4);
if (_tri_table[i] > 1.0) _tri_table[i] = 2.0 - _tri_table[i];
if (_tri_table[i] < -1.0) _tri_table[i] = -2.0 - _tri_table[i];
double ph = (double)i / LOOKUP_SAMPLES;
_lookup_table[0][i] = sin(2.0 * M_PI * ph);
_lookup_table[1][i] = -1.0 + ph * 2.0;
if (ph <= 0.25) _lookup_table[2][i] = ph * 4.0;
else if (ph <= 0.75) _lookup_table[2][i] = 2.0 - ph * 4.0;
else _lookup_table[2][i] = ph * 4.0 - 4.0;
//if (_tri_table[i] > 1.0) _tri_table[i] = 2.0 - _tri_table[i];
//if (_tri_table[i] < -1.0) _tri_table[i] = -2.0 - _tri_table[i];
_lookup_table[3][i] = (ph >= 0.5) ? -1.0 : 1.0;
if (ph < 0.5) _lookup_table[4][i] = -1.0 + ph * 4.0;
else _lookup_table[4][i] = 1.0 - 2.0 * ph;
if (ph > 0.5) _lookup_table[5][i] = 1.0 - ph;
else _lookup_table[5][i] = -1.0 + 8.0 * ph * ph;
}
}

40
osc.h
View File

@ -1,32 +1,50 @@
#define LOOKUP_SAMPLES 360
#define LOOKUP_SAMPLES 3600
extern double _sin_table[LOOKUP_SAMPLES + 1];
extern double _saw_table[LOOKUP_SAMPLES + 1];
extern double _tri_table[LOOKUP_SAMPLES + 1];
extern double _lookup_table[6][LOOKUP_SAMPLES + 1];
struct osc_t
{
double freq;
double step;
double ramp;
double level;
double sin;
double saw;
double tri;
uint8_t shape;
};
void osc_init();
void osc_setfreq(struct osc_t *osc, double freq);
static inline void osc_setphase(struct osc_t *osc, double phase)
{
osc->ramp = LOOKUP_SAMPLES * phase;
}
static inline void osc_tick(struct osc_t *osc)
{
osc->ramp += osc->step;
if (osc->ramp > LOOKUP_SAMPLES) osc->ramp -= LOOKUP_SAMPLES;
uint32_t pos = floor(osc->ramp);
//uint32_t pos = floor(osc->ramp);
osc->sin = _sin_table[pos];
osc->saw = _saw_table[pos];
osc->tri = _tri_table[pos];
//osc->sin = _sin_table[pos];
//osc->saw = _saw_table[pos];
//osc->tri = _tri_table[pos];
}
static inline double osc_getsample(struct osc_t *osc)
{
uint32_t pos = osc->ramp;
return _lookup_table[osc->shape][pos] * osc->level;
}
static inline double osc_getsamplewithphase(struct osc_t *osc, float phase)
{
double sample = osc->ramp + phase * LOOKUP_SAMPLES;
if (sample < 0.0) sample += LOOKUP_SAMPLES;
else if (sample > LOOKUP_SAMPLES) sample -= LOOKUP_SAMPLES;
uint32_t pos = sample;
return _lookup_table[osc->shape][pos] * osc->level;
}

55
psyn.c
View File

@ -8,6 +8,7 @@
#include "osc.h"
#include "filter.h"
#include "voice.h"
#include "control.h"
#include "engine.h"
#include "psyn.h"
@ -20,8 +21,10 @@ struct psyn_t
int midi_event_id;
float *out_l;
float *out_r;
struct engine_t eng;
float *ctrlMono;
float *ctrlLP;
float *ctrlOscShape[4];
float *ctrlOscLevel[4];
};
static void psyn_init(struct psyn_t *psyn, uint32_t sample_rate)
@ -78,6 +81,18 @@ static void connect_port(LV2_Handle lv2instance, uint32_t port, void *data)
case 2:
psyn->out_r = data;
break;
case 3:
psyn->ctrlMono = data;
break;
case 4:
psyn->ctrlLP = data;
break;
case 5: case 6: case 7: case 8:
psyn->ctrlOscShape[port - 5] = data;
break;
case 9: case 10: case 11: case 12:
psyn->ctrlOscLevel[port - 9] = data;
break;
}
}
@ -89,6 +104,7 @@ static void cleanup(LV2_Handle lv2instance)
static void run(LV2_Handle lv2instance, uint32_t sample_count)
{
uint8_t i;
struct psyn_t *psyn = (struct psyn_t *)lv2instance;
uint32_t frame = 0;
LV2_Event *ev = NULL;
@ -98,6 +114,13 @@ static void run(LV2_Handle lv2instance, uint32_t sample_count)
if (lv2_event_is_valid(&iterator)) ev = lv2_event_get(&iterator, NULL);
control_setstep(&_engine.lowpass, *psyn->ctrlLP, sample_count);
_engine.monosynth = (int)*psyn->ctrlMono;
for (i = 0; i < 4; i++) {
_engine.osc_shape[i].value = *psyn->ctrlOscShape[i];
_engine.osc_level[i].value = *psyn->ctrlOscLevel[i];
}
while (frame < sample_count) {
uint32_t to;
@ -107,22 +130,42 @@ static void run(LV2_Handle lv2instance, uint32_t sample_count)
to = sample_count;
}
engine_run(&psyn->eng, to - frame, psyn->out_l + frame, psyn->out_r + frame);
engine_run(&_engine, to - frame, psyn->out_l + frame, psyn->out_r + frame);
frame = to;
if (ev != NULL) {
if (ev->type == 0) {
psyn->event_ref->lv2_event_unref(psyn->event_ref->callback_data, ev);
} else if (ev->type == psyn->midi_event_id && ev->size == 3) {
} else if (ev->type == psyn->midi_event_id) {
uint8_t *data = (uint8_t *)(ev + 1);
switch (data[0] & 0xF0) {
case 0x80:
engine_endvoice(&psyn->eng, data[1], data[2]);
engine_endvoice(&_engine, data[1], data[2]);
break;
case 0x90:
engine_startvoice(&psyn->eng, data[1], data[2]);
engine_startvoice(&_engine, data[1], data[2]);
break;
case 0xA0:
engine_aftertouch(&_engine, data[2]);
break;
case 0xC0:
engine_programchange(&_engine, data[1]);
break;
case 0xB0:
engine_controlchange(&_engine, data[1], data[2]);
break;
case 0xD0:
engine_aftertouch(&_engine, data[1]);
break;
case 0xE0:
engine_pitchchange(&_engine, (data[1] | data[2] << 7) - 0x2000);
break;
}
}

View File

@ -34,4 +34,94 @@
lv2:index 2;
lv2:symbol "out R";
lv2:name "Audio Output R";
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 3;
lv2:symbol "mono";
lv2:name "Mono mode";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 2;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 4;
lv2:symbol "lp_freq";
lv2:name "Low Pass Filter Frequency";
lv2:minimum 1.0;
lv2:default 2000.0;
lv2:maximum 16000.0;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 5;
lv2:symbol "oscshape0";
lv2:name "Oscillator 0 shape";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 5;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 6;
lv2:symbol "oscshape1";
lv2:name "Oscillator 1 shape";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 5;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 7;
lv2:symbol "oscshape2";
lv2:name "Oscillator 2 shape";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 5;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 8;
lv2:symbol "oscshape3";
lv2:name "Oscillator 3 shape";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 5;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 9;
lv2:symbol "osclevel0";
lv2:name "Oscillator 0 level";
lv2:minimum 0;
lv2:default 1;
lv2:maximum 1;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 10;
lv2:symbol "osclevel1";
lv2:name "Oscillator 1 level";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 1;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 11;
lv2:symbol "osclevel2";
lv2:name "Oscillator 2 level";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 1;
],
[
a lv2:InputPort, lv2:ControlPort;
lv2:index 12;
lv2:symbol "osclevel3";
lv2:name "Oscillator 3 level";
lv2:minimum 0;
lv2:default 0;
lv2:maximum 1;
].

77
voice.c
View File

@ -6,19 +6,39 @@
#include "env.h"
#include "filter.h"
#include "voice.h"
#include "control.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, 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], 2000.0);
filter_init_freq(&voice->fil[1], 150.0);
// 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.osc_shape[i].value;
voice->osc[i].level = _engine.osc_level[i].value;
}
osc_setfreq(&voice->osc[0], freq);
osc_setfreq(&voice->osc[1], freq * 1.2);
osc_setfreq(&voice->osc[2], freq * 5);
osc_setphase(&voice->osc[0], 0.0);
osc_setfreq(&voice->osc[1], freq);// * 1.4983);
osc_setphase(&voice->osc[1], 0.25);
osc_setfreq(&voice->osc[2], freq * 2);
osc_setphase(&voice->osc[2], 0.0);
osc_setfreq(&voice->osc[3], 2500.0);
osc_setphase(&voice->osc[3], 0.0);
}
static inline void voice_tick(struct voice_t *voice)
@ -50,22 +70,53 @@ void voice_run(struct voice_t *voice, uint32_t samples, float *left, float *righ
amplitude *= voice->velocity;
l = amplitude * voice->osc[0].sin * (1.0 + rng() * 0.25);
r = amplitude * voice->osc[0].sin * (1.0 + rng() * 0.25);
float s;
amplitude = env_getamplitude(&_env2, voice->sample, voice->released) * voice->velocity * voice->velocity * 1.5;
s = osc_getsample(&voice->osc[0]);
l = amplitude * s;// * (1.0 + rng() * 0.25);
r = amplitude * s;// * (1.0 + rng() * 0.25);
if (amplitude > 0.0) {
l += amplitude * voice->osc[1].tri * (1.0 + voice->osc[2].sin * 0.25);
r += amplitude * voice->osc[1].tri * (1.0 + voice->osc[2].sin * 0.25);
}
s = osc_getsample(&voice->osc[1]);
l += amplitude * s;
r += amplitude * s;
*left += l;
*right += r;
s = osc_getsample(&voice->osc[2]);
l += amplitude * s;
r += amplitude * s;
s = osc_getsample(&_engine.osc[0]);
// 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(&_env2, 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;
// }

View File

@ -11,7 +11,8 @@ struct voice_t
double velocity;
struct osc_t osc[VOICE_OSCILLATORS];
struct filter_t fil[VOICE_FILTERS];
//struct filter_t fil[VOICE_FILTERS];
struct bw_filter_t bw[VOICE_FILTERS];
};
void voice_init(struct voice_t *voice, double freq);