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