Oops, lots of changes
parent
a2f4261b7a
commit
2d4ffb346b
53
engine.c
53
engine.c
|
@ -6,11 +6,14 @@
|
||||||
#include "osc.h"
|
#include "osc.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "voice.h"
|
#include "voice.h"
|
||||||
|
#include "control.h"
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
#include "psyn.h"
|
#include "psyn.h"
|
||||||
|
|
||||||
static double _freqs[128];
|
static double _freqs[128];
|
||||||
|
|
||||||
|
struct engine_t _engine;
|
||||||
|
|
||||||
void engine_init()
|
void engine_init()
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
@ -21,7 +24,14 @@ void engine_init()
|
||||||
|
|
||||||
osc_init();
|
osc_init();
|
||||||
env_init(&_env, 0.0125, 0.025, 5.0, 0.0, 0.25);
|
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)
|
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;
|
uint32_t i;
|
||||||
|
|
||||||
for (pos = 0; pos < samples; pos++) {
|
for (pos = 0; pos < samples; pos++) {
|
||||||
|
control_tick(&_engine.lowpass);
|
||||||
|
|
||||||
left[pos] = 0.0;
|
left[pos] = 0.0;
|
||||||
right[pos] = 0.0;
|
right[pos] = 0.0;
|
||||||
|
|
||||||
for (i = 0; i < NUM_LFO; i++) {
|
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++) {
|
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
|
||||||
if (!v->playing) continue;
|
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;
|
struct voice_t *v = engine->voice;
|
||||||
uint32_t i;
|
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++) {
|
for (i = 0; i < NUM_POLYPHONY; i++, v++) {
|
||||||
if (v->playing) continue;
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
17
engine.h
17
engine.h
|
@ -4,11 +4,28 @@
|
||||||
|
|
||||||
struct engine_t
|
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 osc_t osc[NUM_LFO];
|
||||||
struct voice_t voice[NUM_POLYPHONY];
|
struct voice_t voice[NUM_POLYPHONY];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern struct engine_t _engine;
|
||||||
|
|
||||||
void engine_init();
|
void engine_init();
|
||||||
void engine_run(struct engine_t *engine, uint32_t samples, float *left, float *right);
|
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_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_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);
|
||||||
|
|
52
filter.c
52
filter.c
|
@ -1,15 +1,18 @@
|
||||||
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "psyn.h"
|
#include "psyn.h"
|
||||||
|
|
||||||
void filter_init_rc(struct filter_t *filter, double R, double C)
|
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->k = 1.0 / (R * C) / _sample_rate;
|
||||||
filter->r = 1.0;
|
filter->r = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter_init_freq(struct filter_t *filter, double freq)
|
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->k = (2.0 * M_PI * freq) / _sample_rate;
|
||||||
filter->r = 1.0;
|
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_l = left;
|
||||||
filter->last_in_r = right;
|
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;
|
||||||
|
*/
|
||||||
|
|
18
filter.h
18
filter.h
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
struct filter_t {
|
struct filter_t
|
||||||
|
{
|
||||||
double k;
|
double k;
|
||||||
double r;
|
double r;
|
||||||
double v_l;
|
double v_l;
|
||||||
|
@ -10,7 +11,22 @@ struct filter_t {
|
||||||
double last_out_r;
|
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_rc(struct filter_t *filter, double R, double C);
|
||||||
void filter_init_freq(struct filter_t *filter, double freq);
|
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_lp(struct filter_t *filter, double left, double right);
|
||||||
void filter_run_hp(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
33
osc.c
|
@ -3,24 +3,33 @@
|
||||||
#include "psyn.h"
|
#include "psyn.h"
|
||||||
#include "osc.h"
|
#include "osc.h"
|
||||||
|
|
||||||
double _sin_table[LOOKUP_SAMPLES + 1];
|
double _lookup_table[6][LOOKUP_SAMPLES + 1];
|
||||||
double _saw_table[LOOKUP_SAMPLES + 1];
|
|
||||||
double _tri_table[LOOKUP_SAMPLES + 1];
|
|
||||||
|
|
||||||
void osc_init()
|
void osc_init()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i <= LOOKUP_SAMPLES; i++) {
|
for (i = 0; i <= LOOKUP_SAMPLES; i++) {
|
||||||
_sin_table[i] = sin(2 * M_PI * (double)i / LOOKUP_SAMPLES);
|
double ph = (double)i / LOOKUP_SAMPLES;
|
||||||
}
|
|
||||||
for (i = 0; i <= LOOKUP_SAMPLES; i++) {
|
_lookup_table[0][i] = sin(2.0 * M_PI * ph);
|
||||||
_saw_table[i] = 1.0 - ((double)i / (LOOKUP_SAMPLES / 2));
|
|
||||||
}
|
_lookup_table[1][i] = -1.0 + ph * 2.0;
|
||||||
for (i = 0; i <= LOOKUP_SAMPLES; i++) {
|
|
||||||
_tri_table[i] = (double)i / (LOOKUP_SAMPLES / 4);
|
if (ph <= 0.25) _lookup_table[2][i] = ph * 4.0;
|
||||||
if (_tri_table[i] > 1.0) _tri_table[i] = 2.0 - _tri_table[i];
|
else if (ph <= 0.75) _lookup_table[2][i] = 2.0 - ph * 4.0;
|
||||||
if (_tri_table[i] < -1.0) _tri_table[i] = -2.0 - _tri_table[i];
|
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
40
osc.h
|
@ -1,32 +1,50 @@
|
||||||
|
|
||||||
#define LOOKUP_SAMPLES 360
|
#define LOOKUP_SAMPLES 3600
|
||||||
|
|
||||||
extern double _sin_table[LOOKUP_SAMPLES + 1];
|
extern double _lookup_table[6][LOOKUP_SAMPLES + 1];
|
||||||
extern double _saw_table[LOOKUP_SAMPLES + 1];
|
|
||||||
extern double _tri_table[LOOKUP_SAMPLES + 1];
|
|
||||||
|
|
||||||
struct osc_t
|
struct osc_t
|
||||||
{
|
{
|
||||||
double freq;
|
double freq;
|
||||||
double step;
|
double step;
|
||||||
double ramp;
|
double ramp;
|
||||||
|
double level;
|
||||||
|
|
||||||
double sin;
|
uint8_t shape;
|
||||||
double saw;
|
|
||||||
double tri;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void osc_init();
|
void osc_init();
|
||||||
void osc_setfreq(struct osc_t *osc, double freq);
|
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)
|
static inline void osc_tick(struct osc_t *osc)
|
||||||
{
|
{
|
||||||
osc->ramp += osc->step;
|
osc->ramp += osc->step;
|
||||||
if (osc->ramp > LOOKUP_SAMPLES) osc->ramp -= LOOKUP_SAMPLES;
|
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->sin = _sin_table[pos];
|
||||||
osc->saw = _saw_table[pos];
|
//osc->saw = _saw_table[pos];
|
||||||
osc->tri = _tri_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
55
psyn.c
|
@ -8,6 +8,7 @@
|
||||||
#include "osc.h"
|
#include "osc.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "voice.h"
|
#include "voice.h"
|
||||||
|
#include "control.h"
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
#include "psyn.h"
|
#include "psyn.h"
|
||||||
|
|
||||||
|
@ -20,8 +21,10 @@ struct psyn_t
|
||||||
int midi_event_id;
|
int midi_event_id;
|
||||||
float *out_l;
|
float *out_l;
|
||||||
float *out_r;
|
float *out_r;
|
||||||
|
float *ctrlMono;
|
||||||
struct engine_t eng;
|
float *ctrlLP;
|
||||||
|
float *ctrlOscShape[4];
|
||||||
|
float *ctrlOscLevel[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void psyn_init(struct psyn_t *psyn, uint32_t sample_rate)
|
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:
|
case 2:
|
||||||
psyn->out_r = data;
|
psyn->out_r = data;
|
||||||
break;
|
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)
|
static void run(LV2_Handle lv2instance, uint32_t sample_count)
|
||||||
{
|
{
|
||||||
|
uint8_t i;
|
||||||
struct psyn_t *psyn = (struct psyn_t *)lv2instance;
|
struct psyn_t *psyn = (struct psyn_t *)lv2instance;
|
||||||
uint32_t frame = 0;
|
uint32_t frame = 0;
|
||||||
LV2_Event *ev = NULL;
|
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);
|
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) {
|
while (frame < sample_count) {
|
||||||
uint32_t to;
|
uint32_t to;
|
||||||
|
|
||||||
|
@ -107,22 +130,42 @@ static void run(LV2_Handle lv2instance, uint32_t sample_count)
|
||||||
to = 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;
|
frame = to;
|
||||||
|
|
||||||
if (ev != NULL) {
|
if (ev != NULL) {
|
||||||
if (ev->type == 0) {
|
if (ev->type == 0) {
|
||||||
psyn->event_ref->lv2_event_unref(psyn->event_ref->callback_data, ev);
|
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);
|
uint8_t *data = (uint8_t *)(ev + 1);
|
||||||
|
|
||||||
switch (data[0] & 0xF0) {
|
switch (data[0] & 0xF0) {
|
||||||
case 0x80:
|
case 0x80:
|
||||||
engine_endvoice(&psyn->eng, data[1], data[2]);
|
engine_endvoice(&_engine, data[1], data[2]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x90:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
90
psyn.ttl
90
psyn.ttl
|
@ -34,4 +34,94 @@
|
||||||
lv2:index 2;
|
lv2:index 2;
|
||||||
lv2:symbol "out R";
|
lv2:symbol "out R";
|
||||||
lv2:name "Audio Output 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
77
voice.c
|
@ -6,19 +6,39 @@
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "voice.h"
|
#include "voice.h"
|
||||||
|
#include "control.h"
|
||||||
|
#include "engine.h"
|
||||||
#include "psyn.h"
|
#include "psyn.h"
|
||||||
#include "rng.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)
|
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[0], 1000.0, 0.000000047);
|
||||||
// filter_init_rc(&voice->fil[1], 47000.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[0], freq);
|
||||||
filter_init_freq(&voice->fil[1], 150.0);
|
// 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[0], freq);
|
||||||
osc_setfreq(&voice->osc[1], freq * 1.2);
|
osc_setphase(&voice->osc[0], 0.0);
|
||||||
osc_setfreq(&voice->osc[2], freq * 5);
|
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)
|
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;
|
amplitude *= voice->velocity;
|
||||||
|
|
||||||
l = amplitude * voice->osc[0].sin * (1.0 + rng() * 0.25);
|
float s;
|
||||||
r = amplitude * voice->osc[0].sin * (1.0 + rng() * 0.25);
|
|
||||||
|
s = osc_getsample(&voice->osc[0]);
|
||||||
|
l = amplitude * s;// * (1.0 + rng() * 0.25);
|
||||||
|
r = amplitude * s;// * (1.0 + rng() * 0.25);
|
||||||
|
|
||||||
amplitude = env_getamplitude(&_env2, voice->sample, voice->released) * voice->velocity * voice->velocity * 1.5;
|
s = osc_getsample(&voice->osc[1]);
|
||||||
|
l += amplitude * s;
|
||||||
|
r += amplitude * s;
|
||||||
|
|
||||||
if (amplitude > 0.0) {
|
s = osc_getsample(&voice->osc[2]);
|
||||||
l += amplitude * voice->osc[1].tri * (1.0 + voice->osc[2].sin * 0.25);
|
l += amplitude * s;
|
||||||
r += amplitude * voice->osc[1].tri * (1.0 + voice->osc[2].sin * 0.25);
|
r += amplitude * s;
|
||||||
}
|
|
||||||
|
|
||||||
*left += l;
|
s = osc_getsample(&_engine.osc[0]);
|
||||||
*right += r;
|
// 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_lp(&voice->fil[0], l, r);
|
||||||
// filter_run_hp(&voice->fil[1], voice->fil[0].last_out_l, voice->fil[0].last_out_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;
|
// *left += voice->fil[0].last_out_l;
|
||||||
// *right += voice->fil[0].last_out_r;
|
// *right += voice->fil[0].last_out_r;
|
||||||
// }
|
// }
|
||||||
|
|
3
voice.h
3
voice.h
|
@ -11,7 +11,8 @@ struct voice_t
|
||||||
double velocity;
|
double velocity;
|
||||||
struct osc_t osc[VOICE_OSCILLATORS];
|
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);
|
void voice_init(struct voice_t *voice, double freq);
|
||||||
|
|
Loading…
Reference in New Issue