summaryrefslogtreecommitdiff
path: root/libs/plugins/reasonablesynth.lv2/lv2.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/plugins/reasonablesynth.lv2/lv2.c')
-rw-r--r--libs/plugins/reasonablesynth.lv2/lv2.c214
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: */