1 /*
2 * Copyright (c) 2015-2021 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 <api_atom.h>
19 #include <api_stash.h>
20
21 #include <inttypes.h>
22 #include <math.h>
23
24 #define LV2_ATOM_VECTOR_BODY_ITEM_CONST(body, i) \
25 (LV2_ATOM_CONTENTS_CONST(LV2_Atom_Vector_Body, (body)) + (i)*(body)->child_size)
26
27 const lua_CFunction upclosures [MOONY_UPCLOSURE_COUNT] = {
28 [MOONY_UPCLOSURE_TUPLE_FOREACH] = _latom_tuple_foreach_itr,
29 [MOONY_UPCLOSURE_VECTOR_FOREACH] = _latom_vec_foreach_itr,
30 [MOONY_UPCLOSURE_OBJECT_FOREACH] = _latom_obj_foreach_itr,
31 [MOONY_UPCLOSURE_SEQUENCE_FOREACH] = _latom_seq_foreach_itr,
32 [MOONY_UPCLOSURE_SEQUENCE_MULTIPLEX] = _latom_seq_multiplex_itr
33 };
34
35 __realtime static inline void
_pushupclosure(lua_State * L,moony_t * moony,moony_upclosure_t type,bool cache)36 _pushupclosure(lua_State *L, moony_t *moony, moony_upclosure_t type, bool cache)
37 {
38 int *upc = &moony->upc[type];
39
40 lua_rawgetp(L, LUA_REGISTRYINDEX, &upclosures[type]); // ref
41 if(lua_rawgeti(L, -1, *upc) == LUA_TNIL) // no cached udata, create one!
42 {
43 #if 0
44 if(moony->log)
45 lv2_log_trace(&moony->logger, "_pushupclosure:\n");
46 #endif
47 lua_pop(L, 1); // nil
48
49 lua_pushlightuserdata(L, moony);
50 _latom_new(L, NULL, false); // place-holder
51 lua_pushcclosure(L, upclosures[type], 2);
52
53 lua_pushvalue(L, -1);
54 lua_rawseti(L, -3, *upc); // store in cache
55 }
56 lua_remove(L, -2); // ref
57 *upc += 1;
58 }
59
60 __realtime int
_latom_clone(lua_State * L)61 _latom_clone(lua_State *L)
62 {
63 latom_t *latom = lua_touserdata(L, 1);
64
65 latom_t *litem = lua_newuserdata(L, sizeof(latom_t) + lv2_atom_total_size(latom->atom));
66 litem->lheader.type = MOONY_UDATA_ATOM;
67 litem->lheader.cache = false;
68 litem->atom = (const LV2_Atom *)litem->payload;
69 litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
70
71 litem->payload->size = latom->atom->size;
72 litem->payload->type = latom->atom->type;
73 memcpy(LV2_ATOM_BODY(litem->payload), latom->body.raw, latom->atom->size);
74
75 luaL_getmetatable(L, "latom");
76 lua_setmetatable(L, -2);
77
78 return 1;
79 }
80
81 __realtime static int
_latom__gc(lua_State * L)82 _latom__gc(lua_State *L)
83 {
84 latom_t *latom = lua_touserdata(L, 1);
85
86 if(latom->lheader.type == MOONY_UDATA_STASH)
87 return _lstash__gc(L);
88
89 return 0;
90 }
91
92 // Nil driver
93 __realtime static int
_latom_nil__len(lua_State * L,latom_t * latom)94 _latom_nil__len(lua_State *L, latom_t *latom)
95 {
96 lua_pushinteger(L, latom->atom->size);
97 return 1;
98 }
99
100 __realtime static int
_latom_nil__tostring(lua_State * L,latom_t * latom)101 _latom_nil__tostring(lua_State *L, latom_t *latom)
102 {
103 lua_pushfstring(L, "(nil: %p)", latom);
104 return 1;
105 }
106
107 __realtime static inline int
_latom_nil_value(lua_State * L,latom_t * latom)108 _latom_nil_value(lua_State *L, latom_t *latom)
109 {
110 lua_pushnil(L);
111 return 1;
112 }
113
114 const latom_driver_t latom_nil_driver = {
115 .__len = _latom_nil__len,
116 .__tostring = _latom_nil__tostring,
117 .value = _latom_nil_value
118 };
119
120 // Int driver
121 __realtime static int
_latom_int__len(lua_State * L,latom_t * latom)122 _latom_int__len(lua_State *L, latom_t *latom)
123 {
124 lua_pushinteger(L, latom->atom->size);
125 return 1;
126 }
127
128 __realtime static int
_latom_int__tostring(lua_State * L,latom_t * latom)129 _latom_int__tostring(lua_State *L, latom_t *latom)
130 {
131 lua_pushfstring(L, "(int: %p, %d)", latom, *latom->body.i32);
132 return 1;
133 }
134
135 __realtime static inline int
_latom_int_value(lua_State * L,latom_t * latom)136 _latom_int_value(lua_State *L, latom_t *latom)
137 {
138 lua_pushinteger(L, *latom->body.i32);
139 return 1;
140 }
141
142 const latom_driver_t latom_int_driver = {
143 .__len = _latom_int__len,
144 .__tostring = _latom_int__tostring,
145 .value = _latom_int_value
146 };
147
148 // Long driver
149 __realtime static int
_latom_long__len(lua_State * L,latom_t * latom)150 _latom_long__len(lua_State *L, latom_t *latom)
151 {
152 lua_pushinteger(L, latom->atom->size);
153 return 1;
154 }
155
156 static int
_latom_long__tostring(lua_State * L,latom_t * latom)157 __realtime _latom_long__tostring(lua_State *L, latom_t *latom)
158 {
159 lua_pushfstring(L, "(long: %p, %d)", latom, *latom->body.i64);
160 return 1;
161 }
162
163 __realtime static inline int
_latom_long_value(lua_State * L,latom_t * latom)164 _latom_long_value(lua_State *L, latom_t *latom)
165 {
166 lua_pushinteger(L, *latom->body.i64);
167 return 1;
168 }
169
170 const latom_driver_t latom_long_driver = {
171 .__len = _latom_long__len,
172 .__tostring = _latom_long__tostring,
173 .value = _latom_long_value
174 };
175
176 // Float driver
177 __realtime static int
_latom_float__len(lua_State * L,latom_t * latom)178 _latom_float__len(lua_State *L, latom_t *latom)
179 {
180 lua_pushinteger(L, latom->atom->size);
181 return 1;
182 }
183
184 __realtime static int
_latom_float__tostring(lua_State * L,latom_t * latom)185 _latom_float__tostring(lua_State *L, latom_t *latom)
186 {
187 lua_pushfstring(L, "(float: %p, %f)", latom, *latom->body.f32);
188 return 1;
189 }
190
191 __realtime static inline int
_latom_float_value(lua_State * L,latom_t * latom)192 _latom_float_value(lua_State *L, latom_t *latom)
193 {
194 lua_pushnumber(L, *latom->body.f32);
195 return 1;
196 }
197
198 const latom_driver_t latom_float_driver = {
199 .__len = _latom_float__len,
200 .__tostring = _latom_float__tostring,
201 .value = _latom_float_value
202 };
203
204 // Double driver
205 __realtime static int
_latom_double__len(lua_State * L,latom_t * latom)206 _latom_double__len(lua_State *L, latom_t *latom)
207 {
208 lua_pushinteger(L, latom->atom->size);
209 return 1;
210 }
211
212 __realtime static int
_latom_double__tostring(lua_State * L,latom_t * latom)213 _latom_double__tostring(lua_State *L, latom_t *latom)
214 {
215 lua_pushfstring(L, "(double: %p, %f)", latom, *latom->body.f64);
216 return 1;
217 }
218
219 __realtime static inline int
_latom_double_value(lua_State * L,latom_t * latom)220 _latom_double_value(lua_State *L, latom_t *latom)
221 {
222 lua_pushnumber(L, *latom->body.f64);
223 return 1;
224 }
225
226 const latom_driver_t latom_double_driver = {
227 .__len = _latom_double__len,
228 .__tostring = _latom_double__tostring,
229 .value = _latom_double_value
230 };
231
232 // Bool driver
233 __realtime static int
_latom_bool__len(lua_State * L,latom_t * latom)234 _latom_bool__len(lua_State *L, latom_t *latom)
235 {
236 lua_pushinteger(L, latom->atom->size);
237 return 1;
238 }
239
240 __realtime static int
_latom_bool__tostring(lua_State * L,latom_t * latom)241 _latom_bool__tostring(lua_State *L, latom_t *latom)
242 {
243 if(*latom->body.i32 == 0)
244 lua_pushfstring(L, "(bool: %p, false)", latom);
245 else
246 lua_pushfstring(L, "(bool: %p, true)", latom);
247 return 1;
248 }
249
250 __realtime static inline int
_latom_bool_value(lua_State * L,latom_t * latom)251 _latom_bool_value(lua_State *L, latom_t *latom)
252 {
253 lua_pushboolean(L, *latom->body.i32);
254 return 1;
255 }
256
257 const latom_driver_t latom_bool_driver = {
258 .__len = _latom_bool__len,
259 .__tostring = _latom_bool__tostring,
260 .value = _latom_bool_value
261 };
262
263 // URID driver
264 __realtime static int
_latom_urid__len(lua_State * L,latom_t * latom)265 _latom_urid__len(lua_State *L, latom_t *latom)
266 {
267 lua_pushinteger(L, latom->atom->size);
268 return 1;
269 }
270
271 __realtime static int
_latom_urid__tostring(lua_State * L,latom_t * latom)272 _latom_urid__tostring(lua_State *L, latom_t *latom)
273 {
274 lua_pushfstring(L, "(URID: %p, %d)", latom, *latom->body.u32);
275 return 1;
276 }
277
278 __realtime static inline int
_latom_urid_value(lua_State * L,latom_t * latom)279 _latom_urid_value(lua_State *L, latom_t *latom)
280 {
281 lua_pushinteger(L, *latom->body.u32);
282 return 1;
283 }
284
285 const latom_driver_t latom_urid_driver = {
286 .__len = _latom_urid__len,
287 .__tostring = _latom_urid__tostring,
288 .value = _latom_urid_value
289 };
290
291 // String driver
292 __realtime static int
_latom_string__len(lua_State * L,latom_t * latom)293 _latom_string__len(lua_State *L, latom_t *latom)
294 {
295 lua_pushinteger(L, latom->atom->size);
296 return 1;
297 }
298
299 __realtime static inline int
_latom_string_value(lua_State * L,latom_t * latom)300 _latom_string_value(lua_State *L, latom_t *latom)
301 {
302 lua_pushlstring(L, latom->body.str, latom->atom->size - 1);
303 return 1;
304 }
305
306 __realtime static int
_latom_string__tostring(lua_State * L,latom_t * latom)307 _latom_string__tostring(lua_State *L, latom_t *latom)
308 {
309 //FIXME URI, Path
310 lua_pushfstring(L, "(string: %p, %s)", latom, latom->body.str);
311 return 1;
312 }
313
314 const latom_driver_t latom_string_driver = {
315 .__len = _latom_string__len,
316 .__tostring = _latom_string__tostring,
317 .value = _latom_string_value
318 };
319
320 // Literal driver
321 __realtime static int
_latom_literal__indexk(lua_State * L,latom_t * latom,const char * key)322 _latom_literal__indexk(lua_State *L, latom_t *latom, const char *key)
323 {
324 if(!strcmp(key, "datatype"))
325 lua_pushinteger(L, latom->body.lit->datatype);
326 else if(!strcmp(key, "lang"))
327 lua_pushinteger(L, latom->body.lit->lang);
328 else
329 lua_pushnil(L);
330 return 1;
331 }
332
333 __realtime static int
_latom_literal_value(lua_State * L,latom_t * latom)334 _latom_literal_value(lua_State *L, latom_t *latom)
335 {
336 lua_pushlstring(L,
337 LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal_Body, latom->body.lit),
338 latom->atom->size - 1 - sizeof(LV2_Atom_Literal_Body));
339 return 1;
340 }
341
342 __realtime static int
_latom_literal__tostring(lua_State * L,latom_t * latom)343 _latom_literal__tostring(lua_State *L, latom_t *latom)
344 {
345 lua_pushfstring(L, "(literal: %p, %s)", latom,
346 LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal_Body, latom->body.lit));
347 return 1;
348 }
349
350 __realtime int
_latom_literal_unpack(lua_State * L)351 _latom_literal_unpack(lua_State *L)
352 {
353 latom_t *latom = lua_touserdata(L, 1);
354 lua_pushlstring(L,
355 LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal_Body, latom->body.lit),
356 latom->atom->size - 1 - sizeof(LV2_Atom_Literal_Body));
357 lua_pushinteger(L, latom->body.lit->datatype);
358 lua_pushinteger(L, latom->body.lit->lang);
359 return 3;
360 }
361
362 const latom_driver_t latom_literal_driver = {
363 .__indexk = _latom_literal__indexk,
364 .__len = _latom_string__len,
365 .__tostring = _latom_literal__tostring,
366 .value = _latom_literal_value,
367 .unpack = _latom_literal_unpack
368 };
369
370 __realtime static int
_latom_tuple__indexi(lua_State * L,latom_t * latom)371 _latom_tuple__indexi(lua_State *L, latom_t *latom)
372 {
373 const int idx = lua_tointeger(L, 2);
374
375 int count = 0;
376 LV2_ATOM_TUPLE_BODY_FOREACH(latom->body.tuple, latom->atom->size, atom)
377 {
378 if(++count == idx)
379 {
380 _latom_new(L, atom, latom->lheader.cache);
381 return 1;
382 }
383 }
384
385 lua_pushnil(L);
386 return 1;
387 }
388
389 __realtime static int
_latom_tuple__len(lua_State * L,latom_t * latom)390 _latom_tuple__len(lua_State *L, latom_t *latom)
391 {
392 int count = 0;
393 LV2_ATOM_TUPLE_BODY_FOREACH(latom->body.tuple, latom->atom->size, atom)
394 ++count;
395
396 lua_pushinteger(L, count);
397 return 1;
398 }
399
400 __realtime static int
_latom_tuple__tostring(lua_State * L,latom_t * latom)401 _latom_tuple__tostring(lua_State *L, latom_t *latom)
402 {
403 lua_pushfstring(L, "(tuple: %p)", latom);
404 return 1;
405 }
406
407 __realtime int
_latom_tuple_unpack(lua_State * L)408 _latom_tuple_unpack(lua_State *L)
409 {
410 latom_t *latom = lua_touserdata(L, 1);
411
412 int n = lua_gettop(L);
413 int min = n > 1
414 ? luaL_checkinteger(L, 2)
415 : 1;
416 int max = n > 2
417 ? luaL_checkinteger(L, 3)
418 : INT_MAX;
419
420 int pos = 1;
421 int count = 0;
422 LV2_ATOM_TUPLE_BODY_FOREACH(latom->body.tuple, latom->atom->size, atom)
423 {
424 if(pos >= min)
425 {
426 if(pos <= max)
427 {
428 _latom_new(L, atom, latom->lheader.cache);
429 count += 1;
430 }
431 else
432 break;
433 }
434
435 pos += 1;
436 }
437
438 return count;
439 }
440
441 static const LV2_Atom nil_atom = {
442 .size = 0,
443 .type = 0
444 };
445
446 __realtime static void
_latom_clear(latom_t * litem)447 _latom_clear(latom_t *litem)
448 {
449 litem->atom = &nil_atom;
450 litem->body.raw = NULL;
451 }
452
453 __realtime int
_latom_tuple_foreach_itr(lua_State * L)454 _latom_tuple_foreach_itr(lua_State *L)
455 {
456 latom_t *latom = lua_touserdata(L, 1);
457 latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
458
459 if(!lv2_atom_tuple_is_end(latom->body.tuple, latom->atom->size, latom->iter.tuple.item))
460 {
461 // push index
462 lua_pushinteger(L, latom->iter.tuple.pos);
463 // push atom
464 lua_pushvalue(L, lua_upvalueindex(2));
465 litem->atom = latom->iter.tuple.item;
466 litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
467
468 // advance iterator
469 latom->iter.tuple.pos += 1;
470 latom->iter.tuple.item = lv2_atom_tuple_next(latom->iter.tuple.item);
471
472 return 2;
473 }
474
475 // end of tuple reached
476 _latom_clear(litem);
477 lua_pushnil(L);
478 return 1;
479 }
480
481 __realtime int
_latom_tuple_foreach(lua_State * L)482 _latom_tuple_foreach(lua_State *L)
483 {
484 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
485 latom_t *latom = lua_touserdata(L, 1);
486
487 // reset iterator to beginning of tuple
488 latom->iter.tuple.pos = 1;
489 latom->iter.tuple.item = latom->body.tuple;
490
491 _pushupclosure(L, moony, MOONY_UPCLOSURE_TUPLE_FOREACH, latom->lheader.cache);
492 lua_pushvalue(L, 1);
493
494 return 2;
495 }
496
497 const latom_driver_t latom_tuple_driver = {
498 .__indexi = _latom_tuple__indexi,
499 .__len = _latom_tuple__len,
500 .__tostring = _latom_tuple__tostring,
501 .unpack = _latom_tuple_unpack,
502 .foreach = _latom_tuple_foreach
503 };
504
505 __realtime static int
_latom_obj__indexi(lua_State * L,latom_t * latom)506 _latom_obj__indexi(lua_State *L, latom_t *latom)
507 {
508 const LV2_URID urid = lua_tointeger(L, 2);
509
510 const LV2_Atom *atom = NULL;
511 lv2_atom_object_body_get(latom->atom->size, latom->body.obj, urid, &atom, 0);
512
513 if(atom) // query returned a matching atom
514 _latom_new(L, atom, latom->lheader.cache);
515 else // query returned no matching atom
516 lua_pushnil(L);
517
518 return 1;
519 }
520
521 __realtime static int
_latom_obj__indexk(lua_State * L,latom_t * latom,const char * key)522 _latom_obj__indexk(lua_State *L, latom_t *latom, const char *key)
523 {
524 if(!strcmp(key, "id"))
525 lua_pushinteger(L, latom->body.obj->id);
526 else if(!strcmp(key, "otype"))
527 lua_pushinteger(L, latom->body.obj->otype);
528 else
529 lua_pushnil(L);
530 return 1;
531 }
532
533 __realtime static int
_latom_obj__len(lua_State * L,latom_t * latom)534 _latom_obj__len(lua_State *L, latom_t *latom)
535 {
536 int count = 0;
537 LV2_ATOM_OBJECT_BODY_FOREACH(latom->body.obj, latom->atom->size, prop)
538 ++count;
539
540 lua_pushinteger(L, count);
541 return 1;
542 }
543
544 __realtime static int
_latom_obj__tostring(lua_State * L,latom_t * latom)545 _latom_obj__tostring(lua_State *L, latom_t *latom)
546 {
547 lua_pushfstring(L, "(object: %p)", latom);
548 return 1;
549 }
550
551 __realtime int
_latom_obj_foreach_itr(lua_State * L)552 _latom_obj_foreach_itr(lua_State *L)
553 {
554 latom_t *latom = lua_touserdata(L, 1);
555 latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
556
557 if(!lv2_atom_object_is_end(latom->body.obj, latom->atom->size, latom->iter.obj.prop))
558 {
559 // push key
560 lua_pushinteger(L, latom->iter.obj.prop->key);
561 // push atom
562
563 lua_pushvalue(L, lua_upvalueindex(2));
564 litem->atom = &latom->iter.obj.prop->value;
565 litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
566
567 // push context
568 lua_pushinteger(L, latom->iter.obj.prop->context);
569
570 // advance iterator
571 latom->iter.obj.prop = lv2_atom_object_next(latom->iter.obj.prop);
572
573 return 3;
574 }
575
576 // end of object reached
577 _latom_clear(litem);
578 lua_pushnil(L);
579 return 1;
580 }
581
582 __realtime int
_latom_obj_foreach(lua_State * L)583 _latom_obj_foreach(lua_State *L)
584 {
585 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
586 latom_t *latom = lua_touserdata(L, 1);
587
588 // reset iterator to beginning of object
589 latom->iter.obj.prop = lv2_atom_object_begin(latom->body.obj);
590
591 _pushupclosure(L, moony, MOONY_UPCLOSURE_OBJECT_FOREACH, latom->lheader.cache);
592 lua_pushvalue(L, 1);
593
594 return 2;
595 }
596
597 const latom_driver_t latom_object_driver = {
598 .__indexi = _latom_obj__indexi,
599 .__indexk = _latom_obj__indexk,
600 .__len = _latom_obj__len,
601 .__tostring = _latom_obj__tostring,
602 .foreach = _latom_obj_foreach
603 };
604
605 __realtime static int
_latom_seq__indexk(lua_State * L,latom_t * latom,const char * key)606 _latom_seq__indexk(lua_State *L, latom_t *latom, const char *key)
607 {
608 if(!strcmp(key, "unit"))
609 lua_pushinteger(L, latom->body.seq->unit);
610 else
611 lua_pushnil(L);
612 return 1;
613 }
614
615 __realtime static int
_latom_seq__indexi(lua_State * L,latom_t * latom)616 _latom_seq__indexi(lua_State *L, latom_t *latom)
617 {
618 int index = lua_tointeger(L, 2); // indexing start from 1
619
620 int count = 0;
621 LV2_ATOM_SEQUENCE_BODY_FOREACH(latom->body.seq, latom->atom->size, ev)
622 {
623 if(++count == index)
624 {
625 _latom_new(L, &ev->body, latom->lheader.cache);
626 return 1;
627 }
628 }
629
630 lua_pushnil(L);
631 return 1;
632 }
633
634 __realtime static int
_latom_seq__len(lua_State * L,latom_t * latom)635 _latom_seq__len(lua_State *L, latom_t *latom)
636 {
637 int count = 0;
638 LV2_ATOM_SEQUENCE_BODY_FOREACH(latom->body.seq, latom->atom->size, ev)
639 ++count;
640
641 lua_pushinteger(L, count);
642 return 1;
643 }
644
645 __realtime static int
_latom_seq__tostring(lua_State * L,latom_t * latom)646 _latom_seq__tostring(lua_State *L, latom_t *latom)
647 {
648 lua_pushfstring(L, "(sequence: %p)", latom);
649 return 1;
650 }
651
652 __realtime int
_latom_seq_multiplex_itr(lua_State * L)653 _latom_seq_multiplex_itr(lua_State *L)
654 {
655 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
656 const unsigned n = lua_rawlen(L, 1);
657 latom_t *latom [n];
658 latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
659
660 // fill latom* array
661 for(unsigned i=0; i<n; i++)
662 {
663 lua_rawgeti(L, 1, 1+i);
664 latom[i] = lua_touserdata(L, -1);
665 }
666 lua_pop(L, n);
667
668 double huge = HUGE_VAL;
669 int nxt = -1;
670 for(unsigned i=0; i<n; i++)
671 {
672 if(lv2_atom_sequence_is_end(latom[i]->body.seq, latom[i]->atom->size, latom[i]->iter.seq.ev))
673 continue;
674
675 if(latom[i]->body.seq->unit == moony->uris.atom_beat_time)
676 {
677 if(latom[i]->iter.seq.ev->time.beats < huge)
678 {
679 huge = latom[i]->iter.seq.ev->time.beats;
680 nxt = i;
681 }
682 }
683 else
684 {
685 if(latom[i]->iter.seq.ev->time.frames < huge)
686 {
687 huge = latom[i]->iter.seq.ev->time.frames;
688 nxt = i;
689 }
690 }
691 }
692
693 if(nxt >= 0) // is there a valid next event?
694 {
695 if(latom[nxt]->body.seq->unit == moony->uris.atom_beat_time)
696 lua_pushnumber(L, latom[nxt]->iter.seq.ev->time.beats);
697 else
698 lua_pushinteger(L, latom[nxt]->iter.seq.ev->time.frames);
699
700 // push atom
701 lua_pushvalue(L, lua_upvalueindex(2));
702 litem->atom = &latom[nxt]->iter.seq.ev->body;
703 litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
704 lua_rawgeti(L, 1, 1+nxt);
705
706 // advance iterator
707 latom[nxt]->iter.seq.ev = lv2_atom_sequence_next(latom[nxt]->iter.seq.ev);
708
709 return 3;
710 }
711
712 // end of sequence reached
713 _latom_clear(litem);
714 lua_pushnil(L);
715 return 1;
716 }
717
718 __realtime static int
_latom_seq_multiplex(lua_State * L,unsigned n)719 _latom_seq_multiplex(lua_State *L, unsigned n)
720 {
721 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
722 latom_t *latom = lua_touserdata(L, 1);
723
724 for(unsigned i=1; i<=n; i++)
725 {
726 latom_t *lmux = lua_touserdata(L, i);
727
728 // reset iterator to beginning of sequence
729 lmux->iter.seq.ev = lv2_atom_sequence_begin(lmux->body.seq);
730 }
731
732 _pushupclosure(L, moony, MOONY_UPCLOSURE_SEQUENCE_MULTIPLEX, latom->lheader.cache);
733
734 lua_createtable(L, n, 0); //FIXME cache this?
735 for(unsigned i=1; i<=n; i++)
736 {
737 lua_pushvalue(L, i);
738 lua_rawseti(L, -2, i);
739 }
740
741 return 2;
742 }
743
744 __realtime int
_latom_seq_foreach_itr(lua_State * L)745 _latom_seq_foreach_itr(lua_State *L)
746 {
747 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
748 latom_t *latom = lua_touserdata(L, 1);
749 latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
750
751 if(!lv2_atom_sequence_is_end(latom->body.seq, latom->atom->size, latom->iter.seq.ev))
752 {
753 if(latom->body.seq->unit == moony->uris.atom_beat_time)
754 lua_pushnumber(L, latom->iter.seq.ev->time.beats);
755 else
756 lua_pushinteger(L, latom->iter.seq.ev->time.frames);
757
758 // push atom
759 lua_pushvalue(L, lua_upvalueindex(2));
760 litem->atom = &latom->iter.seq.ev->body;
761 litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
762
763 // advance iterator
764 latom->iter.seq.ev = lv2_atom_sequence_next(latom->iter.seq.ev);
765
766 return 2;
767 }
768
769 // end of sequence reached
770 _latom_clear(litem);
771 lua_pushnil(L);
772 return 1;
773 }
774
775 __realtime int
_latom_seq_foreach(lua_State * L)776 _latom_seq_foreach(lua_State *L)
777 {
778 const unsigned n = lua_gettop(L);
779 if(n > 1) // multiplex if given any function arguments
780 return _latom_seq_multiplex(L, n);
781
782 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
783 latom_t *latom = lua_touserdata(L, 1);
784
785 // reset iterator to beginning of sequence
786 latom->iter.seq.ev = lv2_atom_sequence_begin(latom->body.seq);
787
788 _pushupclosure(L, moony, MOONY_UPCLOSURE_SEQUENCE_FOREACH, latom->lheader.cache);
789 lua_pushvalue(L, 1);
790
791 return 2;
792 }
793
794 const latom_driver_t latom_sequence_driver = {
795 .__indexk = _latom_seq__indexk,
796 .__indexi = _latom_seq__indexi,
797 .__len = _latom_seq__len,
798 .__tostring = _latom_seq__tostring,
799 .foreach = _latom_seq_foreach
800 };
801
802 __realtime static int
_latom_vec__indexi(lua_State * L,latom_t * latom)803 _latom_vec__indexi(lua_State *L, latom_t *latom)
804 {
805 int index = lua_tointeger(L, 2); // indexing start from 1
806
807 const int count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
808 / latom->body.vec->child_size;
809
810 if( (index > 0) && (index <= count) )
811 {
812 latom_t *litem = _latom_new(L, NULL, latom->lheader.cache);
813 litem->atom = (const LV2_Atom *)latom->body.vec;
814 litem->body.raw = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, index - 1);
815 }
816 else // index is out of bounds
817 lua_pushnil(L);
818
819 return 1;
820 }
821
822 __realtime static int
_latom_vec__indexk(lua_State * L,latom_t * latom,const char * key)823 _latom_vec__indexk(lua_State *L, latom_t *latom, const char *key)
824 {
825 if(!strcmp(key, "childType"))
826 lua_pushinteger(L, latom->body.vec->child_type);
827 else if(!strcmp(key, "childSize"))
828 lua_pushinteger(L, latom->body.vec->child_size);
829 else
830 lua_pushnil(L);
831 return 1;
832 }
833
834 __realtime static int
_latom_vec__len(lua_State * L,latom_t * latom)835 _latom_vec__len(lua_State *L, latom_t *latom)
836 {
837 const int count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
838 / latom->body.vec->child_size;
839
840 lua_pushinteger(L, count);
841 return 1;
842 }
843
844 __realtime static int
_latom_vec__tostring(lua_State * L,latom_t * latom)845 _latom_vec__tostring(lua_State *L, latom_t *latom)
846 {
847 lua_pushfstring(L, "(vector: %p)", latom);
848 return 1;
849 }
850
851 __realtime static int
_latom_vec_value(lua_State * L,latom_t * latom)852 _latom_vec_value(lua_State *L, latom_t *latom)
853 {
854 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
855
856 const int n = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
857 / latom->body.vec->child_size;
858 const void *ptr = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, 0);
859
860 lua_createtable(L, n, 0);
861
862 if(latom->body.vec->child_type == moony->forge.Bool)
863 {
864 const int32_t *i32 = ptr;
865 for(int i=0; i<n; i++)
866 {
867 lua_pushboolean(L, i32[i]);
868 lua_rawseti(L, -2, i+1);
869 }
870 }
871 else if(latom->body.vec->child_type == moony->forge.Int)
872 {
873 const int32_t *i32 = ptr;
874 for(int i=0; i<n; i++)
875 {
876 lua_pushinteger(L, i32[i]);
877 lua_rawseti(L, -2, i+1);
878 }
879 }
880 else if(latom->body.vec->child_type == moony->forge.URID)
881 {
882 const uint32_t *u32 = ptr;
883 for(int i=0; i<n; i++)
884 {
885 lua_pushinteger(L, u32[i]);
886 lua_rawseti(L, -2, i+1);
887 }
888 }
889 else if(latom->body.vec->child_type == moony->forge.Long)
890 {
891 const int64_t *i64 = ptr;
892 for(int i=0; i<n; i++)
893 {
894 lua_pushinteger(L, i64[i]);
895 lua_rawseti(L, -2, i+1);
896 }
897 }
898 else if(latom->body.vec->child_type == moony->forge.Float)
899 {
900 const float *f32 = ptr;
901 for(int i=0; i<n; i++)
902 {
903 lua_pushnumber(L, f32[i]);
904 lua_rawseti(L, -2, i+1);
905 }
906 }
907 else if(latom->body.vec->child_type == moony->forge.Double)
908 {
909 const double *f64 = ptr;
910 for(int i=0; i<n; i++)
911 {
912 lua_pushnumber(L, f64[i]);
913 lua_rawseti(L, -2, i+1);
914 }
915 }
916
917 return 1;
918 }
919
920 __realtime int
_latom_vec_unpack(lua_State * L)921 _latom_vec_unpack(lua_State *L)
922 {
923 latom_t *latom = lua_touserdata(L, 1);
924
925 const int count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
926 / latom->body.vec->child_size;
927
928 const int n = lua_gettop(L);
929 int min = 1;
930 int max = count;
931
932 if(n > 1) // check provided index ranges
933 {
934 min = luaL_checkinteger(L, 2);
935 min = min < 1
936 ? 1
937 : (min > count
938 ? count
939 : min);
940
941 if(n > 2)
942 {
943 max = luaL_checkinteger(L, 3);
944 max = max < 1
945 ? 1
946 : (max > count
947 ? count
948 : max);
949 }
950 }
951
952 for(int i=min; i<=max; i++)
953 {
954 latom_t *litem = _latom_new(L, NULL, latom->lheader.cache);
955 litem->atom = (const LV2_Atom *)latom->body.vec;
956 litem->body.raw = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, i - 1);
957 }
958
959 return max - min + 1;
960 }
961
962 __realtime int
_latom_vec_foreach_itr(lua_State * L)963 _latom_vec_foreach_itr(lua_State *L)
964 {
965 latom_t *latom = lua_touserdata(L, 1);
966 latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
967
968 if(latom->iter.vec.pos < latom->iter.vec.count)
969 {
970 // push index
971 lua_pushinteger(L, latom->iter.vec.pos + 1);
972 // push atom
973 lua_pushvalue(L, lua_upvalueindex(2));
974 litem->atom = (const LV2_Atom *)latom->body.vec;
975 litem->body.raw = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, latom->iter.vec.pos);
976
977 // advance iterator
978 latom->iter.vec.pos += 1;
979
980 return 2;
981 }
982
983 // end of vector reached
984 _latom_clear(litem);
985 lua_pushnil(L);
986 return 1;
987 }
988
989 __realtime int
_latom_vec_foreach(lua_State * L)990 _latom_vec_foreach(lua_State *L)
991 {
992 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
993 latom_t *latom = lua_touserdata(L, 1);
994
995 // reset iterator to beginning of vector
996 latom->iter.vec.count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
997 / latom->body.vec->child_size;
998 latom->iter.vec.pos = 0;
999
1000 _pushupclosure(L, moony, MOONY_UPCLOSURE_VECTOR_FOREACH, latom->lheader.cache);
1001 lua_pushvalue(L, 1);
1002
1003 return 2;
1004 }
1005
1006 const latom_driver_t latom_vector_driver = {
1007 .__indexi = _latom_vec__indexi,
1008 .__indexk = _latom_vec__indexk,
1009 .__len = _latom_vec__len,
1010 .__tostring = _latom_vec__tostring,
1011 .value = _latom_vec_value,
1012 .unpack = _latom_vec_unpack,
1013 .foreach = _latom_vec_foreach
1014 };
1015
1016 __realtime static int
_latom_chunk__indexi(lua_State * L,latom_t * latom)1017 _latom_chunk__indexi(lua_State *L, latom_t *latom)
1018 {
1019 const uint8_t *payload = latom->body.raw;
1020 int index = lua_tointeger(L, 2); // indexing start from 1
1021
1022 if( (index > 0) && (index <= (int)latom->atom->size) )
1023 lua_pushinteger(L, payload[index-1]);
1024 else // index is out of bounds
1025 lua_pushnil(L);
1026
1027 return 1;
1028 }
1029
1030 __realtime static int
_latom_chunk__len(lua_State * L,latom_t * latom)1031 _latom_chunk__len(lua_State *L, latom_t *latom)
1032 {
1033 lua_pushinteger(L, latom->atom->size);
1034 return 1;
1035 }
1036
1037 __realtime static int
_latom_chunk__tostring(lua_State * L,latom_t * latom)1038 _latom_chunk__tostring(lua_State *L, latom_t *latom)
1039 {
1040 lua_pushfstring(L, "(chunk: %p)", latom);
1041 return 1;
1042 }
1043
1044 __realtime static int
_latom_chunk_value(lua_State * L,latom_t * latom)1045 _latom_chunk_value(lua_State *L, latom_t *latom)
1046 {
1047 lua_pushlstring(L, latom->body.raw, latom->atom->size);
1048
1049 return 1;
1050 }
1051
1052 __realtime int
_latom_chunk_unpack(lua_State * L)1053 _latom_chunk_unpack(lua_State *L)
1054 {
1055 latom_t *latom = lua_touserdata(L, 1);
1056 const uint8_t *payload = latom->body.raw;
1057
1058 int n = lua_gettop(L);
1059 int min = 1;
1060 int max = latom->atom->size;
1061
1062 if(n > 1) // check provided index ranges
1063 {
1064 min = luaL_checkinteger(L, 2);
1065 min = min < 1
1066 ? 1
1067 : (min > (int)latom->atom->size
1068 ? (int)latom->atom->size
1069 : min);
1070
1071 if(n > 2)
1072 {
1073 max = luaL_checkinteger(L, 3);
1074 max = max < 1
1075 ? 1
1076 : (max > (int)latom->atom->size
1077 ? (int)latom->atom->size
1078 : max);
1079 }
1080 }
1081
1082 for(int i=min; i<=max; i++)
1083 lua_pushinteger(L, payload[i-1]);
1084
1085 return max - min + 1;
1086 }
1087
1088 const latom_driver_t latom_chunk_driver = {
1089 .__indexi = _latom_chunk__indexi,
1090 .__len = _latom_chunk__len,
1091 .__tostring = _latom_chunk__tostring,
1092 .value = _latom_chunk_value,
1093 .unpack = _latom_chunk_unpack
1094 };
1095
1096 __realtime static int
_latom__index(lua_State * L)1097 _latom__index(lua_State *L)
1098 {
1099 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1100 latom_t *latom = lua_touserdata(L, 1);
1101 const latom_driver_t *driver = _latom_driver(moony, latom->atom->type);
1102
1103 if(driver)
1104 {
1105 const int type = lua_type(L, 2);
1106 if(type == LUA_TSTRING)
1107 {
1108 const char *key = lua_tostring(L, 2);
1109 if(!strcmp(key, "type"))
1110 {
1111 lua_pushinteger(L, latom->atom->type);
1112 return 1;
1113 }
1114 else if(driver->value && !strcmp(key, "body"))
1115 {
1116 return driver->value(L, latom);
1117 }
1118 else if(driver->foreach && !strcmp(key, "foreach"))
1119 {
1120 lua_rawgetp(L, LUA_REGISTRYINDEX, driver->foreach);
1121 return 1;
1122 }
1123 else if(driver->unpack && !strcmp(key, "unpack"))
1124 {
1125 lua_rawgetp(L, LUA_REGISTRYINDEX, driver->unpack);
1126 return 1;
1127 }
1128 else if(!strcmp(key, "clone"))
1129 {
1130 lua_rawgetp(L, LUA_REGISTRYINDEX, _latom_clone);
1131 return 1;
1132 }
1133 else if(!strcmp(key, "raw"))
1134 {
1135 lua_pushlstring(L, latom->body.raw, latom->atom->size);
1136 return 1;
1137 }
1138 else if( (latom->lheader.type == MOONY_UDATA_STASH) && !strcmp(key, "write") )
1139 {
1140 lua_rawgetp(L, LUA_REGISTRYINDEX, _lstash_write);
1141 return 1;
1142 }
1143 else if( (latom->lheader.type == MOONY_UDATA_STASH) && !strcmp(key, "read") )
1144 {
1145 lua_rawgetp(L, LUA_REGISTRYINDEX, _lstash_read);
1146 return 1;
1147 }
1148 else if(driver->__indexk)
1149 {
1150 return driver->__indexk(L, latom, key);
1151 }
1152 }
1153 else if(driver->__indexi && (type == LUA_TNUMBER) )
1154 {
1155 return driver->__indexi(L, latom);
1156 }
1157 }
1158
1159 lua_pushnil(L);
1160 return 1;
1161 }
1162
1163 __realtime static int
_latom__len(lua_State * L)1164 _latom__len(lua_State *L)
1165 {
1166 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1167 latom_t *latom = lua_touserdata(L, 1);
1168 const latom_driver_t *driver = _latom_driver(moony, latom->atom->type);
1169
1170 if(driver && driver->__len)
1171 return driver->__len(L, latom);
1172
1173 lua_pushinteger(L, latom->atom->size);
1174 return 1;
1175 }
1176
1177 __realtime static int
_latom__tostring(lua_State * L)1178 _latom__tostring(lua_State *L)
1179 {
1180 moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1181 latom_t *latom = lua_touserdata(L, 1);
1182 const latom_driver_t *driver = _latom_driver(moony, latom->atom->type);
1183
1184 if(driver && driver->__tostring)
1185 return driver->__tostring(L, latom);
1186
1187 lua_pushnil(L);
1188 return 1;
1189 }
1190
1191 __realtime static int
_latom__eq(lua_State * L)1192 _latom__eq(lua_State *L)
1193 {
1194 //moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1195 latom_t *latom1 = lua_touserdata(L, 1);
1196 latom_t *latom2 = luaL_checkudata(L, 2, "latom");
1197
1198 lua_pushboolean(L,
1199 (latom1->atom->type == latom2->atom->type)
1200 && (latom1->atom->size == latom2->atom->size)
1201 && (memcmp(latom1->body.raw, latom2->body.raw, latom1->atom->size) == 0) );
1202
1203 return 1;
1204 }
1205
1206 const luaL_Reg latom_mt [] = {
1207 {"__index", _latom__index},
1208 {"__len", _latom__len},
1209 {"__tostring", _latom__tostring},
1210 {"__eq", _latom__eq},
1211 {"__gc", _latom__gc},
1212
1213 {NULL, NULL}
1214 };
1215