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 (2 + MPE_ZONE_MAX*4)
28 
29 typedef struct _targetI_t targetI_t;
30 typedef struct _plugstate_t plugstate_t;
31 typedef struct _plughandle_t plughandle_t;
32 
33 struct _targetI_t {
34 	uint8_t chan;
35 	uint8_t zone;
36 	uint8_t key;
37 };
38 
39 struct _plugstate_t {
40 	int32_t zones;
41 	int32_t velocity;
42 	int32_t master_range [MPE_ZONE_MAX];
43 	int32_t voice_range [MPE_ZONE_MAX];
44 	int32_t pressure_controller [MPE_ZONE_MAX];
45 	int32_t timbre_controller [MPE_ZONE_MAX];
46 };
47 
48 struct _plughandle_t {
49 	struct {
50 		LV2_URID midi_MidiEvent;
51 	} uris;
52 
53 	LV2_URID_Map *map;
54 	LV2_Atom_Forge forge;
55 	LV2_Atom_Forge_Ref ref;
56 
57 	XPRESS_T(xpressI, MAX_NVOICES);
58 	targetI_t targetI [MAX_NVOICES];
59 
60 	const LV2_Atom_Sequence *event_in;
61 	LV2_Atom_Sequence *midi_out;
62 
63 	mpe_t mpe;
64 	PROPS_T(props, MAX_NPROPS);
65 
66 	plugstate_t state;
67 	plugstate_t stash;
68 };
69 
70 static inline void
mpe_populate(mpe_t * mpe,uint8_t n_zones)71 mpe_populate(mpe_t *mpe, uint8_t n_zones)
72 {
73 	plughandle_t *handle = (void *)mpe - offsetof(plughandle_t, mpe);
74 
75 	assert(n_zones > 0);
76 	n_zones %= MPE_ZONE_MAX + 1; // wrap around if n_zones > MPE_ZONE_MAX
77 	int8_t rem = MPE_CHAN_MAX % n_zones;
78 	const uint8_t span = (MPE_CHAN_MAX - rem) / n_zones - 1;
79 	uint8_t ptr = 0;
80 
81 	mpe->n_zones = n_zones;
82 	zone_t *zones = mpe->zones;
83 	int8_t *channels = mpe->channels;
84 
85 	for(uint8_t i=0;
86 		i<n_zones;
87 		rem--, ptr += 1 + zones[i++].span)
88 	{
89 		zones[i].base = ptr;
90 		zones[i].ref = 0;
91 		zones[i].span = span;
92 		if(rem > 0)
93 			zones[i].span += 1;
94 		zones[i].master_range = handle->state.master_range[i];
95 		zones[i].voice_range = handle->state.voice_range[i];
96 	}
97 
98 	for(uint8_t i=0; i<MPE_CHAN_MAX; i++)
99 		channels[i] = 0;
100 }
101 
102 static inline uint8_t
mpe_acquire(mpe_t * mpe,uint8_t zone_idx)103 mpe_acquire(mpe_t *mpe, uint8_t zone_idx)
104 {
105 	zone_idx %= mpe->n_zones; // wrap around if zone_idx > n_zones
106 	zone_t *zone = &mpe->zones[zone_idx];
107 	int8_t *channels = mpe->channels;
108 
109 	int8_t min = INT8_MAX;
110 	uint8_t pos = zone->ref; // start search at current channel
111 	const uint8_t base_1 = zone->base + 1;
112 	for(uint8_t i = zone->ref; i < zone->ref + zone->span; i++)
113 	{
114 		const uint8_t ch = base_1 + (i % zone->span); // wrap to [0..span]
115 		if(channels[ch] < min) // check for less occupation
116 		{
117 			min = channels[ch]; // lower minimum
118 			pos = i; // set new minimally occupied channel
119 		}
120 	}
121 
122 	const uint8_t ch = base_1 + (pos % zone->span); // wrap to [0..span]
123 	if(channels[ch] <= 0) // off since long
124 		channels[ch] = 1;
125 	else
126 		channels[ch] += 1; // increase occupation
127 	zone->ref = (pos + 1) % zone->span; // start next search from next channel
128 
129 	return ch;
130 }
131 
132 static inline float
mpe_range_1(mpe_t * mpe,uint8_t zone_idx)133 mpe_range_1(mpe_t *mpe, uint8_t zone_idx)
134 {
135 	zone_idx %= mpe->n_zones; // wrap around if zone_idx > n_zones
136 	zone_t *zone = &mpe->zones[zone_idx];
137 	return 1.f / (float)zone->voice_range;
138 }
139 
140 static inline void
mpe_release(mpe_t * mpe,uint8_t zone_idx,uint8_t ch)141 mpe_release(mpe_t *mpe, uint8_t zone_idx, uint8_t ch)
142 {
143 	zone_idx %= mpe->n_zones; // wrap around if zone_idx > n_zones
144 	ch %= MPE_CHAN_MAX; // wrap around if ch > MPE_CHAN_MAX
145 	zone_t *zone = &mpe->zones[zone_idx];
146 	int8_t *channels = mpe->channels;
147 
148 	const uint8_t base_1 = zone->base + 1;
149 	for(uint8_t i = base_1; i < base_1 + zone->span; i++)
150 	{
151 		if( (i == ch) || (channels[i] <= 0) )
152 			channels[i] -= 1;
153 		// do not decrease occupied channels
154 	}
155 }
156 
157 static inline LV2_Atom_Forge_Ref
_midi_event(plughandle_t * handle,int64_t frames,const uint8_t * m,size_t len)158 _midi_event(plughandle_t *handle, int64_t frames, const uint8_t *m, size_t len)
159 {
160 	LV2_Atom_Forge *forge = &handle->forge;
161 	LV2_Atom_Forge_Ref ref;
162 
163 	ref = lv2_atom_forge_frame_time(forge, frames);
164 	if(ref)
165 		ref = lv2_atom_forge_atom(forge, len, handle->uris.midi_MidiEvent);
166 	if(ref)
167 		ref = lv2_atom_forge_write(forge, m, len);
168 
169 	return ref;
170 }
171 
172 static inline LV2_Atom_Forge_Ref
_zone_span_update(plughandle_t * handle,int64_t frames,unsigned zone_idx)173 _zone_span_update(plughandle_t *handle, int64_t frames, unsigned zone_idx)
174 {
175 	LV2_Atom_Forge_Ref fref;
176 	mpe_t *mpe = &handle->mpe;
177 	zone_t *zone = &mpe->zones[zone_idx];
178 	const uint8_t zone_ch = zone->base;
179 
180 	const uint8_t lsb [3] = {
181 		LV2_MIDI_MSG_CONTROLLER | zone_ch,
182 		LV2_MIDI_CTL_RPN_LSB,
183 		0x6 // zone
184 	};
185 
186 	const uint8_t msb [3] = {
187 		LV2_MIDI_MSG_CONTROLLER | zone_ch,
188 		LV2_MIDI_CTL_RPN_MSB,
189 		0x0
190 	};
191 
192 	const uint8_t dat [3] = {
193 		LV2_MIDI_MSG_CONTROLLER | zone_ch,
194 		LV2_MIDI_CTL_MSB_DATA_ENTRY,
195 		zone->span
196 	};
197 
198 	fref = _midi_event(handle, frames, lsb, 3);
199 	if(fref)
200 		fref = _midi_event(handle, frames, msb, 3);
201 	if(fref)
202 		fref = _midi_event(handle, frames, dat, 3);
203 
204 	return fref;
205 }
206 
207 static inline LV2_Atom_Forge_Ref
_master_range_update(plughandle_t * handle,int64_t frames,unsigned zone_idx)208 _master_range_update(plughandle_t *handle, int64_t frames, unsigned zone_idx)
209 {
210 	LV2_Atom_Forge_Ref fref;
211 	mpe_t *mpe = &handle->mpe;
212 	zone_t *zone = &mpe->zones[zone_idx];
213 	const uint8_t zone_ch = zone->base;
214 
215 	const uint8_t lsb [3] = {
216 		LV2_MIDI_MSG_CONTROLLER | zone_ch,
217 		LV2_MIDI_CTL_RPN_LSB,
218 		0x0, // bend range
219 	};
220 
221 	const uint8_t msb [3] = {
222 		LV2_MIDI_MSG_CONTROLLER | zone_ch,
223 		LV2_MIDI_CTL_RPN_MSB,
224 		0x0,
225 	};
226 	const uint8_t dat [3] = {
227 		LV2_MIDI_MSG_CONTROLLER | zone_ch,
228 		LV2_MIDI_CTL_MSB_DATA_ENTRY,
229 		zone->master_range
230 	};
231 
232 	fref = _midi_event(handle, frames, lsb, 3);
233 	if(fref)
234 		fref = _midi_event(handle, frames, msb, 3);
235 	if(fref)
236 		fref = _midi_event(handle, frames, dat, 3);
237 
238 	return fref;
239 }
240 
241 static inline LV2_Atom_Forge_Ref
_voice_range_update(plughandle_t * handle,int64_t frames,unsigned zone_idx)242 _voice_range_update(plughandle_t *handle, int64_t frames, unsigned zone_idx)
243 {
244 	LV2_Atom_Forge_Ref fref;
245 	mpe_t *mpe = &handle->mpe;
246 	zone_t *zone = &mpe->zones[zone_idx];
247 	const uint8_t voice_ch = zone->base + 1;
248 
249 	const uint8_t lsb [3] = {
250 		LV2_MIDI_MSG_CONTROLLER | voice_ch,
251 		LV2_MIDI_CTL_RPN_LSB,
252 		0x0, // bend range
253 	};
254 
255 	const uint8_t msb [3] = {
256 		LV2_MIDI_MSG_CONTROLLER | voice_ch,
257 		LV2_MIDI_CTL_RPN_MSB,
258 		0x0,
259 	};
260 	const uint8_t dat [3] = {
261 		LV2_MIDI_MSG_CONTROLLER | voice_ch,
262 		LV2_MIDI_CTL_MSB_DATA_ENTRY,
263 		zone->voice_range
264 	};
265 
266 	fref = _midi_event(handle, frames, lsb, 3);
267 	if(fref)
268 		fref = _midi_event(handle, frames, msb, 3);
269 	if(fref)
270 		fref = _midi_event(handle, frames, dat, 3);
271 
272 	return fref;
273 }
274 
275 static inline LV2_Atom_Forge_Ref
_full_update(plughandle_t * handle,int64_t frames)276 _full_update(plughandle_t *handle, int64_t frames)
277 {
278 	LV2_Atom_Forge_Ref fref = 1;
279 	mpe_t *mpe = &handle->mpe;
280 
281 	for(unsigned z=0; z<mpe->n_zones; z++)
282 	{
283 		if(fref)
284 			fref = _zone_span_update(handle, frames, z);
285 		if(fref)
286 			fref = _master_range_update(handle, frames, z);
287 		if(fref)
288 			fref = _voice_range_update(handle, frames, z);
289 	}
290 
291 	return fref;
292 }
293 
294 static void
_intercept_zones(void * data,int64_t frames,props_impl_t * impl)295 _intercept_zones(void *data, int64_t frames, props_impl_t *impl)
296 {
297 	plughandle_t *handle = data;
298 
299 	mpe_populate(&handle->mpe, handle->state.zones);
300 	if(handle->ref)
301 		handle->ref = _full_update(handle, frames);
302 }
303 
304 static void
_intercept_master(void * data,int64_t frames,props_impl_t * impl)305 _intercept_master(void *data, int64_t frames, props_impl_t *impl)
306 {
307 	plughandle_t *handle = data;
308 
309 	const int zone_idx = (int32_t *)impl->value.body - handle->state.master_range; //TODO check
310 	handle->mpe.zones[zone_idx].master_range = handle->state.master_range[zone_idx];
311 
312 	if( (zone_idx < handle->state.zones) && handle->ref) // update active zones only
313 		handle->ref = _master_range_update(handle, frames, zone_idx);
314 }
315 
316 static void
_intercept_voice(void * data,int64_t frames,props_impl_t * impl)317 _intercept_voice(void *data, int64_t frames, props_impl_t *impl)
318 {
319 	plughandle_t *handle = data;
320 
321 	const int zone_idx = (int32_t *)impl->value.body - handle->state.voice_range; //TODO check
322 	handle->mpe.zones[zone_idx].voice_range = handle->state.voice_range[zone_idx];
323 
324 	if( (zone_idx < handle->state.zones) && handle->ref) // update active zones only
325 		handle->ref = _voice_range_update(handle, frames, zone_idx);
326 }
327 
328 #define MASTER_RANGE(NUM) \
329 { \
330 	.property = ESPRESSIVO_URI"#mpe_master_range_"#NUM, \
331 	.offset = offsetof(plugstate_t, master_range) + (NUM-1)*sizeof(int32_t), \
332 	.type = LV2_ATOM__Int, \
333 	.event_cb = _intercept_master \
334 }
335 
336 #define VOICE_RANGE(NUM) \
337 { \
338 	.property = ESPRESSIVO_URI"#mpe_voice_range_"#NUM, \
339 	.offset = offsetof(plugstate_t, voice_range) + (NUM-1)*sizeof(int32_t), \
340 	.type = LV2_ATOM__Int, \
341 	.event_cb = _intercept_voice \
342 }
343 
344 #define PRESSURE_CONTROLLER(NUM) \
345 { \
346 	.property = ESPRESSIVO_URI"#mpe_pressure_controller_"#NUM, \
347 	.offset = offsetof(plugstate_t, pressure_controller) + (NUM-1)*sizeof(int32_t), \
348 	.type = LV2_ATOM__Int, \
349 }
350 
351 #define TIMBRE_CONTROLLER(NUM) \
352 { \
353 	.property = ESPRESSIVO_URI"#mpe_timbre_controller_"#NUM, \
354 	.offset = offsetof(plugstate_t, timbre_controller) + (NUM-1)*sizeof(int32_t), \
355 	.type = LV2_ATOM__Int, \
356 }
357 
358 static const props_def_t defs [MAX_NPROPS] = {
359 	{
360 		.property = ESPRESSIVO_URI"#mpe_zones",
361 		.offset = offsetof(plugstate_t, zones),
362 		.type = LV2_ATOM__Int,
363 		.event_cb = _intercept_zones
364 	},
365 	{
366 		.property = ESPRESSIVO_URI"#mpe_velocity",
367 		.offset = offsetof(plugstate_t, velocity),
368 		.type = LV2_ATOM__Int
369 	},
370 
371 	MASTER_RANGE(1),
372 	MASTER_RANGE(2),
373 	MASTER_RANGE(3),
374 	MASTER_RANGE(4),
375 	MASTER_RANGE(5),
376 	MASTER_RANGE(6),
377 	MASTER_RANGE(7),
378 	MASTER_RANGE(8),
379 
380 	VOICE_RANGE(1),
381 	VOICE_RANGE(2),
382 	VOICE_RANGE(3),
383 	VOICE_RANGE(4),
384 	VOICE_RANGE(5),
385 	VOICE_RANGE(6),
386 	VOICE_RANGE(7),
387 	VOICE_RANGE(8),
388 
389 	PRESSURE_CONTROLLER(1),
390 	PRESSURE_CONTROLLER(2),
391 	PRESSURE_CONTROLLER(3),
392 	PRESSURE_CONTROLLER(4),
393 	PRESSURE_CONTROLLER(5),
394 	PRESSURE_CONTROLLER(6),
395 	PRESSURE_CONTROLLER(7),
396 	PRESSURE_CONTROLLER(8),
397 
398 	TIMBRE_CONTROLLER(1),
399 	TIMBRE_CONTROLLER(2),
400 	TIMBRE_CONTROLLER(3),
401 	TIMBRE_CONTROLLER(4),
402 	TIMBRE_CONTROLLER(5),
403 	TIMBRE_CONTROLLER(6),
404 	TIMBRE_CONTROLLER(7),
405 	TIMBRE_CONTROLLER(8)
406 };
407 
408 static inline bool
_notes_enabled(plughandle_t * handle,targetI_t * src)409 _notes_enabled(plughandle_t *handle, targetI_t *src)
410 {
411 	if(handle->state.voice_range[src->zone] >= 0)
412 		return true;
413 
414 	return false;
415 }
416 
417 static inline void
_upd(plughandle_t * handle,int64_t frames,const xpress_state_t * state,float val,targetI_t * src)418 _upd(plughandle_t *handle, int64_t frames, const xpress_state_t *state,
419 	float val, targetI_t *src)
420 {
421 	// bender
422 	if(_notes_enabled(handle, src))
423 	{
424 		const uint16_t bnd = (val - src->key) * mpe_range_1(&handle->mpe, state->zone) * 0x2000 + 0x1fff;
425 		const uint8_t bnd_msb = bnd >> 7;
426 		const uint8_t bnd_lsb = bnd & 0x7f;
427 
428 		const uint8_t bend [3] = {
429 			LV2_MIDI_MSG_BENDER | src->chan,
430 			bnd_lsb,
431 			bnd_msb
432 		};
433 
434 		if(handle->ref)
435 			handle->ref = _midi_event(handle, frames, bend, 3);
436 	}
437 
438 	// pressure
439 	if(handle->state.pressure_controller[state->zone] >= 0)
440 	{
441 		const uint16_t z = state->pressure * 0x3fff;
442 		const uint8_t z_msb = z >> 7;
443 		const uint8_t z_lsb = z & 0x7f;
444 
445 		const uint8_t pressure_lsb [3] = {
446 			LV2_MIDI_MSG_CONTROLLER | src->chan,
447 			handle->state.pressure_controller[state->zone] | 0x20,
448 			z_lsb
449 		};
450 
451 		const uint8_t pressure_msb [3] = {
452 			LV2_MIDI_MSG_CONTROLLER | src->chan,
453 			handle->state.pressure_controller[state->zone],
454 			z_msb
455 		};
456 
457 		if(handle->ref)
458 			handle->ref = _midi_event(handle, frames, pressure_lsb, 3);
459 		if(handle->ref)
460 			handle->ref = _midi_event(handle, frames, pressure_msb, 3);
461 	}
462 
463 	// timbre
464 	if(handle->state.timbre_controller[state->zone] >= 0)
465 	{
466 		float pos2 = state->timbre;
467 		if(pos2 < -1.f) pos2 = -1.f;
468 		else if(pos2 > 1.f) pos2 = 1.f;
469 		const uint16_t vx = (pos2 * 0x2000) + 0x1fff;
470 		const uint8_t vx_msb = vx >> 7;
471 		const uint8_t vx_lsb = vx & 0x7f;
472 
473 		const uint8_t timbre_lsb [3] = {
474 			LV2_MIDI_MSG_CONTROLLER | src->chan,
475 			handle->state.timbre_controller[state->zone] | 0x20,
476 			vx_lsb
477 		};
478 
479 		const uint8_t timbre_msb [3] = {
480 			LV2_MIDI_MSG_CONTROLLER | src->chan,
481 			handle->state.timbre_controller[state->zone],
482 			vx_msb
483 		};
484 
485 		if(handle->ref)
486 			handle->ref = _midi_event(handle, frames, timbre_lsb, 3);
487 		if(handle->ref)
488 			handle->ref = _midi_event(handle, frames, timbre_msb, 3);
489 	}
490 
491 	// FIXME dPitch, dPressure, dTimbre
492 }
493 
494 static void
_add(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)495 _add(void *data, int64_t frames, const xpress_state_t *state,
496 	xpress_uuid_t uuid, void *target)
497 {
498 	plughandle_t *handle = data;
499 	targetI_t *src = target;
500 
501 	const float val = state->pitch * 0x7f;
502 
503 	src->chan = mpe_acquire(&handle->mpe, state->zone);
504 	src->zone = state->zone;
505 	src->key = floor(val);
506 
507 	if(_notes_enabled(handle, src))
508 	{
509 		const uint8_t vel = handle->state.velocity;
510 
511 		const uint8_t note_on [3] = {
512 			LV2_MIDI_MSG_NOTE_ON | src->chan,
513 			src->key,
514 			vel
515 		};
516 
517 		if(handle->ref)
518 			handle->ref = _midi_event(handle, frames, note_on, 3);
519 	}
520 
521 	_upd(handle, frames, state, val, src);
522 }
523 
524 static void
_set(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)525 _set(void *data, int64_t frames, const xpress_state_t *state,
526 	xpress_uuid_t uuid, void *target)
527 {
528 	plughandle_t *handle = data;
529 	targetI_t *src = target;
530 
531 	const float val = state->pitch * 0x7f;
532 
533 	_upd(handle, frames, state, val, src);
534 }
535 
536 static void
_del(void * data,int64_t frames,xpress_uuid_t uuid,void * target)537 _del(void *data, int64_t frames,
538 	xpress_uuid_t uuid, void *target)
539 {
540 	plughandle_t *handle = data;
541 	targetI_t *src = target;
542 
543 	if(_notes_enabled(handle, src))
544 	{
545 		const uint8_t vel = 0x0;
546 
547 		const uint8_t note_off [3] = {
548 			LV2_MIDI_MSG_NOTE_OFF | src->chan,
549 			src->key,
550 			vel
551 		};
552 
553 		if(handle->ref)
554 			handle->ref = _midi_event(handle, frames, note_off, 3);
555 	}
556 
557 	mpe_release(&handle->mpe, src->zone, src->chan);
558 }
559 
560 static const xpress_iface_t ifaceI = {
561 	.size = sizeof(targetI_t),
562 
563 	.add = _add,
564 	.set = _set,
565 	.del = _del
566 };
567 
568 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)569 instantiate(const LV2_Descriptor* descriptor, double rate,
570 	const char *bundle_path, const LV2_Feature *const *features)
571 {
572 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
573 	if(!handle)
574 		return NULL;
575 
576 	xpress_map_t *voice_map = NULL;
577 
578 	for(unsigned i=0; features[i]; i++)
579 	{
580 		if(!strcmp(features[i]->URI, LV2_URID__map))
581 			handle->map = features[i]->data;
582 		else if(!strcmp(features[i]->URI, XPRESS__voiceMap))
583 			voice_map = features[i]->data;
584 	}
585 
586 	if(!handle->map)
587 	{
588 		fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
589 		free(handle);
590 		return NULL;
591 	}
592 
593 	handle->uris.midi_MidiEvent = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
594 
595 	lv2_atom_forge_init(&handle->forge, handle->map);
596 
597 	if(!xpress_init(&handle->xpressI, MAX_NVOICES, handle->map, voice_map,
598 			XPRESS_EVENT_ALL, &ifaceI, handle->targetI, handle))
599 	{
600 		free(handle);
601 		return NULL;
602 	}
603 
604 	if(!props_init(&handle->props, descriptor->URI,
605 		defs, MAX_NPROPS, &handle->state, &handle->stash,
606 		handle->map, handle))
607 	{
608 		free(handle);
609 		return NULL;
610 	}
611 
612 	return handle;
613 }
614 
615 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)616 connect_port(LV2_Handle instance, uint32_t port, void *data)
617 {
618 	plughandle_t *handle = instance;
619 
620 	switch(port)
621 	{
622 		case 0:
623 			handle->event_in = (const LV2_Atom_Sequence *)data;
624 			break;
625 		case 1:
626 			handle->midi_out = (LV2_Atom_Sequence *)data;
627 			break;
628 		default:
629 			break;
630 	}
631 }
632 
633 static void
activate(LV2_Handle instance)634 activate(LV2_Handle instance)
635 {
636 	plughandle_t *handle = instance;
637 
638 	const uint8_t n_zones = 1;
639 	mpe_populate(&handle->mpe, n_zones);
640 }
641 
642 static void
run(LV2_Handle instance,uint32_t nsamples)643 run(LV2_Handle instance, uint32_t nsamples)
644 {
645 	plughandle_t *handle = instance;
646 
647 	// prepare midi atom forge
648 	const uint32_t capacity = handle->midi_out->atom.size;
649 	LV2_Atom_Forge *forge = &handle->forge;
650 	lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->midi_out, capacity);
651 	LV2_Atom_Forge_Frame frame;
652 	handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
653 
654 	props_idle(&handle->props, forge, 0, &handle->ref);
655 	xpress_pre(&handle->xpressI);
656 
657 	LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev)
658 	{
659 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
660 		const int64_t frames = ev->time.frames;
661 
662 		if(!props_advance(&handle->props, forge, frames, obj, &handle->ref))
663 		{
664 			xpress_advance(&handle->xpressI, forge, frames, obj, &handle->ref);
665 		}
666 	}
667 
668 	xpress_post(&handle->xpressI, nsamples-1);
669 
670 	if(handle->ref)
671 		lv2_atom_forge_pop(forge, &frame);
672 	else
673 		lv2_atom_sequence_clear(handle->midi_out);
674 }
675 
676 static void
cleanup(LV2_Handle instance)677 cleanup(LV2_Handle instance)
678 {
679 	plughandle_t *handle = instance;
680 
681 	if(handle)
682 	{
683 		xpress_deinit(&handle->xpressI);
684 		free(handle);
685 	}
686 }
687 
688 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)689 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
690 	LV2_State_Handle state, uint32_t flags,
691 	const LV2_Feature *const *features)
692 {
693 	plughandle_t *handle = instance;
694 
695 	return props_save(&handle->props, store, state, flags, features);
696 }
697 
698 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)699 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
700 	LV2_State_Handle state, uint32_t flags,
701 	const LV2_Feature *const *features)
702 {
703 	plughandle_t *handle = instance;
704 
705 	return props_restore(&handle->props, retrieve, state, flags, features);
706 }
707 
708 static const LV2_State_Interface state_iface = {
709 	.save = _state_save,
710 	.restore = _state_restore
711 };
712 
713 static const void *
extension_data(const char * uri)714 extension_data(const char *uri)
715 {
716 	if(!strcmp(uri, LV2_STATE__interface))
717 		return &state_iface;
718 	return NULL;
719 }
720 
721 const LV2_Descriptor mpe_out = {
722 	.URI						= ESPRESSIVO_MPE_OUT_URI,
723 	.instantiate		= instantiate,
724 	.connect_port		= connect_port,
725 	.activate				= activate,
726 	.run						= run,
727 	.deactivate			= NULL,
728 	.cleanup				= cleanup,
729 	.extension_data	= extension_data
730 };
731