1 /*
2  * Copyright (c) 2015 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 <stdio.h>
19 #include <stdlib.h>
20 
21 #include <espressivo.h>
22 #include <osc.lv2/forge.h>
23 #include <props.h>
24 
25 #define SYNTH_NAMES 8
26 #define STRING_SIZE 256
27 #define MAX_NPROPS (SYNTH_NAMES + 8)
28 
29 typedef struct _targetI_t targetI_t;
30 typedef struct _plugstate_t plugstate_t;
31 typedef struct _plughandle_t plughandle_t;
32 
33 struct _targetI_t {
34 	int32_t sid;
35 	int32_t zone;
36 };
37 
38 struct _plugstate_t {
39 	char synth_name [SYNTH_NAMES][STRING_SIZE];
40 	int32_t out_offset;
41 	int32_t gid_offset;
42 	int32_t sid_offset;
43 	int32_t sid_wrap;
44 	int32_t arg_offset;
45 	int32_t allocate;
46 	int32_t gate;
47 	int32_t group;
48 };
49 
50 struct _plughandle_t {
51 	LV2_URID_Map *map;
52 	LV2_OSC_URID osc_urid;
53 	LV2_Atom_Forge forge;
54 	LV2_Atom_Forge_Ref ref;
55 
56 	PROPS_T(props, MAX_NPROPS);
57 	XPRESS_T(xpressI, MAX_NVOICES);
58 	targetI_t targetI [MAX_NVOICES];
59 
60 	const LV2_Atom_Sequence *event_in;
61 	LV2_Atom_Sequence *osc_out;
62 
63 	int32_t sid;
64 
65 	plugstate_t state;
66 	plugstate_t stash;
67 };
68 
69 #define SYNTH_NAME(NUM) \
70 { \
71 	.property = ESPRESSIVO_URI"#sc_synth_name_"#NUM, \
72 	.offset = offsetof(plugstate_t, synth_name) + (NUM-1)*STRING_SIZE, \
73 	.type = LV2_ATOM__String, \
74 	.max_size = STRING_SIZE \
75 }
76 
77 static const props_def_t defs [MAX_NPROPS] = {
78 	{
79 		.property = ESPRESSIVO_URI"#sc_out_offset",
80 		.offset = offsetof(plugstate_t, out_offset),
81 		.type = LV2_ATOM__Int,
82 	},
83 	{
84 		.property = ESPRESSIVO_URI"#sc_gid_offset",
85 		.offset = offsetof(plugstate_t, gid_offset),
86 		.type = LV2_ATOM__Int,
87 	},
88 	{
89 		.property = ESPRESSIVO_URI"#sc_sid_offset",
90 		.offset = offsetof(plugstate_t, sid_offset),
91 		.type = LV2_ATOM__Int,
92 	},
93 	{
94 		.property = ESPRESSIVO_URI"#sc_sid_wrap",
95 		.offset = offsetof(plugstate_t, sid_wrap),
96 		.type = LV2_ATOM__Int,
97 	},
98 	{
99 		.property = ESPRESSIVO_URI"#sc_arg_offset",
100 		.offset = offsetof(plugstate_t, arg_offset),
101 		.type = LV2_ATOM__Int,
102 	},
103 	{
104 		.property = ESPRESSIVO_URI"#sc_allocate",
105 		.offset = offsetof(plugstate_t, allocate),
106 		.type = LV2_ATOM__Bool,
107 	},
108 	{
109 		.property = ESPRESSIVO_URI"#sc_gate",
110 		.offset = offsetof(plugstate_t, gate),
111 		.type = LV2_ATOM__Bool,
112 	},
113 	{
114 		.property = ESPRESSIVO_URI"#sc_group",
115 		.offset = offsetof(plugstate_t, group),
116 		.type = LV2_ATOM__Bool,
117 	},
118 
119 	SYNTH_NAME(1),
120 	SYNTH_NAME(2),
121 	SYNTH_NAME(3),
122 	SYNTH_NAME(4),
123 	SYNTH_NAME(5),
124 	SYNTH_NAME(6),
125 	SYNTH_NAME(7),
126 	SYNTH_NAME(8)
127 };
128 
129 static LV2_State_Status
_state_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)130 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
131 	LV2_State_Handle state, uint32_t flags,
132 	const LV2_Feature *const *features)
133 {
134 	plughandle_t *handle = instance;
135 
136 	return props_save(&handle->props, store, state, flags, features);
137 }
138 
139 static LV2_State_Status
_state_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)140 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
141 	LV2_State_Handle state, uint32_t flags,
142 	const LV2_Feature *const *features)
143 {
144 	plughandle_t *handle = instance;
145 
146 	return props_restore(&handle->props, retrieve, state, flags, features);
147 }
148 
149 static const LV2_State_Interface state_iface = {
150 	.save = _state_save,
151 	.restore = _state_restore
152 };
153 
154 static void
_add(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)155 _add(void *data, int64_t frames, const xpress_state_t *state,
156 	xpress_uuid_t uuid, void *target)
157 {
158 	plughandle_t *handle = data;
159 	LV2_Atom_Forge *forge = &handle->forge;
160 	targetI_t *src = target;
161 
162 	const int32_t sid = handle->state.sid_offset + (handle->state.sid_wrap
163 		? handle->sid++ % handle->state.sid_wrap
164 		: handle->sid++);
165 	src->sid = sid;
166 	src->zone = state->zone;
167 	const int32_t gid = handle->state.gid_offset + state->zone;
168 	const int32_t out = handle->state.out_offset + state->zone;
169 	const int32_t id = handle->state.group ? gid : sid;
170 	const int32_t arg_num = 4;
171 
172 	if(handle->state.allocate)
173 	{
174 		if(handle->ref)
175 			handle->ref = lv2_atom_forge_frame_time(forge, frames);
176 		if(handle->state.gate)
177 		{
178 			if(handle->ref)
179 				handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid,
180 					"/s_new", "siiiiisisi",
181 					handle->state.synth_name[state->zone], id, 0, gid,
182 					handle->state.arg_offset + 4, 128,
183 					"gate", 1,
184 					"out", out);
185 		}
186 		else // !handle->state.gate
187 		{
188 			if(handle->ref)
189 				handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid,
190 					"/s_new", "siiiiisi",
191 					handle->state.synth_name[state->zone], id, 0, gid,
192 					handle->state.arg_offset + 4, 128,
193 					"out", out);
194 		}
195 	}
196 	else if(handle->state.gate)
197 	{
198 		if(handle->ref)
199 			handle->ref = lv2_atom_forge_frame_time(forge, frames);
200 		if(handle->ref)
201 			handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid,
202 				"/n_set", "isi",
203 				id,
204 				"gate", 1);
205 	}
206 
207 	if(handle->ref)
208 		handle->ref = lv2_atom_forge_frame_time(forge, frames);
209 	if(handle->ref)
210 		handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid,
211 			"/n_setn", "iiiffff",
212 			id, handle->state.arg_offset, arg_num,
213 			_midi2cps(state->pitch * 0x7f), state->pressure,
214 			state->dPitch, state->dPressure);
215 }
216 
217 static void
_set(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)218 _set(void *data, int64_t frames, const xpress_state_t *state,
219 	xpress_uuid_t uuid, void *target)
220 {
221 	plughandle_t *handle = data;
222 	LV2_Atom_Forge *forge = &handle->forge;
223 	targetI_t *src = target;
224 
225 	const int32_t sid = src->sid;
226 	const int32_t gid = handle->state.gid_offset + state->zone;
227 	const int32_t id = handle->state.group ? gid : sid;
228 	const int32_t arg_num = 4;
229 
230 	if(handle->ref)
231 		handle->ref = lv2_atom_forge_frame_time(forge, frames);
232 	if(handle->ref)
233 		handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid,
234 			"/n_setn", "iiiffff",
235 			id, handle->state.arg_offset, arg_num,
236 			_midi2cps(state->pitch * 0x7f), state->pressure,
237 			state->dPitch, state->dPressure);
238 }
239 
240 static void
_del(void * data,int64_t frames,xpress_uuid_t uuid,void * target)241 _del(void *data, int64_t frames,
242 	xpress_uuid_t uuid, void *target)
243 {
244 	plughandle_t *handle = data;
245 	LV2_Atom_Forge *forge = &handle->forge;
246 	targetI_t *src = target;
247 
248 	const int32_t sid = src->sid;
249 	const int32_t gid = handle->state.gid_offset + src->zone;
250 	const int32_t id = handle->state.group ? gid : sid;
251 
252 	if(handle->state.gate)
253 	{
254 		if(handle->ref)
255 			handle->ref = lv2_atom_forge_frame_time(forge, frames);
256 		if(handle->ref)
257 			handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid,
258 				"/n_set", "isi",
259 				id,
260 				"gate", 0);
261 	}
262 }
263 
264 static const xpress_iface_t ifaceI = {
265 	.size = sizeof(targetI_t),
266 
267 	.add = _add,
268 	.set = _set,
269 	.del = _del
270 };
271 
272 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)273 instantiate(const LV2_Descriptor* descriptor, double rate,
274 	const char *bundle_path, const LV2_Feature *const *features)
275 {
276 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
277 	if(!handle)
278 		return NULL;
279 
280 	xpress_map_t *voice_map = NULL;
281 
282 	for(int i=0; features[i]; i++)
283 	{
284 		if(!strcmp(features[i]->URI, LV2_URID__map))
285 			handle->map = features[i]->data;
286 		else if(!strcmp(features[i]->URI, XPRESS__voiceMap))
287 			voice_map = features[i]->data;
288 	}
289 
290 	if(!handle->map)
291 	{
292 		fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
293 		free(handle);
294 		return NULL;
295 	}
296 
297 	lv2_atom_forge_init(&handle->forge, handle->map);
298 	lv2_osc_urid_init(&handle->osc_urid, handle->map);
299 
300 	if(!xpress_init(&handle->xpressI, MAX_NVOICES, handle->map, voice_map,
301 			XPRESS_EVENT_ALL, &ifaceI, handle->targetI, handle) )
302 	{
303 		free(handle);
304 		return NULL;
305 	}
306 
307 	if(!props_init(&handle->props, descriptor->URI,
308 		defs, MAX_NPROPS, &handle->state, &handle->stash,
309 		handle->map, handle))
310 	{
311 		free(handle);
312 		return NULL;
313 	}
314 
315 	return handle;
316 }
317 
318 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)319 connect_port(LV2_Handle instance, uint32_t port, void *data)
320 {
321 	plughandle_t *handle = (plughandle_t *)instance;
322 
323 	switch(port)
324 	{
325 		case 0:
326 			handle->event_in = (const LV2_Atom_Sequence *)data;
327 			break;
328 		case 1:
329 			handle->osc_out = (LV2_Atom_Sequence *)data;
330 			break;
331 		default:
332 			break;
333 	}
334 }
335 
336 static void
run(LV2_Handle instance,uint32_t nsamples)337 run(LV2_Handle instance, uint32_t nsamples)
338 {
339 	plughandle_t *handle = (plughandle_t *)instance;
340 
341 	// prepare osc atom forge
342 	const uint32_t capacity = handle->osc_out->atom.size;
343 	LV2_Atom_Forge *forge = &handle->forge;
344 	lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->osc_out, capacity);
345 	LV2_Atom_Forge_Frame frame;
346 	handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
347 
348 	props_idle(&handle->props, forge, 0, &handle->ref);
349 	xpress_pre(&handle->xpressI);
350 
351 	LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev)
352 	{
353 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
354 		const int64_t frames = ev->time.frames;
355 
356 		if(!props_advance(&handle->props, forge, frames, obj, &handle->ref))
357 		{
358 			xpress_advance(&handle->xpressI, forge, frames, obj, &handle->ref);
359 		}
360 	}
361 
362 	xpress_post(&handle->xpressI, nsamples-1);
363 
364 	if(handle->ref)
365 		lv2_atom_forge_pop(forge, &frame);
366 	else
367 		lv2_atom_sequence_clear(handle->osc_out);
368 }
369 
370 static void
cleanup(LV2_Handle instance)371 cleanup(LV2_Handle instance)
372 {
373 	plughandle_t *handle = (plughandle_t *)instance;
374 
375 	if(handle)
376 	{
377 		xpress_deinit(&handle->xpressI);
378 		free(handle);
379 	}
380 }
381 
382 static const void*
extension_data(const char * uri)383 extension_data(const char* uri)
384 {
385 	if(!strcmp(uri, LV2_STATE__interface))
386 		return &state_iface;
387 
388 	return NULL;
389 }
390 
391 const LV2_Descriptor sc_out = {
392 	.URI						= ESPRESSIVO_SC_OUT_URI,
393 	.instantiate		= instantiate,
394 	.connect_port		= connect_port,
395 	.activate				= NULL,
396 	.run						= run,
397 	.deactivate			= NULL,
398 	.cleanup				= cleanup,
399 	.extension_data	= extension_data
400 };
401