1 /*
2  * Copyright (c) 2016-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 voiceied 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 #ifndef _LV2_XPRESS_H_
19 #define _LV2_XPRESS_H_
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdatomic.h>
28 #include <time.h>
29 #ifndef _WIN32
30 #	include <sys/mman.h>
31 #	include <sys/stat.h>
32 #	include <fcntl.h>
33 #	include <unistd.h>
34 #endif
35 
36 #include <lv2/lv2plug.in/ns/lv2core/lv2.h>
37 #include <lv2/lv2plug.in/ns/ext/urid/urid.h>
38 #include <lv2/lv2plug.in/ns/ext/atom/atom.h>
39 #include <lv2/lv2plug.in/ns/ext/atom/forge.h>
40 
41 /*****************************************************************************
42  * API START
43  *****************************************************************************/
44 
45 #define XPRESS_SHM_ID				"/lv2_xpress_shm"
46 #define XPRESS_URI	  			"http://open-music-kontrollers.ch/lv2/xpress"
47 #define XPRESS_PREFIX				XPRESS_URI"#"
48 
49 // Features
50 #define XPRESS__voiceMap		XPRESS_PREFIX"voiceMap"
51 
52 // Message types
53 #define XPRESS__Token				XPRESS_PREFIX"Token"
54 #define XPRESS__Alive				XPRESS_PREFIX"Alive"
55 
56 // Properties
57 #define XPRESS__source			XPRESS_PREFIX"source"
58 #define XPRESS__uuid				XPRESS_PREFIX"uuid"
59 #define XPRESS__zone				XPRESS_PREFIX"zone"
60 #define XPRESS__body   			XPRESS_PREFIX"body"
61 #define XPRESS__pitch				XPRESS_PREFIX"pitch"
62 #define XPRESS__pressure		XPRESS_PREFIX"pressure"
63 #define XPRESS__timbre			XPRESS_PREFIX"timbre"
64 #define XPRESS__dPitch			XPRESS_PREFIX"dPitch"
65 #define XPRESS__dPressure		XPRESS_PREFIX"dPressure"
66 #define XPRESS__dTimbre			XPRESS_PREFIX"dTimbre"
67 
68 // types
69 typedef uint32_t xpress_uuid_t;
70 
71 // structures
72 typedef struct _xpress_map_t xpress_map_t;
73 typedef struct _xpress_shm_t xpress_shm_t;
74 typedef struct _xpress_state_t xpress_state_t;
75 typedef struct _xpress_voice_t xpress_voice_t;
76 typedef struct _xpress_iface_t xpress_iface_t;
77 typedef struct _xpress_t xpress_t;
78 
79 // function callbacks
80 typedef xpress_uuid_t (*xpress_map_new_uuid_t)(void *handle, uint32_t flag);
81 
82 typedef void (*xpress_add_cb_t)(void *data, int64_t frames,
83 	const xpress_state_t *state, xpress_uuid_t uuid, void *target);
84 
85 typedef xpress_add_cb_t xpress_set_cb_t;
86 
87 typedef void (*xpress_del_cb_t)(void *data, int64_t frames,
88 	xpress_uuid_t uuid, void *target);
89 
90 typedef enum _xpress_event_t {
91 	XPRESS_EVENT_ADD					= (1 << 0),
92 	XPRESS_EVENT_DEL					= (1 << 1),
93 	XPRESS_EVENT_SET					= (1 << 2)
94 } xpress_event_t;
95 
96 #define XPRESS_EVENT_NONE		(0)
97 #define XPRESS_EVENT_ALL		(XPRESS_EVENT_ADD | XPRESS_EVENT_DEL | XPRESS_EVENT_SET)
98 
99 struct _xpress_state_t {
100 	int32_t zone;
101 
102 	float pitch;
103 	float pressure;
104 	float timbre;
105 
106 	float dPitch;
107 	float dPressure;
108 	float dTimbre;
109 };
110 
111 struct _xpress_iface_t {
112 	size_t size;
113 
114 	xpress_add_cb_t add;
115 	xpress_set_cb_t set;
116 	xpress_del_cb_t del;
117 };
118 
119 struct _xpress_voice_t {
120 	LV2_URID source;
121 	xpress_uuid_t uuid;
122 	bool alive;
123 	void *target;
124 };
125 
126 struct _xpress_map_t {
127 	void *handle;
128 	xpress_map_new_uuid_t new_uuid;
129 };
130 
131 struct _xpress_shm_t {
132 	atomic_uint voice_uuid;
133 };
134 
135 struct _xpress_t {
136 	struct {
137 		LV2_URID xpress_Token;
138 		LV2_URID xpress_Alive;
139 
140 		LV2_URID xpress_source;
141 		LV2_URID xpress_uuid;
142 		LV2_URID xpress_zone;
143 		LV2_URID xpress_body;
144 
145 		LV2_URID xpress_pitch;
146 		LV2_URID xpress_pressure;
147 		LV2_URID xpress_timbre;
148 
149 		LV2_URID xpress_dPitch;
150 		LV2_URID xpress_dPressure;
151 		LV2_URID xpress_dTimbre;
152 	} urid;
153 
154 	LV2_URID_Map *map;
155 	xpress_map_t *voice_map;
156 	xpress_shm_t *xpress_shm;
157 	atomic_uint voice_uuid;
158 	bool synced;
159 	xpress_uuid_t source;
160 
161 	xpress_event_t event_mask;
162 	const xpress_iface_t *iface;
163 	void *data;
164 
165 	unsigned max_nvoices;
166 	unsigned nvoices;
167 	xpress_voice_t voices [1];
168 };
169 
170 #define XPRESS_CONCAT_IMPL(X, Y) X##Y
171 #define XPRESS_CONCAT(X, Y) XPRESS_CONCAT_IMPL(X, Y)
172 
173 #define XPRESS_T(XPRESS, MAX_NVOICES) \
174 	xpress_t (XPRESS); \
175 	xpress_voice_t XPRESS_CONCAT(_voices, __COUNTER__) [(MAX_NVOICES - 1)]
176 
177 #define XPRESS_VOICE_FOREACH(XPRESS, VOICE) \
178 	for(xpress_voice_t *(VOICE) = &(XPRESS)->voices[(int)(XPRESS)->nvoices - 1]; \
179 		(VOICE) >= (XPRESS)->voices; \
180 		(VOICE)--)
181 
182 #define XPRESS_VOICE_FREE(XPRESS, VOICE) \
183 	for(xpress_voice_t *(VOICE) = &(XPRESS)->voices[(int)(XPRESS)->nvoices - 1]; \
184 		(VOICE) >= (XPRESS)->voices; \
185 		(VOICE)->uuid = 0, (VOICE)--, (XPRESS)->nvoices--)
186 
187 // non rt-safe
188 static inline int
189 xpress_init(xpress_t *xpress, unsigned max_nvoices, LV2_URID_Map *map,
190 	xpress_map_t *voice_map, xpress_event_t event_mask, const xpress_iface_t *iface,
191 	void *target, void *data);
192 
193 static inline void
194 xpress_deinit(xpress_t *xpress);
195 
196 // rt-safe
197 static inline void *
198 xpress_get(xpress_t *xpress, xpress_uuid_t uuid);
199 
200 // rt-safe
201 static inline int
202 xpress_advance(xpress_t *xpress, LV2_Atom_Forge *forge, uint32_t frames,
203 	const LV2_Atom_Object *obj, LV2_Atom_Forge_Ref *ref);
204 
205 // rt-safe
206 static inline void
207 xpress_pre(xpress_t *xpress);
208 
209 // rt-safe
210 static inline void
211 xpress_rst(xpress_t *xpress);
212 
213 // rt-safe
214 static inline bool
215 xpress_synced(xpress_t *xpress);
216 
217 // rt-safe
218 static inline void
219 xpress_post(xpress_t *xpress, int64_t frames);
220 
221 // rt-safe
222 static inline void *
223 xpress_add(xpress_t *xpress, xpress_uuid_t uuid);
224 
225 // rt-safe
226 static inline void *
227 xpress_create(xpress_t *xpress, xpress_uuid_t *uuid);
228 
229 // rt-safe
230 static inline int
231 xpress_free(xpress_t *xpress, xpress_uuid_t uuid);
232 
233 // rt-safe
234 static inline LV2_Atom_Forge_Ref
235 xpress_token(xpress_t *xpress, LV2_Atom_Forge *forge, uint32_t frames,
236 	xpress_uuid_t uuid, const xpress_state_t *state);
237 
238 // rt-safe
239 static inline LV2_Atom_Forge_Ref
240 xpress_alive(xpress_t *xpress, LV2_Atom_Forge *forge, uint32_t frames);
241 
242 // rt-safe
243 static inline int32_t
244 xpress_map(xpress_t *xpress);
245 
246 /*****************************************************************************
247  * API END
248  *****************************************************************************/
249 
250 static const xpress_state_t xpress_vanilla;
251 
252 //tools.ietf.org/html/rfc4122 version 4
253 static LV2_URID
_xpress_urn_uuid(LV2_URID_Map * map)254 _xpress_urn_uuid(LV2_URID_Map *map)
255 {
256 	uint8_t bytes [0x10];
257 
258 	for(unsigned i=0x0; i<0x10; i++)
259 		bytes[i] = rand() & 0xff;
260 
261 	bytes[6] = (bytes[6] & 0x0f) | 0x40; // set four most significant bits of 7th byte to 0b0100
262 	bytes[8] = (bytes[8] & 0x3f) | 0x80; // set two most significant bits of 9th byte to 0b10
263 
264 	char uuid [46];
265 	snprintf(uuid, sizeof(uuid),
266 		"urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
267 		bytes[0x0], bytes[0x1], bytes[0x2], bytes[0x3],
268 		bytes[0x4], bytes[0x5],
269 		bytes[0x6], bytes[0x7],
270 		bytes[0x8], bytes[0x9],
271 		bytes[0xa], bytes[0xb], bytes[0xc], bytes[0xd], bytes[0xe], bytes[0xf]);
272 
273 	return map->map(map->handle, uuid);
274 }
275 
276 static inline void
_xpress_qsort(xpress_voice_t * A,int n)277 _xpress_qsort(xpress_voice_t *A, int n)
278 {
279 	if(n < 2)
280 		return;
281 
282 	const xpress_voice_t *p = A;
283 
284 	int i = -1;
285 	int j = n;
286 
287 	while(true)
288 	{
289 		do {
290 			i += 1;
291 		} while(A[i].uuid > p->uuid);
292 
293 		do {
294 			j -= 1;
295 		} while(A[j].uuid < p->uuid);
296 
297 		if(i >= j)
298 			break;
299 
300 		const xpress_voice_t tmp = A[i];
301 		A[i] = A[j];
302 		A[j] = tmp;
303 	}
304 
305 	_xpress_qsort(A, j + 1);
306 	_xpress_qsort(A + j + 1, n - j - 1);
307 }
308 
309 static inline xpress_voice_t *
_xpress_bsearch(xpress_uuid_t p,xpress_voice_t * a,int n)310 _xpress_bsearch(xpress_uuid_t p, xpress_voice_t *a, int n)
311 {
312 	xpress_voice_t *base = a;
313 
314 	for(int N = n, half; N > 1; N -= half)
315 	{
316 		half = N/2;
317 		xpress_voice_t *dst = &base[half];
318 		base = (dst->uuid < p) ? base : dst;
319 	}
320 
321 	return (base->uuid == p) ? base : NULL;
322 }
323 
324 static inline void
_xpress_sort(xpress_t * xpress)325 _xpress_sort(xpress_t *xpress)
326 {
327 	_xpress_qsort(xpress->voices, xpress->nvoices);
328 }
329 
330 static inline xpress_voice_t *
_xpress_voice_get(xpress_t * xpress,xpress_uuid_t uuid)331 _xpress_voice_get(xpress_t *xpress, xpress_uuid_t uuid)
332 {
333 	return _xpress_bsearch(uuid, xpress->voices, xpress->nvoices);
334 }
335 
336 static inline void *
_xpress_voice_add(xpress_t * xpress,LV2_URID source,xpress_uuid_t uuid,bool alive)337 _xpress_voice_add(xpress_t *xpress, LV2_URID source, xpress_uuid_t uuid, bool alive)
338 {
339 	if(xpress->nvoices >= xpress->max_nvoices)
340 		return NULL; // failed
341 
342 	xpress_voice_t *voice = &xpress->voices[xpress->nvoices++];
343 	voice->source = source;
344 	voice->uuid = uuid;
345 	voice->alive = alive;
346 	void *target = voice->target;
347 
348 	_xpress_sort(xpress);
349 
350 	return target;
351 }
352 
353 static inline void
_xpress_voice_free(xpress_t * xpress,xpress_voice_t * voice)354 _xpress_voice_free(xpress_t *xpress, xpress_voice_t *voice)
355 {
356 	voice->uuid = 0;
357 
358 	_xpress_sort(xpress);
359 
360 	xpress->nvoices--;
361 }
362 
363 static xpress_shm_t *
_xpress_shm_init()364 _xpress_shm_init()
365 {
366 	xpress_shm_t *xpress_shm = NULL;
367 #ifndef _WIN32
368 	const size_t total_size = sizeof(xpress_shm_t);
369 
370 	bool is_first = true;
371 	int fd = shm_open(XPRESS_SHM_ID, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
372 
373 	if(fd == -1)
374 	{
375 		is_first = false;
376 		fd = shm_open(XPRESS_SHM_ID, O_RDWR, S_IRUSR | S_IWUSR);
377 	}
378 
379 	if(fd == -1)
380 	{
381 		return NULL;
382 	}
383 
384 	if(  (ftruncate(fd, total_size) == -1)
385 		|| ((xpress_shm = mmap(NULL, total_size, PROT_READ | PROT_WRITE,
386 					MAP_SHARED, fd, 0)) == MAP_FAILED) )
387 	{
388 		close(fd);
389 		return NULL;
390 	}
391 
392 	close(fd);
393 
394 	if(is_first)
395 	{
396 		atomic_init(&xpress_shm->voice_uuid, 1);
397 	}
398 #endif
399 
400 	return xpress_shm;
401 }
402 
403 static void
_xpress_shm_deinit(xpress_shm_t * xpress_shm)404 _xpress_shm_deinit(xpress_shm_t *xpress_shm)
405 {
406 #ifndef _WIN32
407 	const size_t total_size = sizeof(xpress_shm_t);
408 
409 	munmap(xpress_shm, total_size);
410 #else
411 	(void)xpress_shm;
412 #endif
413 }
414 
415 static inline int
xpress_init(xpress_t * xpress,unsigned max_nvoices,LV2_URID_Map * map,xpress_map_t * voice_map,xpress_event_t event_mask,const xpress_iface_t * iface,void * target,void * data)416 xpress_init(xpress_t *xpress, unsigned max_nvoices, LV2_URID_Map *map,
417 	xpress_map_t *voice_map, xpress_event_t event_mask, const xpress_iface_t *iface,
418 	void *target, void *data)
419 {
420 	if(!map || ( (event_mask != XPRESS_EVENT_NONE) && !iface))
421 		return 0;
422 
423 	xpress->nvoices = 0;
424 	xpress->max_nvoices = max_nvoices;
425 	xpress->map = map;
426 	xpress->voice_map = voice_map;
427 	xpress->event_mask = event_mask;
428 	xpress->iface = iface;
429 	xpress->data = data;
430 
431 	xpress->urid.xpress_Token = map->map(map->handle, XPRESS__Token);
432 	xpress->urid.xpress_Alive = map->map(map->handle, XPRESS__Alive);
433 
434 	xpress->urid.xpress_source = map->map(map->handle, XPRESS__source);
435 	xpress->urid.xpress_uuid = map->map(map->handle, XPRESS__uuid);
436 	xpress->urid.xpress_zone = map->map(map->handle, XPRESS__zone);
437 
438 	xpress->urid.xpress_body = map->map(map->handle, XPRESS__body);
439 
440 	xpress->urid.xpress_pitch = map->map(map->handle, XPRESS__pitch);
441 	xpress->urid.xpress_pressure = map->map(map->handle, XPRESS__pressure);
442 	xpress->urid.xpress_timbre = map->map(map->handle, XPRESS__timbre);
443 
444 	xpress->urid.xpress_dPitch = map->map(map->handle, XPRESS__dPitch);
445 	xpress->urid.xpress_dPressure = map->map(map->handle, XPRESS__dPressure);
446 	xpress->urid.xpress_dTimbre = map->map(map->handle, XPRESS__dTimbre);
447 
448 	for(unsigned i = 0; i < xpress->max_nvoices; i++)
449 	{
450 		xpress_voice_t *voice = &xpress->voices[i];
451 
452 		voice->uuid = 0;
453 		voice->target = target && iface
454 			? (uint8_t *)target + i*iface->size
455 			: NULL;
456 	}
457 
458 	xpress->source = _xpress_urn_uuid(map);
459 
460 	if(!xpress->voice_map)
461 	{
462 		// fall-back to shared memory
463 		xpress->xpress_shm = _xpress_shm_init();
464 
465 		if(!xpress->xpress_shm)
466 		{
467 			// fall-back to local memory
468 			const uint32_t pseudo_unique =  (const uintptr_t)xpress;
469 			atomic_init(&xpress->voice_uuid, pseudo_unique);
470 		}
471 	}
472 
473 	return 1;
474 }
475 
476 static inline void
xpress_deinit(xpress_t * xpress)477 xpress_deinit(xpress_t *xpress)
478 {
479 	if(xpress->xpress_shm)
480 	{
481 		_xpress_shm_deinit(xpress->xpress_shm);
482 	}
483 }
484 
485 static inline void *
xpress_get(xpress_t * xpress,xpress_uuid_t uuid)486 xpress_get(xpress_t *xpress, xpress_uuid_t uuid)
487 {
488 	xpress_voice_t *voice = _xpress_voice_get(xpress, uuid);
489 	if(voice)
490 		return voice->target;
491 
492 	return NULL;
493 }
494 
495 static inline int
xpress_advance(xpress_t * xpress,LV2_Atom_Forge * forge,uint32_t frames,const LV2_Atom_Object * obj,LV2_Atom_Forge_Ref * ref)496 xpress_advance(xpress_t *xpress, LV2_Atom_Forge *forge, uint32_t frames,
497 	const LV2_Atom_Object *obj, LV2_Atom_Forge_Ref *ref __attribute__((unused)))
498 {
499 	if(!lv2_atom_forge_is_object_type(forge, obj->atom.type))
500 		return 0;
501 
502 	if(obj->body.otype == xpress->urid.xpress_Token)
503 	{
504 		const LV2_Atom_URID *source = NULL;
505 		const LV2_Atom_Int *uuid = NULL;
506 		const LV2_Atom_Int *zone = NULL;
507 		const LV2_Atom_Float *pitch = NULL;
508 		const LV2_Atom_Float *pressure = NULL;
509 		const LV2_Atom_Float *timbre = NULL;
510 		const LV2_Atom_Float *dPitch = NULL;
511 		const LV2_Atom_Float *dPressure = NULL;
512 		const LV2_Atom_Float *dTimbre = NULL;
513 
514 		lv2_atom_object_get(obj,
515 			xpress->urid.xpress_source, &source,
516 			xpress->urid.xpress_uuid, &uuid,
517 			xpress->urid.xpress_zone, &zone,
518 			xpress->urid.xpress_pitch, &pitch,
519 			xpress->urid.xpress_pressure, &pressure,
520 			xpress->urid.xpress_timbre, &timbre,
521 			xpress->urid.xpress_dPitch, &dPitch,
522 			xpress->urid.xpress_dPressure, &dPressure,
523 			xpress->urid.xpress_dTimbre, &dTimbre,
524 			0);
525 
526 		if(  !source || (source->atom.type != forge->URID)
527 			|| !uuid || (uuid->atom.type != forge->Int) )
528 		{
529 			return 0;
530 		}
531 
532 		bool added;
533 		xpress_voice_t *voice = _xpress_voice_get(xpress, uuid->body);
534 		void *target;
535 		if(voice)
536 		{
537 			target = voice->target;
538 
539 			added = false;
540 		}
541 		else
542 		{
543 			if(!(target = _xpress_voice_add(xpress, source->body, uuid->body, false)))
544 				return 0;
545 
546 			added = true;
547 		}
548 
549 		xpress_state_t state = xpress_vanilla;
550 		if(zone && (zone->atom.type == forge->Int))
551 			state.zone = zone->body;
552 		if(pitch && (pitch->atom.type == forge->Float))
553 			state.pitch = pitch->body;
554 		if(pressure && (pressure->atom.type == forge->Float))
555 			state.pressure = pressure->body;
556 		if(timbre && (timbre->atom.type == forge->Float))
557 			state.timbre = timbre->body;
558 		if(dPitch && (dPitch->atom.type == forge->Float))
559 			state.dPitch = dPitch->body;
560 		if(dPressure && (dPressure->atom.type == forge->Float))
561 			state.dPressure = dPressure->body;
562 		if(dTimbre && (dTimbre->atom.type == forge->Float))
563 			state.dTimbre = dTimbre->body;
564 
565 		if(added)
566 		{
567 			if( (xpress->event_mask & XPRESS_EVENT_ADD) && xpress->iface->add)
568 				xpress->iface->add(xpress->data, frames, &state, uuid->body, target);
569 		}
570 		else
571 		{
572 			if( (xpress->event_mask & XPRESS_EVENT_SET) && xpress->iface->set)
573 				xpress->iface->set(xpress->data, frames, &state, uuid->body, target);
574 		}
575 
576 		return 1;
577 	}
578 	else if(obj->body.otype == xpress->urid.xpress_Alive)
579 	{
580 		const LV2_Atom_URID *source = NULL;
581 		const LV2_Atom_Tuple *body = NULL;
582 
583 		lv2_atom_object_get(obj,
584 			xpress->urid.xpress_source, &source,
585 			xpress->urid.xpress_body, &body,
586 			0);
587 
588 		if(  !source || (source->atom.type != forge->URID) )
589 			return 0;
590 
591 		if(body && (body->atom.type == forge->Tuple) ) // non-existent body is a valid empty body
592 		{
593 			LV2_ATOM_TUPLE_FOREACH(body, item)
594 			{
595 				const LV2_Atom_Int *uuid = (const LV2_Atom_Int *)item;
596 
597 				if(uuid->atom.type == forge->Int)
598 				{
599 					xpress_voice_t *voice = _xpress_voice_get(xpress, uuid->body);
600 					if(voice)
601 					{
602 						voice->alive = true;
603 					}
604 					else
605 					{
606 						void *target = _xpress_voice_add(xpress, source->body, uuid->body, true);
607 						if(target)
608 						{
609 							xpress_state_t state = xpress_vanilla;
610 							if( (xpress->event_mask & XPRESS_EVENT_ADD) && xpress->iface->add)
611 								xpress->iface->add(xpress->data, frames, &state, uuid->body, target);
612 						}
613 					}
614 				}
615 			}
616 		}
617 
618 		unsigned freed = 0;
619 
620 		XPRESS_VOICE_FOREACH(xpress, voice)
621 		{
622 			if(  (voice->source == source->body)
623 				&& !voice->alive )
624 			{
625 				if( (xpress->event_mask & XPRESS_EVENT_DEL) && xpress->iface->del)
626 					xpress->iface->del(xpress->data, frames, voice->uuid, voice->target);
627 
628 				freed += 1;
629 				voice->uuid = 0; // invalidate
630 			}
631 		}
632 
633 		if(freed > 0)
634 		{
635 			_xpress_sort(xpress);
636 			xpress->nvoices -= freed;
637 		}
638 
639 		return 1;
640 	}
641 
642 	return 0; // did not handle a patch event
643 }
644 
645 static inline void
xpress_pre(xpress_t * xpress)646 xpress_pre(xpress_t *xpress)
647 {
648 	XPRESS_VOICE_FOREACH(xpress, voice)
649 	{
650 		voice->alive = false;
651 	}
652 }
653 
654 static inline void
xpress_rst(xpress_t * xpress)655 xpress_rst(xpress_t *xpress)
656 {
657 	xpress->synced = false; // e.g. needs an xpress#alive
658 }
659 
660 static inline bool
xpress_synced(xpress_t * xpress)661 xpress_synced(xpress_t *xpress)
662 {
663 	return xpress->synced;
664 }
665 
666 static inline void
xpress_post(xpress_t * xpress,int64_t frames)667 xpress_post(xpress_t *xpress, int64_t frames)
668 {
669 	unsigned freed = 0;
670 
671 	XPRESS_VOICE_FOREACH(xpress, voice)
672 	{
673 		if(!voice->alive)
674 		{
675 			if( (xpress->event_mask & XPRESS_EVENT_DEL) && xpress->iface->del)
676 				xpress->iface->del(xpress->data, frames, voice->uuid, voice->target);
677 
678 			freed += 1;
679 			voice->uuid = 0; // invalidate
680 		}
681 	}
682 
683 	if(freed > 0)
684 	{
685 		_xpress_sort(xpress);
686 		xpress->nvoices -= freed;
687 	}
688 }
689 
690 static inline void *
xpress_add(xpress_t * xpress,xpress_uuid_t uuid)691 xpress_add(xpress_t *xpress, xpress_uuid_t uuid)
692 {
693 	return _xpress_voice_add(xpress, xpress->source, uuid, false);
694 }
695 
696 static inline void *
xpress_create(xpress_t * xpress,xpress_uuid_t * uuid)697 xpress_create(xpress_t *xpress, xpress_uuid_t *uuid)
698 {
699 	*uuid = xpress_map(xpress);
700 
701 	return xpress_add(xpress, *uuid);
702 }
703 
704 static inline int
xpress_free(xpress_t * xpress,xpress_uuid_t uuid)705 xpress_free(xpress_t *xpress, xpress_uuid_t uuid)
706 {
707 	xpress_voice_t *voice = _xpress_voice_get(xpress, uuid);
708 	if(!voice)
709 		return 0; // failed
710 
711 	_xpress_voice_free(xpress, voice);
712 
713 	return 1;
714 }
715 
716 static inline LV2_Atom_Forge_Ref
xpress_token(xpress_t * xpress,LV2_Atom_Forge * forge,uint32_t frames,xpress_uuid_t uuid,const xpress_state_t * state)717 xpress_token(xpress_t *xpress, LV2_Atom_Forge *forge, uint32_t frames,
718 	xpress_uuid_t uuid, const xpress_state_t *state)
719 {
720 	LV2_Atom_Forge_Frame obj_frame;
721 
722 	LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, frames);
723 
724 	if(ref)
725 		ref = lv2_atom_forge_object(forge, &obj_frame, 0, xpress->urid.xpress_Token);
726 	{
727 		if(ref)
728 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_source);
729 		if(ref)
730 			ref = lv2_atom_forge_urid(forge, xpress->source);
731 
732 		if(ref)
733 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_uuid);
734 		if(ref)
735 			ref = lv2_atom_forge_int(forge, uuid);
736 
737 		if(ref)
738 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_zone);
739 		if(ref)
740 			ref = lv2_atom_forge_int(forge, state->zone);
741 
742 		if(ref)
743 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_pitch);
744 		if(ref)
745 			ref = lv2_atom_forge_float(forge, state->pitch);
746 
747 		if(ref)
748 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_pressure);
749 		if(ref)
750 			ref = lv2_atom_forge_float(forge, state->pressure);
751 
752 		if(ref)
753 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_timbre);
754 		if(ref)
755 			ref = lv2_atom_forge_float(forge, state->timbre);
756 
757 		if(ref)
758 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_dPitch);
759 		if(ref)
760 			ref = lv2_atom_forge_float(forge, state->dPitch);
761 
762 		if(ref)
763 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_dPressure);
764 		if(ref)
765 			ref = lv2_atom_forge_float(forge, state->dPressure);
766 
767 		if(ref)
768 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_dTimbre);
769 		if(ref)
770 			ref = lv2_atom_forge_float(forge, state->dTimbre);
771 	}
772 	if(ref)
773 		lv2_atom_forge_pop(forge, &obj_frame);
774 
775 	xpress->synced = false; // e.g. needs an xpress#alive
776 
777 	return ref;
778 }
779 
780 static inline LV2_Atom_Forge_Ref
xpress_alive(xpress_t * xpress,LV2_Atom_Forge * forge,uint32_t frames)781 xpress_alive(xpress_t *xpress, LV2_Atom_Forge *forge, uint32_t frames)
782 {
783 	LV2_Atom_Forge_Frame obj_frame;
784 	LV2_Atom_Forge_Frame tup_frame;
785 
786 	LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, frames);
787 
788 	if(ref)
789 		ref = lv2_atom_forge_object(forge, &obj_frame, 0, xpress->urid.xpress_Alive);
790 	{
791 		if(ref)
792 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_source);
793 		if(ref)
794 			ref = lv2_atom_forge_urid(forge, xpress->source);
795 
796 		if(ref)
797 			ref = lv2_atom_forge_key(forge, xpress->urid.xpress_body);
798 		if(ref)
799 			ref = lv2_atom_forge_tuple(forge, &tup_frame);
800 		{
801 			XPRESS_VOICE_FOREACH(xpress, voice)
802 			{
803 				if(ref)
804 					ref = lv2_atom_forge_int(forge, voice->uuid);
805 			}
806 		}
807 		if(ref)
808 			lv2_atom_forge_pop(forge, &tup_frame);
809 	}
810 	if(ref)
811 		lv2_atom_forge_pop(forge, &obj_frame);
812 
813 	xpress->synced = true;
814 
815 	return ref;
816 }
817 
818 static inline int32_t
xpress_map(xpress_t * xpress)819 xpress_map(xpress_t *xpress)
820 {
821 	if(xpress->voice_map)
822 	{
823 		xpress_map_t *voice_map = xpress->voice_map;
824 
825 		return voice_map->new_uuid(voice_map->handle, 0);
826 	}
827 	else if(xpress->xpress_shm)
828 	{
829 		xpress_shm_t *xpress_shm = xpress->xpress_shm;
830 
831 		return atomic_fetch_add_explicit(&xpress_shm->voice_uuid, 1, memory_order_relaxed);
832 	}
833 
834 	// fall-back
835 	return atomic_fetch_add_explicit(&xpress->voice_uuid, 1, memory_order_relaxed);
836 }
837 
838 #ifdef __cplusplus
839 }
840 #endif
841 
842 #endif // _LV2_XPRESS_H_
843