1 /*
2  * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
3  *
4  * This is free software: you can redistribute it and/or modify
5  * it under the terms of the Artistic License 2.0 as published by
6  * The Perl Foundation.
7  *
8  * This source is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * Artistic License 2.0 for more details.
12  *
13  * You should have received a copy of the Artistic License 2.0
14  * along the source as a COPYING file. If not, obtain it from
15  * http://www.perlfoundation.org/artistic_license_2_0.
16  */
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <math.h>
21 
22 #include <espressivo.h>
23 #include <props.h>
24 
25 #include <mpe.h>
26 
27 #define MAX_NPROPS (4*0x10)
28 
29 typedef struct _targetI_t targetI_t;
30 typedef struct _plugstate_t plugstate_t;
31 typedef struct _plughandle_t plughandle_t;
32 
33 typedef enum _pressure_mode_t
34 {
35 	MODE_CONTROLLER       = 0,
36 	MODE_NOTE_PRESSURE    = 1,
37 	MODE_CHANNEL_PRESSURE = 2,
38 	MODE_NOTE_VELOCITY    = 3
39 } pressure_mode_t;
40 
41 struct _targetI_t {
42 	uint8_t chan;
43 	uint8_t key;
44 
45 	float range; //FIXME use this
46 	uint8_t pressure; //FIXME use this
47 	uint8_t timbre; //FIXME use this
48 	pressure_mode_t mode; //FIXME use this
49 };
50 
51 struct _plugstate_t {
52 	float range [0x10];
53 	int32_t pressure [0x10];
54 	int32_t timbre [0x10];
55 	int32_t mode [0x10];
56 };
57 
58 struct _plughandle_t {
59 	struct {
60 		LV2_URID midi_MidiEvent;
61 	} uris;
62 
63 	LV2_URID_Map *map;
64 	LV2_Atom_Forge forge;
65 	LV2_Atom_Forge_Ref ref;
66 
67 	XPRESS_T(xpressI, MAX_NVOICES);
68 	targetI_t targetI [MAX_NVOICES];
69 
70 	const LV2_Atom_Sequence *event_in;
71 	LV2_Atom_Sequence *event_out;
72 
73 	PROPS_T(props, MAX_NPROPS);
74 
75 	plugstate_t state;
76 	plugstate_t stash;
77 };
78 
79 static inline LV2_Atom_Forge_Ref
_midi_event(plughandle_t * handle,int64_t frames,const uint8_t * m,size_t len)80 _midi_event(plughandle_t *handle, int64_t frames, const uint8_t *m, size_t len)
81 {
82 	LV2_Atom_Forge *forge = &handle->forge;
83 	LV2_Atom_Forge_Ref ref;
84 
85 	ref = lv2_atom_forge_frame_time(forge, frames);
86 	if(ref)
87 		ref = lv2_atom_forge_atom(forge, len, handle->uris.midi_MidiEvent);
88 	if(ref)
89 		ref = lv2_atom_forge_write(forge, m, len);
90 
91 	return ref;
92 }
93 
94 static void
_intercept_midi_range(void * data,int64_t frames,props_impl_t * impl)95 _intercept_midi_range(void *data, int64_t frames, props_impl_t *impl)
96 {
97 	plughandle_t *handle = data;
98 
99 	const size_t chan = (float *)impl->value.body - handle->state.range;
100 
101 	if(chan <= 0xf)
102 	{
103 		const uint8_t rpn_lsb [3] = {
104 			LV2_MIDI_MSG_CONTROLLER | chan,
105 			LV2_MIDI_CTL_RPN_LSB,
106 			0x0
107 		};
108 
109 		const uint8_t rpn_msb [3] = {
110 			LV2_MIDI_MSG_CONTROLLER | chan,
111 			LV2_MIDI_CTL_RPN_MSB,
112 			0x0
113 		};
114 
115 		const float range = handle->state.range[chan];
116 		const uint8_t semis = floorf(range);
117 		const uint8_t cents = floorf( (range - semis) * 100.f);
118 
119 		const uint8_t data_lsb [3] = {
120 			LV2_MIDI_MSG_CONTROLLER | chan,
121 			LV2_MIDI_CTL_LSB_DATA_ENTRY,
122 			cents
123 		};
124 
125 		const uint8_t data_msb [3] = {
126 			LV2_MIDI_MSG_CONTROLLER | chan,
127 			LV2_MIDI_CTL_MSB_DATA_ENTRY,
128 			semis
129 		};
130 
131 		if(handle->ref)
132 			handle->ref = _midi_event(handle, frames, rpn_lsb, 3);
133 		if(handle->ref)
134 			handle->ref = _midi_event(handle, frames, rpn_msb, 3);
135 		if(handle->ref)
136 			handle->ref = _midi_event(handle, frames, data_lsb, 3);
137 		if(handle->ref)
138 			handle->ref = _midi_event(handle, frames, data_msb, 3);
139 	}
140 }
141 
142 #define RANGE(NUM) \
143 { \
144 	.property = ESPRESSIVO_URI"#midi_range_"#NUM, \
145 	.offset = offsetof(plugstate_t, range) + (NUM-1)*sizeof(float), \
146 	.type = LV2_ATOM__Float, \
147 	.event_cb = _intercept_midi_range, \
148 }
149 
150 #define PRESSURE(NUM) \
151 { \
152 	.property = ESPRESSIVO_URI"#midi_pressure_"#NUM, \
153 	.offset = offsetof(plugstate_t, pressure) + (NUM-1)*sizeof(int32_t), \
154 	.type = LV2_ATOM__Int, \
155 }
156 
157 #define TIMBRE(NUM) \
158 { \
159 	.property = ESPRESSIVO_URI"#midi_timbre_"#NUM, \
160 	.offset = offsetof(plugstate_t, timbre) + (NUM-1)*sizeof(int32_t), \
161 	.type = LV2_ATOM__Int, \
162 }
163 
164 #define MODE(NUM) \
165 { \
166 	.property = ESPRESSIVO_URI"#midi_pressure_mode_"#NUM, \
167 	.offset = offsetof(plugstate_t, mode) + (NUM-1)*sizeof(int32_t), \
168 	.type = LV2_ATOM__Int, \
169 }
170 
171 static const props_def_t defs [MAX_NPROPS] = {
172 	RANGE(1),
173 	RANGE(2),
174 	RANGE(3),
175 	RANGE(4),
176 	RANGE(5),
177 	RANGE(6),
178 	RANGE(7),
179 	RANGE(8),
180 	RANGE(9),
181 	RANGE(10),
182 	RANGE(11),
183 	RANGE(12),
184 	RANGE(13),
185 	RANGE(14),
186 	RANGE(15),
187 	RANGE(16),
188 
189 	PRESSURE(1),
190 	PRESSURE(2),
191 	PRESSURE(3),
192 	PRESSURE(4),
193 	PRESSURE(5),
194 	PRESSURE(6),
195 	PRESSURE(7),
196 	PRESSURE(8),
197 	PRESSURE(9),
198 	PRESSURE(10),
199 	PRESSURE(11),
200 	PRESSURE(12),
201 	PRESSURE(13),
202 	PRESSURE(14),
203 	PRESSURE(15),
204 	PRESSURE(16),
205 
206 	TIMBRE(1),
207 	TIMBRE(2),
208 	TIMBRE(3),
209 	TIMBRE(4),
210 	TIMBRE(5),
211 	TIMBRE(6),
212 	TIMBRE(7),
213 	TIMBRE(8),
214 	TIMBRE(9),
215 	TIMBRE(10),
216 	TIMBRE(11),
217 	TIMBRE(12),
218 	TIMBRE(13),
219 	TIMBRE(14),
220 	TIMBRE(15),
221 	TIMBRE(16),
222 
223 	MODE(1),
224 	MODE(2),
225 	MODE(3),
226 	MODE(4),
227 	MODE(5),
228 	MODE(6),
229 	MODE(7),
230 	MODE(8),
231 	MODE(9),
232 	MODE(10),
233 	MODE(11),
234 	MODE(12),
235 	MODE(13),
236 	MODE(14),
237 	MODE(15),
238 	MODE(16)
239 };
240 
241 static inline void
_upd(plughandle_t * handle,int64_t frames,const xpress_state_t * state,float val,targetI_t * src)242 _upd(plughandle_t *handle, int64_t frames, const xpress_state_t *state,
243 	float val, targetI_t *src)
244 {
245 	// bender
246 	{
247 		const uint16_t bnd = (val - src->key) * src->range * 0x1fff + 0x2000;
248 		const uint8_t bnd_msb = bnd >> 7;
249 		const uint8_t bnd_lsb = bnd & 0x7f;
250 
251 		const uint8_t bend [3] = {
252 			LV2_MIDI_MSG_BENDER | src->chan,
253 			bnd_lsb,
254 			bnd_msb
255 		};
256 
257 		if(handle->ref)
258 			handle->ref = _midi_event(handle, frames, bend, 3);
259 	}
260 
261 	// pressure
262 	{
263 		const uint16_t z = state->pressure * 0x3fff;
264 		const uint8_t z_msb = z >> 7;
265 		const uint8_t z_lsb = z & 0x7f;
266 
267 		switch(src->mode)
268 		{
269 			case MODE_NOTE_PRESSURE:
270 			{
271 				const uint8_t note_pressure [3] = {
272 					LV2_MIDI_MSG_NOTE_PRESSURE | src->chan,
273 					src->key,
274 					z_msb
275 				};
276 
277 				if(handle->ref)
278 					handle->ref = _midi_event(handle, frames, note_pressure, 3);
279 			} break;
280 			case MODE_CHANNEL_PRESSURE:
281 			{
282 				const uint8_t channel_pressure [2] = {
283 					LV2_MIDI_MSG_CHANNEL_PRESSURE | src->chan,
284 					z_msb
285 				};
286 
287 				if(handle->ref)
288 					handle->ref = _midi_event(handle, frames, channel_pressure, 2);
289 			} break;
290 			case MODE_CONTROLLER:
291 			{
292 				const uint8_t pressure_lsb [3] = {
293 					LV2_MIDI_MSG_CONTROLLER | src->chan,
294 					src->pressure | 0x20,
295 					z_lsb
296 				};
297 
298 				const uint8_t pressure_msb [3] = {
299 					LV2_MIDI_MSG_CONTROLLER | src->chan,
300 					src->pressure,
301 					z_msb
302 				};
303 
304 				if(handle->ref)
305 					handle->ref = _midi_event(handle, frames, pressure_lsb, 3);
306 				if(handle->ref)
307 					handle->ref = _midi_event(handle, frames, pressure_msb, 3);
308 			} break;
309 			case MODE_NOTE_VELOCITY:
310 			{
311 				// nothing to do
312 			} break;
313 		}
314 	}
315 
316 	// timbre
317 	{
318 		const uint16_t z = state->timbre * 0x3fff;
319 		const uint8_t z_msb = z >> 7;
320 		const uint8_t z_lsb = z & 0x7f;
321 
322 		const uint8_t timbre_lsb [3] = {
323 			LV2_MIDI_MSG_CONTROLLER | src->chan,
324 			src->timbre | 0x20,
325 			z_lsb
326 		};
327 
328 		const uint8_t timbre_msb [3] = {
329 			LV2_MIDI_MSG_CONTROLLER | src->chan,
330 			src->timbre,
331 			z_msb
332 		};
333 
334 		if(handle->ref)
335 			handle->ref = _midi_event(handle, frames, timbre_lsb, 3);
336 		if(handle->ref)
337 			handle->ref = _midi_event(handle, frames, timbre_msb, 3);
338 	}
339 
340 	// FIXME dPitch, dPressure, dTimbre
341 }
342 
343 static void
_add(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)344 _add(void *data, int64_t frames, const xpress_state_t *state,
345 	xpress_uuid_t uuid, void *target)
346 {
347 	plughandle_t *handle = data;
348 	targetI_t *src = target;
349 
350 	const float val = state->pitch * 0x7f;
351 
352 	// these will remain fixed per note
353 	src->chan = state->zone;
354 	src->key = floorf(val);
355 	src->mode = handle->state.mode[state->zone];
356 	src->range = handle->state.range[state->zone];
357 	src->pressure = handle->state.pressure[state->zone];
358 	src->timbre = handle->state.timbre[state->zone];
359 
360 	const uint8_t vel = (src->mode == MODE_NOTE_VELOCITY)
361 		? state->pressure * 0x7f
362 		: 0x7f; //FIXME make this configurable
363 
364 	const uint8_t note_on [3] = {
365 		LV2_MIDI_MSG_NOTE_ON | src->chan,
366 		src->key,
367 		vel
368 	};
369 
370 	if(handle->ref)
371 		handle->ref = _midi_event(handle, frames, note_on, 3);
372 
373 	_upd(handle, frames, state, val, src);
374 }
375 
376 static void
_set(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)377 _set(void *data, int64_t frames, const xpress_state_t *state,
378 	xpress_uuid_t uuid, void *target)
379 {
380 	plughandle_t *handle = data;
381 	targetI_t *src = target;
382 
383 	const float val = state->pitch * 0x7f;
384 
385 	_upd(handle, frames, state, val, src);
386 }
387 
388 static void
_del(void * data,int64_t frames,xpress_uuid_t uuid,void * target)389 _del(void *data, int64_t frames,
390 	xpress_uuid_t uuid, void *target)
391 {
392 	plughandle_t *handle = data;
393 	targetI_t *src = target;
394 
395 	const uint8_t vel = 0x0; //FIXME maybe we want src->pressure here ?
396 
397 	const uint8_t note_off [3] = {
398 		LV2_MIDI_MSG_NOTE_OFF | src->chan,
399 		src->key,
400 		vel
401 	};
402 
403 	if(handle->ref)
404 		handle->ref = _midi_event(handle, frames, note_off, 3);
405 }
406 
407 static const xpress_iface_t ifaceI = {
408 	.size = sizeof(targetI_t),
409 
410 	.add = _add,
411 	.set = _set,
412 	.del = _del
413 };
414 
415 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)416 instantiate(const LV2_Descriptor* descriptor, double rate,
417 	const char *bundle_path, const LV2_Feature *const *features)
418 {
419 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
420 	if(!handle)
421 		return NULL;
422 
423 	xpress_map_t *voice_map = NULL;
424 
425 	for(unsigned i=0; features[i]; i++)
426 	{
427 		if(!strcmp(features[i]->URI, LV2_URID__map))
428 			handle->map = features[i]->data;
429 		else if(!strcmp(features[i]->URI, XPRESS__voiceMap))
430 			voice_map = features[i]->data;
431 	}
432 
433 	if(!handle->map)
434 	{
435 		fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
436 		free(handle);
437 		return NULL;
438 	}
439 
440 	handle->uris.midi_MidiEvent = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
441 
442 	lv2_atom_forge_init(&handle->forge, handle->map);
443 
444 	if(!xpress_init(&handle->xpressI, MAX_NVOICES, handle->map, voice_map,
445 			XPRESS_EVENT_ALL, &ifaceI, handle->targetI, handle))
446 	{
447 		free(handle);
448 		return NULL;
449 	}
450 
451 	if(!props_init(&handle->props, descriptor->URI,
452 		defs, MAX_NPROPS, &handle->state, &handle->stash,
453 		handle->map, handle))
454 	{
455 		free(handle);
456 		return NULL;
457 	}
458 
459 	return handle;
460 }
461 
462 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)463 connect_port(LV2_Handle instance, uint32_t port, void *data)
464 {
465 	plughandle_t *handle = instance;
466 
467 	switch(port)
468 	{
469 		case 0:
470 			handle->event_in = (const LV2_Atom_Sequence *)data;
471 			break;
472 		case 1:
473 			handle->event_out = (LV2_Atom_Sequence *)data;
474 			break;
475 		default:
476 			break;
477 	}
478 }
479 
480 static void
run(LV2_Handle instance,uint32_t nsamples)481 run(LV2_Handle instance, uint32_t nsamples)
482 {
483 	plughandle_t *handle = instance;
484 
485 	// prepare midi atom forge
486 	const uint32_t capacity = handle->event_out->atom.size;
487 	LV2_Atom_Forge *forge = &handle->forge;
488 	lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->event_out, capacity);
489 	LV2_Atom_Forge_Frame frame;
490 	handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
491 
492 	props_idle(&handle->props, forge, 0, &handle->ref);
493 	xpress_pre(&handle->xpressI);
494 
495 	LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev)
496 	{
497 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
498 		const int64_t frames = ev->time.frames;
499 
500 		if(!props_advance(&handle->props, forge, frames, obj, &handle->ref))
501 		{
502 			xpress_advance(&handle->xpressI, forge, frames, obj, &handle->ref);
503 		}
504 	}
505 
506 	xpress_post(&handle->xpressI, nsamples-1);
507 
508 	if(handle->ref)
509 		lv2_atom_forge_pop(forge, &frame);
510 	else
511 		lv2_atom_sequence_clear(handle->event_out);
512 }
513 
514 static void
cleanup(LV2_Handle instance)515 cleanup(LV2_Handle instance)
516 {
517 	plughandle_t *handle = instance;
518 
519 	if(handle)
520 	{
521 		xpress_deinit(&handle->xpressI);
522 		free(handle);
523 	}
524 }
525 
526 static LV2_State_Status
_state_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)527 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
528 	LV2_State_Handle state, uint32_t flags,
529 	const LV2_Feature *const *features)
530 {
531 	plughandle_t *handle = instance;
532 
533 	return props_save(&handle->props, store, state, flags, features);
534 }
535 
536 static LV2_State_Status
_state_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)537 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
538 	LV2_State_Handle state, uint32_t flags,
539 	const LV2_Feature *const *features)
540 {
541 	plughandle_t *handle = instance;
542 
543 	return props_restore(&handle->props, retrieve, state, flags, features);
544 }
545 
546 static const LV2_State_Interface state_iface = {
547 	.save = _state_save,
548 	.restore = _state_restore
549 };
550 
551 static const void *
extension_data(const char * uri)552 extension_data(const char *uri)
553 {
554 	if(!strcmp(uri, LV2_STATE__interface))
555 		return &state_iface;
556 	return NULL;
557 }
558 
559 const LV2_Descriptor midi_out = {
560 	.URI						= ESPRESSIVO_MIDI_OUT_URI,
561 	.instantiate		= instantiate,
562 	.connect_port		= connect_port,
563 	.activate				= NULL,
564 	.run						= run,
565 	.deactivate			= NULL,
566 	.cleanup				= cleanup,
567 	.extension_data	= extension_data
568 };
569