diff options
Diffstat (limited to 'libs/plugins/reasonablesynth.lv2/lv2.c')
-rw-r--r-- | libs/plugins/reasonablesynth.lv2/lv2.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/libs/plugins/reasonablesynth.lv2/lv2.c b/libs/plugins/reasonablesynth.lv2/lv2.c new file mode 100644 index 0000000000..6b9c81d8dd --- /dev/null +++ b/libs/plugins/reasonablesynth.lv2/lv2.c @@ -0,0 +1,214 @@ +/* reasonable simple synth + * + * Copyright (C) 2013 Robin Gareus <robin@gareus.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <time.h> + +/* LV2 */ +#include "lv2/lv2plug.in/ns/lv2core/lv2.h" +#include "lv2/lv2plug.in/ns/ext/atom/atom.h" +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" +#include "lv2/lv2plug.in/ns/ext/midi/midi.h" + +#define RSY_URI "https://community.ardour.org/node/7596" + +/* the synth interface */ +static void * synth_alloc (void); +static void synth_init (void *, double rate); +static void synth_free (void *); +static void synth_parse_midi (void *, const uint8_t *data, const size_t size); +static uint32_t synth_sound (void *, uint32_t written, uint32_t nframes, float **out); + +#include "rsynth.c" + +typedef enum { + RSY_MIDIIN = 0, + RSY_OUTL, + RSY_OUTR +} PortIndex; + +typedef struct { + const LV2_Atom_Sequence* midiin; + float* outL; + float* outR; + + LV2_URID_Map* map; + LV2_URID midi_MidiEvent; + + double SampleRateD; + void *synth; + bool xmas; +} RSynth; + +/* main LV2 */ + +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, + double rate, + const char* bundle_path, + const LV2_Feature* const* features) +{ + (void) descriptor; /* unused variable */ + (void) bundle_path; /* unused variable */ + + if (rate < 8000) { + fprintf(stderr, "RSynth.lv2 error: unsupported sample-rate (must be > 8k)\n"); + return NULL; + } + RSynth* self = (RSynth*)calloc(1, sizeof(RSynth)); + if(!self) { + return NULL; + } + + self->SampleRateD = rate; + + int i; + for (i=0; features[i]; ++i) { + if (!strcmp(features[i]->URI, LV2_URID__map)) { + self->map = (LV2_URID_Map*)features[i]->data; + } + } + + if (!self->map) { + fprintf(stderr, "RSynth.lv2 error: Host does not support urid:map\n"); + free(self); + return NULL; + } + + self->midi_MidiEvent = self->map->map(self->map->handle, LV2_MIDI__MidiEvent); + + self->synth = synth_alloc(); + synth_init(self->synth, rate); + + + struct tm date; + time_t now; + time(&now); + localtime_r(&now, &date); + if (getenv("ITSXMAS") || (date.tm_mon == 11 /*dec*/ && date.tm_mday == 25)) { + printf("reasonable synth.lv2 says: happy holidays!\n"); + self->xmas = true; + } + + return (LV2_Handle)self; +} + +static void +connect_port(LV2_Handle handle, + uint32_t port, + void* data) +{ + RSynth* self = (RSynth*)handle; + + switch ((PortIndex)port) { + case RSY_MIDIIN: + self->midiin = (const LV2_Atom_Sequence*)data; + break; + case RSY_OUTL: + self->outL = (float*)data; + break; + case RSY_OUTR: + self->outR = (float*)data; + break; + } +} + +static void +run(LV2_Handle handle, uint32_t n_samples) +{ + RSynth* self = (RSynth*)handle; + float* audio[2]; + + audio[0] = self->outL; + audio[1] = self->outR; + + uint32_t written = 0; + + /* Process incoming MIDI events */ + if (self->midiin) { + LV2_Atom_Event const* ev = (LV2_Atom_Event const*)((&(self->midiin)->body) + 1); // lv2_atom_sequence_begin + while( // !lv2_atom_sequence_is_end + (const uint8_t*)ev < ((const uint8_t*) &(self->midiin)->body + (self->midiin)->atom.size) + ) + { + if (ev->body.type == self->midi_MidiEvent) { + if (written + BUFFER_SIZE_SAMPLES < ev->time.frames + && ev->time.frames < n_samples) { + /* first synthesize sound up until the message timestamp */ + written = synth_sound(self->synth, written, ev->time.frames, audio); + } + /* send midi message to synth */ + if (self->xmas) { + synth_parse_xmas(self->synth, (const uint8_t*)(ev+1), ev->body.size); + } else { + synth_parse_midi(self->synth, (const uint8_t*)(ev+1), ev->body.size); + } + } + ev = (LV2_Atom_Event const*) // lv2_atom_sequence_next() + ((const uint8_t*)ev + sizeof(LV2_Atom_Event) + ((ev->body.size + 7) & ~7)); + } + } + + /* synthesize [remaining] sound */ + synth_sound(self->synth, written, n_samples, audio); +} + +static void +cleanup(LV2_Handle handle) +{ + RSynth* self = (RSynth*)handle; + synth_free(self->synth); + free(handle); +} + +static const void* +extension_data(const char* uri) +{ + (void) uri; /* unused variable */ + return NULL; +} + +static const LV2_Descriptor descriptor = { + RSY_URI, + instantiate, + connect_port, + NULL, + run, + NULL, + cleanup, + extension_data +}; + +LV2_SYMBOL_EXPORT +const LV2_Descriptor* +lv2_descriptor(uint32_t idx) +{ + switch (idx) { + case 0: + return &descriptor; + default: + return NULL; + } +} + +/* vi:set ts=8 sts=2 sw=2 et: */ |