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