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