aboutsummaryrefslogtreecommitdiff
path: root/include/moony.h
blob: 21de613b3995069561746973dda44ef6e48ab2f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
/*
 * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
 *
 * This is free software: you can redistribute it and/or modify
 * it under the terms of the Artistic License 2.0 as published by
 * The Perl Foundation.
 *
 * This source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * Artistic License 2.0 for more details.
 *
 * You should have received a copy of the Artistic License 2.0
 * along the source as a COPYING file. If not, obtain it from
 * http://www.perlfoundation.org/artistic_license_2_0.
 */

#ifndef _MOONY_H
#define _MOONY_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdatomic.h>

#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
#include <lv2/lv2plug.in/ns/ext/atom/util.h>
#include <lv2/lv2plug.in/ns/ext/atom/forge.h>
#include <lv2/lv2plug.in/ns/ext/midi/midi.h>
#include <lv2/lv2plug.in/ns/ext/time/time.h>
#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include <lv2/lv2plug.in/ns/ext/worker/worker.h>
#include <lv2/lv2plug.in/ns/ext/log/log.h>
#include <lv2/lv2plug.in/ns/ext/log/logger.h>
#include <lv2/lv2plug.in/ns/ext/state/state.h>
#include <lv2/lv2plug.in/ns/ext/buf-size/buf-size.h>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <lv2/lv2plug.in/ns/ext/patch/patch.h>
#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
#include <lv2/lv2plug.in/ns/extensions/units/units.h>

#include <api_vm.h>
#include <lv2_osc.h>
#include <xpress.h>

#include <lua.h>
#include <lauxlib.h>

#define MOONY_MAX_CHUNK_LEN		0x10000 // 64KB
#define MOONY_MAX_ERROR_LEN		0x400 // 1KB

#define MOONY_URI							"http://open-music-kontrollers.ch/lv2/moony"

#define MOONY_CODE_URI				MOONY_URI"#code"
#define MOONY_SELECTION_URI		MOONY_URI"#selection"
#define MOONY_ERROR_URI				MOONY_URI"#error"
#define MOONY_TRACE_URI				MOONY_URI"#trace"
#define MOONY_STATE_URI				MOONY_URI"#state"

#define MOONY_COMMON_UI_URI		MOONY_URI"#ui5_common_ui"
#define MOONY_COMMON_KX_URI		MOONY_URI"#ui6_common_kx"
#define MOONY_COMMON_X11_URI	MOONY_URI"#ui7_common_x11"
#define MOONY_COMMON_EO_URI		MOONY_URI"#ui8_common_eo"

#define MOONY_SIMPLE_UI_URI		MOONY_URI"#ui3_simple_ui"
#define MOONY_SIMPLE_KX_URI		MOONY_URI"#ui4_simple_kx"

#define MOONY_WEB_UI_URI			MOONY_URI"#ui1_web_ui"
#define MOONY_WEB_KX_URI			MOONY_URI"#ui2_web_kx"

#define MOONY_C1XC1_URI				MOONY_URI"#c1xc1"
#define MOONY_C2XC2_URI				MOONY_URI"#c2xc2"
#define MOONY_C4XC4_URI				MOONY_URI"#c4xc4"

#define MOONY_A1XA1_URI				MOONY_URI"#a1xa1"
#define MOONY_A2XA2_URI				MOONY_URI"#a2xa2"
#define MOONY_A4XA4_URI				MOONY_URI"#a4xa4"

#define MOONY_C1A1XC1A1_URI		MOONY_URI"#c1a1xc1a1"
#define MOONY_C2A1XC2A1_URI		MOONY_URI"#c2a1xc2a1"
#define MOONY_C4A1XC4A1_URI		MOONY_URI"#c4a1xc4a1"

extern const LV2_Descriptor c1xc1;
extern const LV2_Descriptor c2xc2;
extern const LV2_Descriptor c4xc4;

extern const LV2_Descriptor a1xa1;
extern const LV2_Descriptor a2xa2;
extern const LV2_Descriptor a4xa4;

extern const LV2_Descriptor c1a1xc1a1;
extern const LV2_Descriptor c2a1xc2a1;
extern const LV2_Descriptor c4a1xc4a1;

extern const LV2UI_Descriptor common_eo;
extern const LV2UI_Descriptor common_ui;
extern const LV2UI_Descriptor common_x11;
extern const LV2UI_Descriptor common_kx;

extern const LV2UI_Descriptor simple_ui;
extern const LV2UI_Descriptor simple_kx;

extern const LV2UI_Descriptor web_ui;
extern const LV2UI_Descriptor web_kx;

typedef enum _moony_udata_t {
	MOONY_UDATA_ATOM,
	MOONY_UDATA_FORGE,
	MOONY_UDATA_STASH,

	MOONY_UDATA_COUNT
} moony_udata_t;

typedef enum _moony_cclosure_t {
	MOONY_CCLOSURE_STASH,
	MOONY_CCLOSURE_APPLY,
	MOONY_CCLOSURE_SAVE,
	MOONY_CCLOSURE_RESTORE,

	MOONY_CCLOSURE_TIME_STASH,
	MOONY_CCLOSURE_TIME_APPLY,

	MOONY_CCLOSURE_LIT_UNPACK,
	MOONY_CCLOSURE_TUPLE_UNPACK,
	MOONY_CCLOSURE_VECTOR_UNPACK,
	MOONY_CCLOSURE_CHUNK_UNPACK,

	MOONY_CCLOSURE_TUPLE_FOREACH,
	MOONY_CCLOSURE_VECTOR_FOREACH,
	MOONY_CCLOSURE_OBJECT_FOREACH,
	MOONY_CCLOSURE_SEQUENCE_FOREACH,

	MOONY_CCLOSURE_CLONE,
	MOONY_CCLOSURE_WRITE,

	MOONY_CCLOSURE_COUNT
} moony_cclosure_t;

typedef enum _moony_upclosure_t {
	MOONY_UPCLOSURE_TUPLE_FOREACH,
	MOONY_UPCLOSURE_VECTOR_FOREACH,
	MOONY_UPCLOSURE_OBJECT_FOREACH,
	MOONY_UPCLOSURE_SEQUENCE_FOREACH,

	MOONY_UPCLOSURE_COUNT
} moony_upclosure_t;

// from api_atom.c
typedef struct _lheader_t lheader_t;
typedef struct _latom_driver_t latom_driver_t;
typedef struct _latom_driver_hash_t latom_driver_hash_t;

struct _lheader_t {
	moony_udata_t type;
	bool cache;
};

struct _latom_driver_hash_t {
	LV2_URID type;
	const latom_driver_t *driver;
};

#define UDATA_OFFSET (LUA_RIDX_LAST + 1)
#define DRIVER_HASH_MAX 17

// from moony.c
typedef struct _patch_t patch_t;
typedef struct _moony_t moony_t;

struct _patch_t {
	LV2_URID self;

	LV2_URID get;
	LV2_URID set;
	LV2_URID put;
	LV2_URID patch;
	LV2_URID body;
	LV2_URID subject;
	LV2_URID property;
	LV2_URID value;
	LV2_URID add;
	LV2_URID remove;
	LV2_URID wildcard;
	LV2_URID writable;
	LV2_URID readable;
};

struct _moony_t {
	LV2_URID_Map *map;
	LV2_URID_Unmap *unmap;
	LV2_Atom_Forge forge;
	LV2_Atom_Forge state_forge;
	LV2_Atom_Forge stash_forge;
	LV2_Atom_Forge notify_forge;

	LV2_Atom_Forge_Frame notify_frame;
	LV2_Atom_Forge_Ref notify_ref;

	struct {
		LV2_URID moony_code;
		LV2_URID moony_selection;
		LV2_URID moony_error;
		LV2_URID moony_trace;
		LV2_URID moony_state;

		LV2_URID midi_event;

		LV2_URID bufsz_max_block_length;
		LV2_URID bufsz_min_block_length;
		LV2_URID bufsz_sequence_size;

		patch_t patch;

		LV2_URID rdfs_label;
		LV2_URID rdfs_range;
		LV2_URID rdfs_comment;

		LV2_URID rdf_value;

		LV2_URID core_minimum;
		LV2_URID core_maximum;
		LV2_URID core_scale_point;

		LV2_URID units_unit;

		LV2_URID atom_beat_time;
		LV2_URID atom_frame_time;
	} uris;

	struct {
		uint32_t max_block_length;
		uint32_t min_block_length;
		uint32_t sequence_size;
		uint32_t sample_rate;
	} opts;

	osc_forge_t oforge;
	
	LV2_Worker_Schedule *sched;
	volatile int working;
	volatile int fully_extended;

	osc_schedule_t *osc_sched;
	
	LV2_Log_Log *log;
	LV2_Log_Logger logger;

	moony_vm_t vm;

	char chunk [MOONY_MAX_CHUNK_LEN];
	volatile int props_out;
	volatile int dirty_out;
	volatile int error_out;
	volatile int trace_out;
	char error [MOONY_MAX_ERROR_LEN];
	char trace [MOONY_MAX_ERROR_LEN];

	// udata cache
	int itr [MOONY_UDATA_COUNT];
	int upc [MOONY_UPCLOSURE_COUNT];

	struct {
		atomic_flag chunk;
		atomic_flag error;
		atomic_flag state;
	} lock;

	LV2_Atom *state_atom;
	LV2_Atom *stash_atom;
	uint32_t stash_size;

	latom_driver_hash_t atom_driver_hash [DRIVER_HASH_MAX];

	xpress_map_t *voice_map;
};

// in api.c
int moony_init(moony_t *moony, const char *subject, double sample_rate,
	const LV2_Feature *const *features);
void moony_deinit(moony_t *moony);
void moony_open(moony_t *moony, lua_State *L, bool use_assert);
void moony_in(moony_t *moony, const LV2_Atom_Sequence *control, LV2_Atom_Sequence *notify);
void moony_out(moony_t *moony, LV2_Atom_Sequence *notify, uint32_t frames);
const void* extension_data(const char* uri);
void *moony_newuserdata(lua_State *L, moony_t *moony, moony_udata_t type, bool cache);

static inline void
moony_freeuserdata(moony_t *moony)
{
	for(unsigned i=0; i<MOONY_UDATA_COUNT; i++)
		moony->itr[i] = 1; // reset iterator
	for(unsigned i=0; i<MOONY_UPCLOSURE_COUNT; i++)
		moony->upc[i] = 1; // reset iterator
}

static inline int
moony_bypass(moony_t *moony)
{
	return moony->error[0] != '\0';
}

static inline void
moony_err(moony_t *moony, const char *msg)
{
	const char *error = msg;
	const char *err = strstr(error, "\"]:"); // search end mark of header [string ""]:
	err = err
		? err + 3 // skip header end mark
		: error; // use whole error string alternatively

	if(moony->log)
		lv2_log_trace(&moony->logger, "%s", err);

	snprintf(moony->error, MOONY_MAX_ERROR_LEN, "%s", err);

	moony->error_out = 1;
}

static inline void
moony_error(moony_t *moony)
{
	lua_State *L = moony->vm.L;

	const char *msg = lua_tostring(L, -1);
	if(msg)
		moony_err(moony, msg);
	lua_pop(L, 1);
}

#define _spin_lock(FLAG) while(atomic_flag_test_and_set_explicit((FLAG), memory_order_acquire)) {}
#define _try_lock(FLAG) !atomic_flag_test_and_set_explicit((FLAG), memory_order_acquire)
#define _unlock(FLAG) atomic_flag_clear_explicit((FLAG), memory_order_release)

static inline LV2_Atom_Forge_Ref
_moony_patch(patch_t *patch, LV2_Atom_Forge *forge, LV2_URID key,
	const char *str, uint32_t size)
{
	LV2_Atom_Forge_Frame frame;
	
	LV2_Atom_Forge_Ref ref = lv2_atom_forge_object(forge, &frame, 0, str ? patch->set : patch->get)
		&& lv2_atom_forge_key(forge, patch->subject)
		&& lv2_atom_forge_urid(forge, patch->self)
		&& lv2_atom_forge_key(forge, patch->property)
		&& lv2_atom_forge_urid(forge, key);

	if(ref && str)
	{
		ref = lv2_atom_forge_key(forge, patch->value)
			&& lv2_atom_forge_string(forge, str, size);
	}

	if(ref)
	{
		lv2_atom_forge_pop(forge, &frame);
		return 1; // success
	}

	return 0; // overflow
}

void *
moony_alloc(moony_t *moony, size_t nsize);

void *
moony_realloc(moony_t *moony, void *buf, size_t osize, size_t nsize);

void
moony_free(moony_t *moony, void *buf, size_t osize);

LV2_Atom_Forge_Ref
_sink(LV2_Atom_Forge_Sink_Handle handle, const void *buf, uint32_t size);

LV2_Atom *
_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref);

#endif // _MOONY_H