1 /* midifilter.lv2
2 *
3 * Copyright (C) 2013 Robin Gareus <robin@gareus.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #define _GNU_SOURCE
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 #include <time.h>
26
27 #ifdef _WIN32
28 #define random() rand()
29 #define srandom(X) srand(X)
30 #endif
31
32 #include "midifilter.h"
33
34 /******************************************************************************
35 * common 'helper' functions
36 */
midi_limit_val(const int d)37 static int midi_limit_val(const int d) {
38 if (d < 0) return 0;
39 if (d > 127) return 127;
40 return d;
41 }
42
midi_limit_chn(const int c)43 static int midi_limit_chn(const int c) {
44 if (c < 0) return 0;
45 if (c > 15) return 15;
46 return c;
47 }
48
midi_valid(const int d)49 static int midi_valid(const int d) {
50 if (d >=0 && d < 128) return 1;
51 return 0;
52 }
53
midi_14bit(const uint8_t * const b)54 static int midi_14bit(const uint8_t * const b) {
55 return ((b[1]) | (b[2]<<7));
56 }
57
midi_is_panic(const uint8_t * const b,const int s)58 static int midi_is_panic(const uint8_t * const b, const int s) {
59 if (s == 3
60 && (b[0] & 0xf0) == MIDI_CONTROLCHANGE
61 && ( (b[1]&0x7f) == 123 || (b[1]&0x7f) == 120 )
62 && (b[2]&0x7f) == 0)
63 return 1;
64 return 0;
65 }
66
normrand(const float dev)67 static float normrand(const float dev) {
68 static char initialized = 0;
69 static float randmem;
70
71 if (!initialized) {
72 randmem = 2.0 * random() / (float)RAND_MAX - 1;
73 initialized = 1;
74 }
75
76 float U = 2.0 * random() / (float)RAND_MAX - 1; //rand E(-1,1)
77 float S = SQUARE(U) + SQUARE(randmem); //map 2 random vars to unit circle
78
79 if(S >= 1.0f) {
80 //repull RV if outside unit circle
81 U = 2.0* random() / (float)RAND_MAX - 1;
82 S = SQUARE(U) + SQUARE(randmem);
83 if(S >= 1.0f) {
84 U = 2.0* random() / (float)RAND_MAX - 1;
85 S = SQUARE(U) + SQUARE(randmem);
86 if(S >= 1.0f) {
87 U=0;
88 }
89 }
90 }
91 randmem = U; //store RV for next round
92 return U ? (dev * U * sqrt(-2.0 * log(S) / S)) : 0;
93 }
94
95 /**
96 * add a midi message to the output port
97 */
98 void
forge_midimessage(MidiFilter * self,uint32_t tme,const uint8_t * const buffer,uint32_t size)99 forge_midimessage(MidiFilter* self,
100 uint32_t tme,
101 const uint8_t* const buffer,
102 uint32_t size)
103 {
104 LV2_Atom midiatom;
105 midiatom.type = self->uris.midi_MidiEvent;
106 midiatom.size = size;
107
108 if (0 == lv2_atom_forge_frame_time(&self->forge, tme)) return;
109 if (0 == lv2_atom_forge_raw(&self->forge, &midiatom, sizeof(LV2_Atom))) return;
110 if (0 == lv2_atom_forge_raw(&self->forge, buffer, size)) return;
111 lv2_atom_forge_pad(&self->forge, sizeof(LV2_Atom) + size);
112 }
113
114 /******************************************************************************
115 * include vairant code
116 */
117
118 #define MX_CODE
119 #include "filters.c"
120 #undef MX_CODE
121
122 /**
123 * Update the current position based on a host message. This is called by
124 * run() when a time:Position is received.
125 */
126 static void
update_position(MidiFilter * self,const LV2_Atom_Object * obj)127 update_position(MidiFilter* self, const LV2_Atom_Object* obj)
128 {
129 const MidiFilterURIs* uris = &self->uris;
130
131 // Received new transport position/speed
132 LV2_Atom *beat = NULL, *bpm = NULL, *speed = NULL;
133 LV2_Atom *fps = NULL, *frame = NULL;
134 lv2_atom_object_get(obj,
135 uris->time_barBeat, &beat,
136 uris->time_beatsPerMinute, &bpm,
137 uris->time_speed, &speed,
138 uris->time_frame, &frame,
139 uris->time_fps, &fps,
140 NULL);
141 if (bpm && bpm->type == uris->atom_Float) {
142 // Tempo changed, update BPM
143 self->bpm = ((LV2_Atom_Float*)bpm)->body;
144 self->available_info |= NFO_BPM;
145 }
146 if (speed && speed->type == uris->atom_Float) {
147 // Speed changed, e.g. 0 (stop) to 1 (play)
148 self->speed = ((LV2_Atom_Float*)speed)->body;
149 self->available_info |= NFO_SPEED;
150 }
151 if (beat && beat->type == uris->atom_Float) {
152 const double samples_per_beat = 60.0 / self->bpm * self->samplerate;
153 self->bar_beats = ((LV2_Atom_Float*)beat)->body;
154 self->beat_beats = self->bar_beats - floor(self->bar_beats);
155 self->pos_bbt = self->beat_beats * samples_per_beat;
156 self->available_info |= NFO_BEAT;
157 }
158 if (fps && fps->type == uris->atom_Float) {
159 self->frames_per_second = ((LV2_Atom_Float*)fps)->body;
160 self->available_info |= NFO_FPS;
161 }
162 if (frame && frame->type == uris->atom_Long) {
163 self->pos_frame = ((LV2_Atom_Long*)frame)->body;
164 self->available_info |= NFO_FRAME;
165 }
166 }
167 /******************************************************************************
168 * LV2
169 */
170
171 static void
run(LV2_Handle instance,uint32_t n_samples)172 run(LV2_Handle instance, uint32_t n_samples)
173 {
174 int i;
175 MidiFilter* self = (MidiFilter*)instance;
176 self->n_samples = n_samples;
177
178 if (!self->midiout || !self->midiin) {
179 /* eg. ARDOUR::LV2Plugin::latency_compute_run()
180 * -> midi ports are not yet connected
181 */
182 goto out;
183 }
184
185 /* prepare midiout port */
186 const uint32_t capacity = self->midiout->atom.size;
187 lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->midiout, capacity);
188 lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);
189
190 if (self->preproc_fn) {
191 self->preproc_fn(self);
192 }
193
194 /* process events on the midiin port */
195 LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->midiin)->body);
196 while(!lv2_atom_sequence_is_end(&(self->midiin)->body, (self->midiin)->atom.size, ev)) {
197 if (ev->body.type == self->uris.midi_MidiEvent) {
198 self->filter_fn(self, ev->time.frames, (uint8_t*)(ev+1), ev->body.size);
199 }
200 else if (ev->body.type == self->uris.atom_Blank || ev->body.type == self->uris.atom_Object) {
201 const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
202 if (obj->body.otype == self->uris.time_Position) {
203 update_position(self, obj);
204 }
205 }
206 ev = lv2_atom_sequence_next(ev);
207 }
208
209 if (self->postproc_fn) {
210 self->postproc_fn(self);
211 }
212
213 /* increment position for next cycle */
214 if (self->available_info & NFO_BEAT) {
215 float bpm = self->bpm;
216 if (self->available_info & NFO_SPEED) {
217 bpm *= self->speed;
218 }
219 if (bpm != 0) {
220 const double samples_per_beat = 60.0 * self->samplerate / bpm;
221 self->bar_beats += (double) n_samples / samples_per_beat;
222 self->beat_beats = self->bar_beats - floor(self->bar_beats);
223 self->pos_bbt = self->beat_beats * samples_per_beat;
224 }
225 }
226 if (self->available_info & NFO_FRAME) {
227 self->pos_frame += n_samples;
228 }
229
230 out:
231 if (self->latency_port) {
232 *self->latency_port = self->latency;
233 }
234
235 for (i = 0 ; i < MAXCFG ; ++i) {
236 if (!self->cfg[i]) continue;
237 self->lcfg[i] = *self->cfg[i];
238 }
239 }
240
241
242 static inline void
map_mf_uris(LV2_URID_Map * map,MidiFilterURIs * uris)243 map_mf_uris(LV2_URID_Map* map, MidiFilterURIs* uris)
244 {
245 uris->atom_Blank = map->map(map->handle, LV2_ATOM__Blank);
246 uris->atom_Object = map->map(map->handle, LV2_ATOM__Object);
247 uris->midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent);
248 uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence);
249
250 uris->atom_Long = map->map(map->handle, LV2_ATOM__Long);
251 uris->atom_Float = map->map(map->handle, LV2_ATOM__Float);
252 uris->time_Position = map->map(map->handle, LV2_TIME__Position);
253 uris->time_barBeat = map->map(map->handle, LV2_TIME__barBeat);
254 uris->time_beatsPerMinute = map->map(map->handle, LV2_TIME__beatsPerMinute);
255 uris->time_speed = map->map(map->handle, LV2_TIME__speed);
256 uris->time_frame = map->map(map->handle, LV2_TIME__frame);
257 uris->time_fps = map->map(map->handle, LV2_TIME__framesPerSecond);
258 }
259
260 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)261 instantiate(const LV2_Descriptor* descriptor,
262 double rate,
263 const char* bundle_path,
264 const LV2_Feature* const* features)
265 {
266 int i;
267 MidiFilter* self = (MidiFilter*)calloc(1, sizeof(MidiFilter));
268 if (!self) return NULL;
269
270 for (i=0; features[i]; ++i) {
271 if (!strcmp(features[i]->URI, LV2_URID__map)) {
272 self->map = (LV2_URID_Map*)features[i]->data;
273 }
274 }
275
276 if (!self->map) {
277 fprintf(stderr, "midifilter.lv2 error: Host does not support urid:map\n");
278 free(self);
279 return NULL;
280 }
281
282 map_mf_uris(self->map, &self->uris);
283 lv2_atom_forge_init(&self->forge, self->map);
284 self->samplerate = rate;
285 self->bpm = 120;
286
287 if (0) ;
288 #define MX_FILTER
289 #include "filters.c"
290 #undef MX_FILTER
291 else {
292 fprintf(stderr, "midifilter.lv2 error: unsupported plugin function.\n");
293 free(self);
294 return NULL;
295 }
296
297 for (i=0; i < MAXCFG; ++i) {
298 self->lcfg[i] = 0;
299 }
300
301 return (LV2_Handle)self;
302 }
303
304 #define CFG_PORT(n) \
305 case (n+3): \
306 self->cfg[n] = (float*)data; \
307 break;
308
309 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)310 connect_port(LV2_Handle instance,
311 uint32_t port,
312 void* data)
313 {
314 MidiFilter* self = (MidiFilter*)instance;
315
316 switch (port) {
317 case 0:
318 self->midiin = (const LV2_Atom_Sequence*)data;
319 break;
320 case 1:
321 self->midiout = (LV2_Atom_Sequence*)data;
322 break;
323 case 2:
324 self->latency_port = (float*)data;
325 break;
326 LOOP_CFG(CFG_PORT)
327 default:
328 break;
329 }
330 }
331
332 static void
cleanup(LV2_Handle instance)333 cleanup(LV2_Handle instance)
334 {
335 MidiFilter* self = (MidiFilter*)instance;
336 if (self->cleanup_fn) {
337 self->cleanup_fn(self);
338 }
339
340 free(instance);
341 }
342
343 const void*
extension_data(const char * uri)344 extension_data(const char* uri)
345 {
346 return NULL;
347 }
348
349 #define MX_DESC
350 #include "filters.c"
351 #undef MX_DESC
352
353 #define LV2DESC(ID) \
354 case ID: return &(descriptor ## ID);
355
356
357 #undef LV2_SYMBOL_EXPORT
358 #ifdef _WIN32
359 # define LV2_SYMBOL_EXPORT __declspec(dllexport)
360 #else
361 # define LV2_SYMBOL_EXPORT __attribute__ ((visibility ("default")))
362 #endif
363 LV2_SYMBOL_EXPORT
364 const LV2_Descriptor*
lv2_descriptor(uint32_t index)365 lv2_descriptor(uint32_t index)
366 {
367 switch (index) {
368 LOOP_DESC(LV2DESC)
369 default: return NULL;
370 }
371 }
372 /* vi:set ts=8 sts=8 sw=8: */
373