#include #include #include #include #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]; }; static void psyn_init(struct psyn_t *psyn, uint32_t sample_rate) { _sample_rate = sample_rate; engine_init(); } 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; 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 = "http://fuzzle.org/~petern/psyn/1", .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; }