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.
204 lines
4.3 KiB
204 lines
4.3 KiB
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <lv2.h>
|
|
#include "lv2_event.h"
|
|
#include "lv2_event_helpers.h"
|
|
#include "lv2_uri_map.h"
|
|
#include "osc.h"
|
|
#include "filter.h"
|
|
#include "env.h"
|
|
#include "control.h"
|
|
#include "voice.h"
|
|
#include "engine.h"
|
|
#include "psyn.h"
|
|
|
|
double _sample_rate;
|
|
|
|
struct psyn_t
|
|
{
|
|
LV2_Event_Buffer *events;
|
|
LV2_Event_Feature *event_ref;
|
|
int midi_event_id;
|
|
float *out_l;
|
|
float *out_r;
|
|
float *ctrlMono;
|
|
float *ctrlLP;
|
|
float *ctrlOscShape[4];
|
|
float *ctrlOscLevel[4];
|
|
|
|
struct engine_t engine;
|
|
};
|
|
|
|
static void psyn_init(struct psyn_t *psyn, uint32_t sample_rate)
|
|
{
|
|
_sample_rate = sample_rate;
|
|
|
|
engine_init(&psyn->engine);
|
|
}
|
|
|
|
static LV2_Handle instantiate(
|
|
const LV2_Descriptor *descriptor,
|
|
double sample_rate,
|
|
const char *bundle_path,
|
|
const LV2_Feature * const *host_features)
|
|
{
|
|
struct psyn_t *psyn;
|
|
LV2_URI_Map_Feature *map_feature;
|
|
int i;
|
|
|
|
psyn = malloc(sizeof *psyn);
|
|
memset(psyn, 0, sizeof *psyn);
|
|
|
|
psyn_init(psyn, sample_rate);
|
|
|
|
for (i = 0; host_features[i]; i++) {
|
|
if (!strcmp(host_features[i]->URI, "http://lv2plug.in/ns/ext/uri-map")) {
|
|
map_feature = host_features[i]->data;
|
|
|
|
psyn->midi_event_id = map_feature->uri_to_id(map_feature->callback_data, "http://lv2plug.in/ns/ext/event", "http://lv2plug.in/ns/ext/midi#MidiEvent");
|
|
} else if (!strcmp(host_features[i]->URI, "http://lv2plug.in/ns/ext/event")) {
|
|
psyn->event_ref = host_features[i]->data;
|
|
}
|
|
}
|
|
|
|
if (psyn->midi_event_id == 0 || psyn->event_ref == NULL) {
|
|
printf("psyn instantiate failed, leaving\n");
|
|
return NULL;
|
|
}
|
|
|
|
return (LV2_Handle)psyn;
|
|
}
|
|
|
|
static void connect_port(LV2_Handle lv2instance, uint32_t port, void *data)
|
|
{
|
|
struct psyn_t *psyn = (struct psyn_t *)lv2instance;
|
|
|
|
switch (port) {
|
|
case 0:
|
|
psyn->events = data;
|
|
break;
|
|
case 1:
|
|
psyn->out_l = data;
|
|
break;
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void cleanup(LV2_Handle lv2instance)
|
|
{
|
|
struct psyn_t *psyn = (struct psyn_t *)lv2instance;
|
|
free(psyn);
|
|
}
|
|
|
|
static void run(LV2_Handle lv2instance, uint32_t sample_count)
|
|
{
|
|
uint8_t i;
|
|
struct psyn_t *psyn = (struct psyn_t *)lv2instance;
|
|
struct engine_t *engine = &psyn->engine;
|
|
uint32_t frame = 0;
|
|
LV2_Event *ev = NULL;
|
|
LV2_Event_Iterator iterator;
|
|
|
|
lv2_event_begin(&iterator, psyn->events);
|
|
|
|
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.params[i].shape.value = *psyn->ctrlOscShape[i];
|
|
// _engine.params[i].level.value = *psyn->ctrlOscLevel[i];
|
|
// }
|
|
|
|
while (frame < sample_count) {
|
|
uint32_t to;
|
|
|
|
if (ev != NULL) {
|
|
to = ev->frames;
|
|
} else {
|
|
to = sample_count;
|
|
}
|
|
|
|
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) {
|
|
uint8_t *data = (uint8_t *)(ev + 1);
|
|
|
|
switch (data[0] & 0xF0) {
|
|
case 0x80:
|
|
engine_endvoice(engine, data[1], data[2]);
|
|
break;
|
|
|
|
case 0x90:
|
|
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;
|
|
}
|
|
}
|
|
|
|
lv2_event_increment(&iterator);
|
|
if (lv2_event_is_valid(&iterator)) {
|
|
ev = lv2_event_get(&iterator, NULL);
|
|
} else {
|
|
ev = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static LV2_Descriptor g_lv2descriptor =
|
|
{
|
|
.URI = "urn:fuzzle:psyn",
|
|
.instantiate = &instantiate,
|
|
.connect_port = &connect_port,
|
|
.run = &run,
|
|
.cleanup = &cleanup,
|
|
};
|
|
|
|
const LV2_Descriptor *lv2_descriptor(uint32_t index)
|
|
{
|
|
if (index == 0) {
|
|
return &g_lv2descriptor;
|
|
}
|
|
|
|
return NULL;
|
|
}
|