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 <moony.h>
19 #include <api_atom.h>
20 #include <api_forge.h>
21
22 #include <lauxlib.h>
23
24 #define BUF_SIZE 8192
25 #define MAX_URIDS 512
26
27 typedef struct _urid_t urid_t;
28 typedef struct _handle_t handle_t;
29
30 struct _urid_t {
31 LV2_URID urid;
32 char *uri;
33 };
34
35 struct _handle_t {
36 moony_t moony;
37
38 const LV2_Worker_Interface *iface;
39
40 LV2_Atom_Forge forge;
41
42 uint8_t buf [BUF_SIZE] __attribute__((aligned(8)));
43 uint8_t buf2 [BUF_SIZE] __attribute__((aligned(8)));
44
45 urid_t urids [MAX_URIDS];
46 LV2_URID urid;
47 };
48
49 __non_realtime static int
_test(lua_State * L)50 _test(lua_State *L)
51 {
52 handle_t *handle = lua_touserdata(L, lua_upvalueindex(1));
53 const size_t buf_size = lua_tointeger(L, lua_upvalueindex(2));
54
55 if(!lua_isfunction(L, 1) || !lua_isfunction(L, 2))
56 {
57 fprintf(stderr, "err: expected 2 function arguments\n");
58 exit(-1);
59 }
60
61 LV2_Atom_Forge *forge = &handle->forge;
62 LV2_Atom_Forge_Frame frame;
63
64 // produce events
65 lv2_atom_forge_set_buffer(forge, handle->buf, buf_size);
66 lv2_atom_forge_sequence_head(forge, &frame, 0);
67 {
68 lua_pushvalue(L, 1); // producer
69
70 lforge_t *lforge = moony_newuserdata(L, &handle->moony, MOONY_UDATA_FORGE, true);
71 lforge->depth = 0;
72 lforge->last.frames = 0;
73 lforge->forge = forge;
74
75 lua_call(L, 1, 0);
76 }
77 if(&frame != forge->stack)
78 fprintf(stderr, "forge frame mismatch\n");
79 else
80 lv2_atom_forge_pop(forge, &frame);
81
82 // consume events
83 lv2_atom_forge_set_buffer(forge, handle->buf2, buf_size);
84 lv2_atom_forge_sequence_head(forge, &frame, 0);
85 {
86 lua_pushvalue(L, 2); // consumer
87
88 latom_t *latom = moony_newuserdata(L, &handle->moony, MOONY_UDATA_ATOM, true);
89 latom->atom = (const LV2_Atom *)handle->buf;
90 latom->body.raw = LV2_ATOM_BODY_CONST(latom->atom);
91
92 lforge_t *lframe = moony_newuserdata(L, &handle->moony, MOONY_UDATA_FORGE, true);
93 lframe->depth = 0;
94 lframe->last.frames = 0;
95 lframe->forge = forge;
96
97 lua_call(L, 2, 0);
98 }
99 if(&frame != forge->stack)
100 fprintf(stderr, "forge frame mismatch\n");
101 else
102 lv2_atom_forge_pop(forge, &frame);
103
104 return 0;
105 }
106
107 __non_realtime static LV2_URID
_map(LV2_URID_Map_Handle instance,const char * uri)108 _map(LV2_URID_Map_Handle instance, const char *uri)
109 {
110 handle_t *handle = instance;
111
112 urid_t *itm;
113 for(itm=handle->urids; itm->urid; itm++)
114 {
115 if(!strcmp(itm->uri, uri))
116 return itm->urid;
117 }
118
119 assert(handle->urid + 1 < MAX_URIDS);
120
121 // create new
122 itm->urid = ++handle->urid;
123 itm->uri = strdup(uri);
124
125 return itm->urid;
126 }
127
128 __non_realtime static const char *
_unmap(LV2_URID_Unmap_Handle instance,LV2_URID urid)129 _unmap(LV2_URID_Unmap_Handle instance, LV2_URID urid)
130 {
131 handle_t *handle = instance;
132
133 urid_t *itm;
134 for(itm=handle->urids; itm->urid; itm++)
135 {
136 if(itm->urid == urid)
137 return itm->uri;
138 }
139
140 // not found
141 return NULL;
142 }
143
144 __non_realtime static LV2_Worker_Status
_respond(LV2_Worker_Respond_Handle instance,uint32_t size,const void * data)145 _respond(LV2_Worker_Respond_Handle instance, uint32_t size, const void *data)
146 {
147 handle_t *handle = instance;
148
149 return handle->iface->work_response(&handle->moony, size, data);
150 }
151
152 __non_realtime static LV2_Worker_Status
_sched(LV2_Worker_Schedule_Handle instance,uint32_t size,const void * data)153 _sched(LV2_Worker_Schedule_Handle instance, uint32_t size, const void *data)
154 {
155 handle_t *handle = instance;
156
157 LV2_Worker_Status status = LV2_WORKER_SUCCESS;
158 status |= handle->iface->work(&handle->moony, _respond, handle, size, data);
159 status |= handle->iface->end_run(&handle->moony);
160
161 return status;
162 }
163
164 __non_realtime static int
_vprintf(void * data,LV2_URID type,const char * fmt,va_list args)165 _vprintf(void *data, LV2_URID type, const char *fmt, va_list args)
166 {
167 vfprintf(stderr, fmt, args);
168
169 return 0;
170 }
171
172 __non_realtime static int
_printf(void * data,LV2_URID type,const char * fmt,...)173 _printf(void *data, LV2_URID type, const char *fmt, ...)
174 {
175 va_list args;
176 int ret;
177
178 va_start (args, fmt);
179 ret = _vprintf(data, type, fmt, args);
180 va_end(args);
181
182 return ret;
183 }
184
185 static double
_osc2frames(LV2_OSC_Schedule_Handle handle,uint64_t timetag)186 _osc2frames(LV2_OSC_Schedule_Handle handle, uint64_t timetag)
187 {
188 return 0.0; // dummy for coverage
189 }
190
191 static uint64_t
_frames2osc(LV2_OSC_Schedule_Handle handle,double frames)192 _frames2osc(LV2_OSC_Schedule_Handle handle, double frames)
193 {
194 return 0; // dummy for coverage
195 }
196
197 __non_realtime int
main(int argc,char ** argv)198 main(int argc, char **argv)
199 {
200 static handle_t handle;
201
202 LV2_URID_Map map = {
203 .handle = &handle,
204 .map = _map
205 };
206 LV2_URID_Unmap unmap = {
207 .handle = &handle,
208 .unmap = _unmap
209 };
210 LV2_Worker_Schedule sched = {
211 .handle = &handle,
212 .schedule_work = _sched
213 };
214 LV2_Log_Log log = {
215 .handle = &handle,
216 .printf = _printf,
217 .vprintf = _vprintf
218 };
219 LV2_OSC_Schedule osched = {
220 .handle = &handle,
221 .osc2frames = _osc2frames,
222 .frames2osc = _frames2osc
223 };
224
225 const float srate = 48000.f;
226 LV2_Options_Option opts [] = {
227 {
228 .key = 0,
229 .value =NULL
230 }
231 };
232
233 const LV2_Feature feat_map = {
234 .URI = LV2_URID__map,
235 .data = &map
236 };
237 const LV2_Feature feat_unmap = {
238 .URI = LV2_URID__unmap,
239 .data = &unmap
240 };
241 const LV2_Feature feat_sched = {
242 .URI = LV2_WORKER__schedule,
243 .data = &sched
244 };
245 const LV2_Feature feat_log = {
246 .URI = LV2_LOG__log,
247 .data = &log
248 };
249 const LV2_Feature feat_opts = {
250 .URI = LV2_OPTIONS__options,
251 .data = opts
252 };
253 const LV2_Feature feat_osc = {
254 .URI = LV2_OSC__schedule,
255 .data = &osched
256 };
257
258 const LV2_Feature *const features [] = {
259 &feat_map,
260 &feat_unmap,
261 &feat_sched,
262 &feat_log,
263 &feat_opts,
264 &feat_osc,
265 NULL
266 };
267
268 if(moony_init(&handle.moony, "http://open-music-kontrollers.ch/lv2/moony#test",
269 srate, features, 0x800000, true)) // 8MB initial memory
270 {
271 return -1;
272 }
273 moony_vm_nrt_enter(handle.moony.vm);
274
275 handle.iface = extension_data(LV2_WORKER__interface);
276
277 lua_State *L = moony_current(&handle.moony);
278 moony_open(&handle.moony, handle.moony.vm, L);
279
280 lua_pushstring(L, "map");
281 lua_newtable(L);
282 lua_rawset(L, LUA_REGISTRYINDEX);
283
284 lua_pushstring(L, "unmap");
285 lua_newtable(L);
286 lua_rawset(L, LUA_REGISTRYINDEX);
287
288 lv2_atom_forge_init(&handle.forge, &map);
289
290 const size_t buf_size = argc > 2
291 ? atoi(argv[2])
292 : BUF_SIZE;
293
294 // register test function
295 lua_pushlightuserdata(L, &handle);
296 lua_pushinteger(L, buf_size);
297 lua_pushcclosure(L, _test, 2);
298 lua_setglobal(L, "test");
299
300 const int ret = luaL_dofile(L, argv[1]); // wraps around lua_pcall
301
302 if(ret)
303 fprintf(stderr, "err: %s\n", lua_tostring(L, -1));
304
305 for(urid_t *itm=handle.urids; itm->urid; itm++)
306 free(itm->uri);
307
308 moony_vm_nrt_leave(handle.moony.vm);
309 moony_deinit(&handle.moony);
310
311 return ret;
312 }
313