1 /*
2  * Copyright (c) 2015-2017 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 <inttypes.h>
21 #include <math.h>
22 
23 #include <espressivo.h>
24 #include <props.h>
25 
26 #include <mpe.h>
27 
28 #define MAX_NPROPS (1 + MPE_ZONE_MAX*2)
29 #define MAX_ZONES 8
30 #define MAX_CHANNELS 16
31 
32 typedef struct _slot_t slot_t;
33 typedef struct _targetO_t targetO_t;
34 typedef struct _plugstate_t plugstate_t;
35 typedef struct _plughandle_t plughandle_t;
36 
37 struct _slot_t {
38 	uint8_t zone;
39 	uint8_t master_channel;
40 	uint8_t num_voices;
41 
42 	uint8_t master_bend_range;
43 	uint8_t voice_bend_range;
44 
45 	int16_t master_bender;
46 
47 	int16_t voice_bender [MAX_CHANNELS - 1];
48 	int16_t voice_pressure [MAX_CHANNELS - 1];
49 	int16_t voice_timbre [ MAX_CHANNELS - 1];
50 };
51 
52 struct _targetO_t {
53 	uint8_t key;
54 	unsigned voice;
55 	xpress_uuid_t uuid;
56 	xpress_state_t state;
57 };
58 
59 struct _plugstate_t {
60 	int32_t num_zones;
61 	int32_t master_range [MPE_ZONE_MAX];
62 	int32_t voice_range [MPE_ZONE_MAX];
63 };
64 
65 struct _plughandle_t {
66 	LV2_URID_Map *map;
67 	struct {
68 		LV2_URID midi_MidiEvent;
69 	} uris;
70 	LV2_Atom_Forge forge;
71 	LV2_Atom_Forge_Ref ref;
72 
73 	const LV2_Atom_Sequence *midi_in;
74 	LV2_Atom_Sequence *event_out;
75 
76 	PROPS_T(props, MAX_NPROPS);
77 
78 	XPRESS_T(xpressO, MAX_NVOICES);
79 	targetO_t targetO [MAX_NVOICES];
80 
81 	uint16_t data;
82 	uint16_t rpn;
83 
84 	slot_t slots [MAX_ZONES];
85 	slot_t *index [MAX_CHANNELS];
86 
87 	plugstate_t state;
88 	plugstate_t stash;
89 	struct {
90 		LV2_URID num_zones;
91 		LV2_URID master_range [MPE_ZONE_MAX];
92 		LV2_URID voice_range [MPE_ZONE_MAX];
93 	} urid;
94 };
95 
96 static const targetO_t targetO_vanilla;
97 
98 #define MASTER_RANGE(NUM) \
99 { \
100 	.property = ESPRESSIVO_URI"#mpe_master_range_"#NUM, \
101 	.offset = offsetof(plugstate_t, master_range) + (NUM-1)*sizeof(int32_t), \
102 	.access = LV2_PATCH__readable, \
103 	.type = LV2_ATOM__Int, \
104 }
105 
106 #define VOICE_RANGE(NUM) \
107 { \
108 	.property = ESPRESSIVO_URI"#mpe_voice_range_"#NUM, \
109 	.offset = offsetof(plugstate_t, voice_range) + (NUM-1)*sizeof(int32_t), \
110 	.access = LV2_PATCH__readable, \
111 	.type = LV2_ATOM__Int, \
112 }
113 
114 static const props_def_t defs [MAX_NPROPS] = {
115 	{
116 		.property = ESPRESSIVO_URI"#mpe_zones",
117 		.offset = offsetof(plugstate_t, num_zones),
118 		.access = LV2_PATCH__readable,
119 		.type = LV2_ATOM__Int,
120 	},
121 
122 	MASTER_RANGE(1),
123 	MASTER_RANGE(2),
124 	MASTER_RANGE(3),
125 	MASTER_RANGE(4),
126 	MASTER_RANGE(5),
127 	MASTER_RANGE(6),
128 	MASTER_RANGE(7),
129 	MASTER_RANGE(8),
130 
131 	VOICE_RANGE(1),
132 	VOICE_RANGE(2),
133 	VOICE_RANGE(3),
134 	VOICE_RANGE(4),
135 	VOICE_RANGE(5),
136 	VOICE_RANGE(6),
137 	VOICE_RANGE(7),
138 	VOICE_RANGE(8)
139 };
140 
141 
142 static inline void
_slot_init(slot_t * slot,uint8_t zone,uint8_t master_channel,uint8_t num_voices)143 _slot_init(slot_t *slot, uint8_t zone, uint8_t master_channel, uint8_t num_voices)
144 {
145 	slot->zone = zone;
146 	slot->master_channel = master_channel;
147 	slot->num_voices = num_voices;
148 
149 	slot->master_bend_range = 2;
150 	slot->voice_bend_range = 48;
151 
152 	slot->master_bender = 0;
153 
154 	const int16_t empty [MAX_CHANNELS - 1] = {
155 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
156 	};
157 	memcpy(slot->voice_bender, empty, sizeof(empty));
158 	memcpy(slot->voice_pressure, empty, sizeof(empty));
159 	memcpy(slot->voice_timbre, empty, sizeof(empty));
160 }
161 
162 static inline void
_slots_init(plughandle_t * handle)163 _slots_init(plughandle_t *handle)
164 {
165 	_slot_init(&handle->slots[0], 0, 0, 15);
166 	for(unsigned i=1; i<MAX_ZONES; i++)
167 		_slot_init(&handle->slots[i], i, UINT8_MAX, 0);
168 }
169 
170 static inline void
_index_update(plughandle_t * handle)171 _index_update(plughandle_t *handle)
172 {
173 	memset(handle->index, 0x0, sizeof(handle->index));
174 
175 	for(unsigned i=0; i<MAX_ZONES; i++)
176 	{
177 		slot_t *slot = &handle->slots[i];
178 
179 		if(slot->num_voices == 0)
180 			continue; // invalid
181 
182 		for(unsigned j = slot->master_channel;
183 			j <= slot->master_channel + slot->num_voices;
184 			j++)
185 		{
186 			handle->index[j] = slot;
187 		}
188 	}
189 }
190 
191 static inline bool
_slot_is_master(slot_t * slot,uint8_t chan)192 _slot_is_master(slot_t *slot, uint8_t chan)
193 {
194 	return slot->master_channel == chan;
195 }
196 
197 static inline bool
_slot_is_first(slot_t * slot,uint8_t chan)198 _slot_is_first(slot_t *slot, uint8_t chan)
199 {
200 	return slot->master_channel + 1 == chan;
201 }
202 
203 static inline bool
_slot_is_voice(slot_t * slot,uint8_t chan)204 _slot_is_voice(slot_t *slot, uint8_t chan)
205 {
206 	return (chan >= slot->master_channel + 1)
207 		&& (chan <= slot->master_channel + slot->num_voices);
208 }
209 
210 static inline unsigned
_slot_voice(slot_t * slot,uint8_t chan)211 _slot_voice(slot_t *slot, uint8_t chan)
212 {
213 	return chan - slot->master_channel - 1;
214 }
215 
216 #if 0
217 static inline void
218 _zone_dump(plughandle_t *handle)
219 {
220 	for(unsigned i=0; i<MAX_ZONES; i++)
221 	{
222 		slot_t *slot = &handle->slots[i];
223 
224 		if(slot->num_voices == 0)
225 			continue;
226 
227 		printf("%u: %"PRIu8" %"PRIu8" %"PRIu8"\n", i, slot->zone, slot->master_channel, slot->num_voices);
228 	}
229 	printf("\n");
230 }
231 #endif
232 
233 static inline void
_zone_notify(plughandle_t * handle,int64_t frames)234 _zone_notify(plughandle_t *handle, int64_t frames)
235 {
236 	handle->state.num_zones = 0;
237 
238 	for(unsigned i=0; i<MAX_ZONES; i++)
239 	{
240 		slot_t *slot = &handle->slots[i];
241 
242 		//printf("%u: %u %i %i\n", i, slot->num_voices, slot->master_bend_range, slot->voice_bend_range);
243 
244 		handle->state.master_range[i] = slot->master_bend_range;
245 		props_set(&handle->props, &handle->forge, frames, handle->urid.master_range[i], &handle->ref);
246 
247 		handle->state.voice_range[i] = slot->voice_bend_range;
248 		props_set(&handle->props, &handle->forge, frames, handle->urid.voice_range[i], &handle->ref);
249 
250 		if(slot->num_voices == 0)
251 			continue; // invalid
252 
253 		handle->state.num_zones += 1;
254 	}
255 
256 	props_set(&handle->props, &handle->forge, frames, handle->urid.num_zones, &handle->ref);
257 }
258 
259 static inline void
_zone_register(plughandle_t * handle,int64_t frames,uint8_t master_channel,uint8_t num_voices)260 _zone_register(plughandle_t *handle, int64_t frames, uint8_t master_channel, uint8_t num_voices)
261 {
262 	if( (num_voices < 1) || (master_channel + num_voices > MAX_CHANNELS) )
263 		return; // invalid
264 
265 	// make copy of current zone layout
266 	slot_t stash [MAX_ZONES];
267 	memcpy(stash, handle->slots, sizeof(stash));
268 
269 	const uint8_t master_end = master_channel + num_voices;
270 
271 	// pass 1
272 	for(unsigned i=0; i<MAX_ZONES; i++)
273 	{
274 		slot_t *slot = &stash[i];
275 
276 		// invalid?
277 		if(slot->num_voices == 0)
278 			continue;
279 
280 		// shorten zone?
281 		if( (slot->master_channel < master_channel) && (slot->master_channel + slot->num_voices >= master_channel) )
282 		{
283 			slot->num_voices = master_channel - 1 - slot->master_channel;
284 			continue;
285 		}
286 
287 		// overwrite master?
288 		if( (slot->master_channel >= master_channel) && (slot->master_channel <= master_end) )
289 		{
290 			slot->num_voices = 0; // invalidate
291 			continue;
292 		}
293 
294 		// overwrite first voice?
295 		if( (slot->master_channel + 1 >= master_channel) && (slot->master_channel + 1 <= master_end) )
296 		{
297 			slot->num_voices = 0; // invalidate
298 			continue;
299 		}
300 	}
301 
302 	// clear slots
303 	_slots_init(handle);
304 
305 	// pass 2
306 	bool inserted = false;
307 	slot_t *dst = handle->slots;
308 	unsigned I = 0;
309 	for(unsigned i=0; i<MAX_ZONES; i++)
310 	{
311 		slot_t *slot = &stash[i];
312 
313 		if(slot->num_voices == 0)
314 		{
315 			continue;
316 		}
317 
318 		if(!inserted && (slot->master_channel > master_end) )
319 		{
320 			// insert new zone
321 			_slot_init(dst, i, master_channel, num_voices);
322 			dst++;
323 
324 			inserted = true;
325 		}
326 
327 		// clone zone
328 		memcpy(dst, slot, sizeof(slot_t));
329 		dst->zone = i;
330 		dst++;
331 
332 		I = i + 1;
333 	}
334 
335 	if(!inserted)
336 	{
337 		// insert new zone at end
338 		_slot_init(dst, I++, master_channel, num_voices);
339 		dst++;
340 	}
341 
342 	_index_update(handle);
343 }
344 
345 static const xpress_iface_t ifaceO = {
346 	.size = sizeof(targetO_t)
347 };
348 
349 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)350 instantiate(const LV2_Descriptor* descriptor, double rate,
351 	const char *bundle_path, const LV2_Feature *const *features)
352 {
353 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
354 	if(!handle)
355 		return NULL;
356 
357 	xpress_map_t *voice_map = NULL;
358 
359 	for(unsigned i=0; features[i]; i++)
360 	{
361 		if(!strcmp(features[i]->URI, LV2_URID__map))
362 			handle->map = features[i]->data;
363 		else if(!strcmp(features[i]->URI, XPRESS__voiceMap))
364 			voice_map = features[i]->data;
365 	}
366 
367 	if(!handle->map)
368 	{
369 		fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
370 		free(handle);
371 		return NULL;
372 	}
373 
374 	handle->uris.midi_MidiEvent = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
375 
376 	lv2_atom_forge_init(&handle->forge, handle->map);
377 
378 	if(  !xpress_init(&handle->xpressO, MAX_NVOICES, handle->map, voice_map,
379 			XPRESS_EVENT_NONE, &ifaceO, handle->targetO, handle) )
380 	{
381 		free(handle);
382 		return NULL;
383 	}
384 
385 	if(!props_init(&handle->props, descriptor->URI,
386 		defs, MAX_NPROPS, &handle->state, &handle->stash,
387 		handle->map, handle))
388 	{
389 		fprintf(stderr, "failed to allocate property structure\n");
390 		free(handle);
391 		return NULL;
392 	}
393 
394 	unsigned p = 0;
395 	handle->urid.num_zones = props_map(&handle->props, defs[p++].property);
396 	handle->state.num_zones = 1;
397 
398 	for(unsigned z=0; z<MPE_ZONE_MAX; z++)
399 	{
400 		handle->urid.master_range[z] = props_map(&handle->props, defs[p++].property);
401 		handle->state.master_range[z] = 2;
402 	}
403 	for(unsigned z=0; z<MPE_ZONE_MAX; z++)
404 	{
405 		handle->urid.voice_range[z] = props_map(&handle->props, defs[p++].property);
406 		handle->state.voice_range[z] = 48;
407 	}
408 
409 	_slots_init(handle);
410 	_index_update(handle);
411 
412 	return handle;
413 }
414 
415 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)416 connect_port(LV2_Handle instance, uint32_t port, void *data)
417 {
418 	plughandle_t *handle = instance;
419 
420 	switch(port)
421 	{
422 		case 0:
423 			handle->midi_in = (const LV2_Atom_Sequence *)data;
424 			break;
425 		case 1:
426 			handle->event_out = (LV2_Atom_Sequence *)data;
427 			break;
428 		default:
429 			break;
430 	}
431 }
432 
433 static inline xpress_uuid_t
_uuid_create(slot_t * slot,uint8_t chan)434 _uuid_create(slot_t *slot, uint8_t chan)
435 {
436 	return ((int32_t)slot->zone << 8) | chan;
437 }
438 
439 static inline bool
_mpe_in(plughandle_t * handle,int64_t frames,const LV2_Atom * atom)440 _mpe_in(plughandle_t *handle, int64_t frames, const LV2_Atom *atom)
441 {
442 	LV2_Atom_Forge *forge = &handle->forge;
443 	const uint8_t *m = LV2_ATOM_BODY_CONST(atom);
444 	const uint8_t comm = m[0] & 0xf0;
445 	const uint8_t chan = m[0] & 0x0f;
446 
447 	bool zone_notify = false;
448 
449 	switch(comm)
450 	{
451 		case LV2_MIDI_MSG_NOTE_ON:
452 		{
453 			slot_t *slot = handle->index[chan];
454 
455 			if(slot && _slot_is_voice(slot, chan))
456 			{
457 				const unsigned voice = _slot_voice(slot, chan);
458 				const uint8_t key = m[1];
459 				const xpress_uuid_t uuid = _uuid_create(slot, chan);
460 
461 				targetO_t *target = xpress_add(&handle->xpressO, uuid);
462 				if(target)
463 				{
464 					*target = targetO_vanilla;
465 					target->key = key;
466 					target->voice = voice;
467 					target->uuid = xpress_map(&handle->xpressO);
468 
469 					const float offset_master = slot->master_bender * 0x1p-13 * slot->master_bend_range;
470 					const float offset_voice = slot->voice_bender[voice] * 0x1p-13 * slot->voice_bend_range;
471 					target->state.zone = slot->zone;
472 					target->state.pitch = ((float)target->key + offset_master + offset_voice) / 0x7f;
473 
474 					if(handle->ref)
475 						handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
476 				}
477 			}
478 
479 			break;
480 		}
481 		case LV2_MIDI_MSG_NOTE_OFF:
482 		{
483 			slot_t *slot = handle->index[chan];
484 
485 			if(slot && _slot_is_voice(slot, chan))
486 			{
487 				const xpress_uuid_t uuid = _uuid_create(slot, chan);
488 
489 				targetO_t *target = xpress_get(&handle->xpressO, uuid);
490 				if(target)
491 				{
492 #if 0
493 					if(handle->ref)
494 						handle->ref = xpress_del(&handle->xpressO, forge, frames, target->uuid);
495 #endif
496 				}
497 
498 				xpress_free(&handle->xpressO, uuid);
499 			}
500 
501 			break;
502 		}
503 		case LV2_MIDI_MSG_CHANNEL_PRESSURE:
504 		{
505 			slot_t *slot = handle->index[chan];
506 
507 			if(slot && _slot_is_voice(slot, chan))
508 			{
509 				const xpress_uuid_t uuid = _uuid_create(slot, chan);
510 				const unsigned voice = _slot_voice(slot, chan);
511 
512 				slot->voice_pressure[voice] = m[1] << 7;
513 
514 				targetO_t *target = xpress_get(&handle->xpressO, uuid);
515 				if(target)
516 				{
517 					const float pressure = slot->voice_pressure[voice] / 0x3fff;
518 					target->state.pressure = pressure;
519 
520 					if(handle->ref)
521 						handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
522 				}
523 			}
524 
525 			break;
526 		}
527 		case LV2_MIDI_MSG_BENDER:
528 		{
529 			slot_t *slot = handle->index[chan];
530 
531 			if(slot)
532 			{
533 				const int16_t bender = (((int16_t)m[2] << 7) | m[1]) - 0x2000;
534 
535 				if(_slot_is_master(slot, chan))
536 				{
537 					slot->master_bender = bender;
538 
539 					XPRESS_VOICE_FOREACH(&handle->xpressO, voice)
540 					{
541 						targetO_t *target = voice->target;
542 
543 						if(target->state.zone != slot->zone)
544 							continue;
545 
546 						const float offset_master = slot->master_bender * 0x1p-13 * slot->master_bend_range;
547 						const float offset_voice = slot->voice_bender[target->voice] * 0x1p-13 * slot->voice_bend_range;
548 						target->state.pitch = ((float)target->key + offset_master + offset_voice) / 0x7f;
549 
550 						if(handle->ref)
551 							handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
552 					}
553 				}
554 				else if(_slot_is_voice(slot, chan))
555 				{
556 					const xpress_uuid_t uuid = _uuid_create(slot, chan);
557 					const unsigned voice = _slot_voice(slot, chan);
558 
559 					slot->voice_bender[voice] = bender;
560 
561 					targetO_t *target = xpress_get(&handle->xpressO, uuid);
562 					if(target)
563 					{
564 						const float offset_master = slot->master_bender * 0x1p-13 * slot->master_bend_range;
565 						const float offset_voice = slot->voice_bender[voice] * 0x1p-13 * slot->voice_bend_range;
566 						target->state.pitch = ((float)target->key + offset_master + offset_voice) / 0x7f;
567 
568 						if(handle->ref)
569 							handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
570 					}
571 				}
572 			}
573 
574 			break;
575 		}
576 		case LV2_MIDI_MSG_CONTROLLER:
577 		{
578 			const uint8_t controller = m[1];
579 			const uint8_t value = m[2];
580 
581 			switch(controller)
582 			{
583 				case LV2_MIDI_CTL_LSB_DATA_ENTRY:
584 				{
585 					handle->data = (handle->data & 0x3f80) | value;
586 
587 					break;
588 				}
589 				case LV2_MIDI_CTL_MSB_DATA_ENTRY:
590 				{
591 					handle->data = (handle->data & 0x7f) | (value << 7);
592 
593 					if(handle->rpn == 6) // new MPE zone registered
594 					{
595 						const uint8_t zone_width = handle->data >> 7;
596 
597 						_zone_register(handle, frames, chan, zone_width);
598 						zone_notify = true;
599 					}
600 					else if(handle->rpn == 0) // pitch-bend range registered
601 					{
602 						const uint8_t bend_range = handle->data >> 7;
603 						slot_t *slot = handle->index[chan];
604 
605 						if(slot)
606 						{
607 							if(_slot_is_master(slot, chan))
608 							{
609 								slot->master_bend_range = bend_range;
610 
611 								handle->state.master_range[slot->zone] = slot->master_bend_range;
612 								props_set(&handle->props, &handle->forge, frames, handle->urid.master_range[slot->zone], &handle->ref);
613 							}
614 							else if(_slot_is_first(slot, chan))
615 							{
616 								slot->voice_bend_range = bend_range;
617 
618 								handle->state.voice_range[slot->zone] = slot->voice_bend_range;
619 								props_set(&handle->props, &handle->forge, frames, handle->urid.voice_range[slot->zone], &handle->ref);
620 							}
621 						}
622 					}
623 
624 					break;
625 				}
626 
627 				case LV2_MIDI_CTL_RPN_LSB:
628 				{
629 					handle->rpn = (handle->rpn & 0x3f80) | value;
630 
631 					break;
632 				}
633 				case LV2_MIDI_CTL_RPN_MSB:
634 				{
635 					handle->rpn = (handle->rpn & 0x7f) | ((uint16_t)value << 7);
636 
637 					break;
638 				}
639 
640 				case LV2_MIDI_CTL_SC1_SOUND_VARIATION | 0x20:
641 				{
642 					slot_t *slot = handle->index[chan];
643 
644 					if(slot && _slot_is_voice(slot, chan))
645 					{
646 						const unsigned voice = _slot_voice(slot, chan);
647 						slot->voice_pressure[voice] = (slot->voice_pressure[voice] & 0x3f80) | value;
648 					}
649 
650 					break;
651 				}
652 				case LV2_MIDI_CTL_SC1_SOUND_VARIATION:
653 				{
654 					slot_t *slot = handle->index[chan];
655 
656 					if(slot && _slot_is_voice(slot, chan))
657 					{
658 						const unsigned voice = _slot_voice(slot, chan);
659 						const xpress_uuid_t uuid = _uuid_create(slot, chan);
660 
661 						slot->voice_pressure[voice] = (slot->voice_pressure[voice] & 0x7f) | ((uint16_t)value << 7);
662 
663 						targetO_t *target = xpress_get(&handle->xpressO, uuid);
664 						if(target)
665 						{
666 							const float pressure = slot->voice_pressure[voice] / 0x3fff;
667 							target->state.pressure = pressure;
668 
669 							if(handle->ref)
670 								handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
671 						}
672 					}
673 
674 					break;
675 				}
676 
677 				case LV2_MIDI_CTL_SC5_BRIGHTNESS | 0x20:
678 				{
679 					slot_t *slot = handle->index[chan];
680 
681 					if(slot && _slot_is_voice(slot, chan))
682 					{
683 						const unsigned voice = _slot_voice(slot, chan);
684 						slot->voice_timbre[voice] = (slot->voice_timbre[voice] & 0x3f80) | value;
685 					}
686 
687 					break;
688 				}
689 				case LV2_MIDI_CTL_SC5_BRIGHTNESS:
690 				{
691 					slot_t *slot = handle->index[chan];
692 
693 					if(slot && _slot_is_voice(slot, chan))
694 					{
695 						const unsigned voice = _slot_voice(slot, chan);
696 						const xpress_uuid_t uuid = _uuid_create(slot, chan);
697 
698 						slot->voice_timbre[voice] = (slot->voice_timbre[voice] & 0x7f) | ((uint16_t)value << 7);
699 
700 						targetO_t *target = xpress_get(&handle->xpressO, uuid);
701 						if(target)
702 						{
703 							const float timbre = slot->voice_timbre[voice] / 0x3fff;
704 							target->state.timbre = timbre;
705 
706 							if(handle->ref)
707 								handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
708 						}
709 					}
710 
711 					break;
712 				}
713 			}
714 
715 			break;
716 		}
717 	}
718 
719 	return zone_notify;
720 }
721 
722 static void
run(LV2_Handle instance,uint32_t nsamples)723 run(LV2_Handle instance, uint32_t nsamples)
724 {
725 	plughandle_t *handle = instance;
726 
727 	// prepare midi atom forge
728 	const uint32_t capacity = handle->event_out->atom.size;
729 	LV2_Atom_Forge *forge = &handle->forge;
730 	lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->event_out, capacity);
731 	LV2_Atom_Forge_Frame frame;
732 	handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
733 
734 	props_idle(&handle->props, forge, 0, &handle->ref);
735 	xpress_rst(&handle->xpressO);
736 
737 	bool zone_notify = false;
738 
739 	LV2_ATOM_SEQUENCE_FOREACH(handle->midi_in, ev)
740 	{
741 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
742 		const int64_t frames = ev->time.frames;
743 
744 		if(obj->atom.type == handle->uris.midi_MidiEvent)
745 		{
746 			if(_mpe_in(handle, frames, &obj->atom))
747 				zone_notify = true;
748 		}
749 		else
750 		{
751 			props_advance(&handle->props, forge, frames, obj, &handle->ref);
752 		}
753 	}
754 
755 	if(zone_notify)
756 		_zone_notify(handle, nsamples - 1);
757 
758 	if(handle->ref && !xpress_synced(&handle->xpressO))
759 		handle->ref = xpress_alive(&handle->xpressO, forge, nsamples-1);
760 
761 	if(handle->ref)
762 		lv2_atom_forge_pop(forge, &frame);
763 	else
764 		lv2_atom_sequence_clear(handle->event_out);
765 }
766 
767 static void
cleanup(LV2_Handle instance)768 cleanup(LV2_Handle instance)
769 {
770 	plughandle_t *handle = instance;
771 
772 	if(handle)
773 	{
774 		xpress_deinit(&handle->xpressO);
775 		free(handle);
776 	}
777 }
778 
779 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)780 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
781 	LV2_State_Handle state, uint32_t flags,
782 	const LV2_Feature *const *features)
783 {
784 	plughandle_t *handle = instance;
785 
786 	return props_save(&handle->props, store, state, flags, features);
787 }
788 
789 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)790 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
791 	LV2_State_Handle state, uint32_t flags,
792 	const LV2_Feature *const *features)
793 {
794 	plughandle_t *handle = instance;
795 
796 	return props_restore(&handle->props, retrieve, state, flags, features);
797 }
798 
799 static const LV2_State_Interface state_iface = {
800 	.save = _state_save,
801 	.restore = _state_restore
802 };
803 
804 static const void *
extension_data(const char * uri)805 extension_data(const char *uri)
806 {
807 	if(!strcmp(uri, LV2_STATE__interface))
808 		return &state_iface;
809 	return NULL;
810 }
811 
812 const LV2_Descriptor mpe_in = {
813 	.URI						= ESPRESSIVO_MPE_IN_URI,
814 	.instantiate		= instantiate,
815 	.connect_port		= connect_port,
816 	.activate				= NULL,
817 	.run						= run,
818 	.deactivate			= NULL,
819 	.cleanup				= cleanup,
820 	.extension_data	= extension_data
821 };
822