1 /*
2 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _GNU_SOURCE
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <time.h>
25
26 /* LV2 */
27 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
28 #include "lv2/lv2plug.in/ns/ext/atom/atom.h"
29 #include "lv2/lv2plug.in/ns/ext/urid/urid.h"
30 #include "lv2/lv2plug.in/ns/ext/midi/midi.h"
31
32 #define RSY_URI "https://community.ardour.org/node/7596"
33
34 /* the synth interface */
35 static void * synth_alloc (void);
36 static void synth_init (void *, double rate);
37 static void synth_free (void *);
38 static void synth_parse_midi (void *, const uint8_t *data, const size_t size);
39 static uint32_t synth_sound (void *, uint32_t written, uint32_t nframes, float **out);
40
41 #include "rsynth.c"
42
43 typedef enum {
44 RSY_MIDIIN = 0,
45 RSY_OUTL,
46 RSY_OUTR
47 } PortIndex;
48
49 typedef struct {
50 const LV2_Atom_Sequence* midiin;
51 float* outL;
52 float* outR;
53
54 LV2_URID_Map* map;
55 LV2_URID midi_MidiEvent;
56
57 double SampleRateD;
58 void *synth;
59 bool xmas;
60 } RSynth;
61
62 /* main LV2 */
63
64 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)65 instantiate (const LV2_Descriptor* descriptor,
66 double rate,
67 const char* bundle_path,
68 const LV2_Feature* const* features)
69 {
70 (void) descriptor; /* unused variable */
71 (void) bundle_path; /* unused variable */
72
73 if (rate < 8000) {
74 fprintf(stderr, "RSynth.lv2 error: unsupported sample-rate (must be > 8k)\n");
75 return NULL;
76 }
77 RSynth* self = (RSynth*)calloc(1, sizeof(RSynth));
78 if(!self) {
79 return NULL;
80 }
81
82 self->SampleRateD = rate;
83
84 int i;
85 for (i=0; features[i]; ++i) {
86 if (!strcmp(features[i]->URI, LV2_URID__map)) {
87 self->map = (LV2_URID_Map*)features[i]->data;
88 }
89 }
90
91 if (!self->map) {
92 fprintf(stderr, "RSynth.lv2 error: Host does not support urid:map\n");
93 free(self);
94 return NULL;
95 }
96
97 self->midi_MidiEvent = self->map->map(self->map->handle, LV2_MIDI__MidiEvent);
98
99 self->synth = synth_alloc();
100 synth_init(self->synth, rate);
101
102 if (getenv("ITSXMAS")) {
103 printf("reasonable synth.lv2 says: happy holidays!\n");
104 self->xmas = true;
105 }
106
107 return (LV2_Handle)self;
108 }
109
110 static void
connect_port(LV2_Handle handle,uint32_t port,void * data)111 connect_port (LV2_Handle handle,
112 uint32_t port,
113 void* data)
114 {
115 RSynth* self = (RSynth*)handle;
116
117 switch ((PortIndex)port) {
118 case RSY_MIDIIN:
119 self->midiin = (const LV2_Atom_Sequence*)data;
120 break;
121 case RSY_OUTL:
122 self->outL = (float*)data;
123 break;
124 case RSY_OUTR:
125 self->outR = (float*)data;
126 break;
127 }
128 }
129
130 static void
run(LV2_Handle handle,uint32_t n_samples)131 run (LV2_Handle handle, uint32_t n_samples)
132 {
133 RSynth* self = (RSynth*)handle;
134 float* audio[2];
135
136 audio[0] = self->outL;
137 audio[1] = self->outR;
138
139 uint32_t written = 0;
140
141 /* Process incoming MIDI events */
142 if (self->midiin) {
143 LV2_Atom_Event const* ev = (LV2_Atom_Event const*)((uintptr_t)((&(self->midiin)->body) + 1)); // lv2_atom_sequence_begin
144 while( // !lv2_atom_sequence_is_end
145 (const uint8_t*)ev < ((const uint8_t*) &(self->midiin)->body + (self->midiin)->atom.size)
146 )
147 {
148 if (ev->body.type == self->midi_MidiEvent) {
149 #ifdef DEBUG_MIDI_EVENT // debug midi messages in synth -- not rt-safe(!)
150 printf ("%5d (%d):", ev->time.frames, ev->body.size);
151 for (uint8_t i = 0; i < ev->body.size; ++i) {
152 printf (" %02x", ((const uint8_t*)(ev+1))[i]);
153 }
154 printf ("\n");
155 #endif
156 if (written + BUFFER_SIZE_SAMPLES < ev->time.frames
157 && ev->time.frames < n_samples) {
158 /* first synthesize sound up until the message timestamp */
159 written = synth_sound(self->synth, written, ev->time.frames, audio);
160 }
161 /* send midi message to synth */
162 if (self->xmas) {
163 synth_parse_xmas(self->synth, (const uint8_t*)(ev+1), ev->body.size);
164 } else {
165 synth_parse_midi(self->synth, (const uint8_t*)(ev+1), ev->body.size);
166 }
167 }
168 ev = (LV2_Atom_Event const*) // lv2_atom_sequence_next()
169 ((uintptr_t)((const uint8_t*)ev + sizeof(LV2_Atom_Event) + ((ev->body.size + 7) & ~7)));
170 }
171 }
172
173 /* synthesize [remaining] sound */
174 synth_sound(self->synth, written, n_samples, audio);
175 }
176
177 static void
cleanup(LV2_Handle handle)178 cleanup(LV2_Handle handle)
179 {
180 RSynth* self = (RSynth*)handle;
181 synth_free(self->synth);
182 free(handle);
183 }
184
185 static const void*
extension_data(const char * uri)186 extension_data(const char* uri)
187 {
188 (void) uri; /* unused variable */
189 return NULL;
190 }
191
192 static const LV2_Descriptor descriptor = {
193 RSY_URI,
194 instantiate,
195 connect_port,
196 NULL,
197 run,
198 NULL,
199 cleanup,
200 extension_data
201 };
202
203 #if defined(COMPILER_MSVC)
204 __declspec(dllexport)
205 #else
206 __attribute__ ((visibility ("default")))
207 #endif
208 const LV2_Descriptor*
lv2_descriptor(uint32_t idx)209 lv2_descriptor(uint32_t idx)
210 {
211 switch (idx) {
212 case 0:
213 return &descriptor;
214 default:
215 return NULL;
216 }
217 }
218