1 /*
2  * Copyright (c) 2015-2017 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 #include <math.h>
21 
22 #include <espressivo.h>
23 #include <props.h>
24 
25 #define MAX_NPROPS 9
26 
27 typedef enum _enum_t enum_t;
28 typedef enum _op_t op_t;
29 typedef struct _targetI_t targetI_t;
30 typedef struct _targetO_t targetO_t;
31 typedef struct _plugstate_t plugstate_t;
32 typedef struct _plughandle_t plughandle_t;
33 
34 enum _enum_t {
35 	ENUM_PITCH = 0,
36 	ENUM_PRESSURE,
37 	ENUM_TIMBRE,
38 	ENUM_DPITCH,
39 	ENUM_DPRESSURE,
40 	ENUM_DTIMBRE
41 };
42 
43 enum _op_t {
44 	OP_ADD = 0,
45 	OP_SUB,
46 	OP_MUL,
47 	OP_DIV,
48 	OP_POW,
49 	OP_SET
50 };
51 
52 struct _targetI_t {
53 	xpress_uuid_t uuid;
54 	int32_t zone_mask;
55 };
56 
57 struct _targetO_t {
58 	xpress_state_t state;
59 };
60 
61 struct _plugstate_t {
62 	int32_t zone_mask_src;
63 	int32_t zone_mask_mod;;
64 	int32_t zone_offset;;
65 	int32_t enum_src;
66 	int32_t enum_mod;
67 	float multiplier;
68 	float adder;
69 	int32_t op;
70 	int32_t reset;
71 };
72 
73 struct _plughandle_t {
74 	LV2_URID_Map *map;
75 	LV2_Atom_Forge forge;
76 	LV2_Atom_Forge_Ref ref;
77 
78 	PROPS_T(props, MAX_NPROPS);
79 	XPRESS_T(xpressI, MAX_NVOICES);
80 	XPRESS_T(xpressO, MAX_NVOICES);
81 	targetI_t targetI [MAX_NVOICES];
82 	targetO_t targetO [MAX_NVOICES];
83 
84 	const LV2_Atom_Sequence *event_in;
85 	LV2_Atom_Sequence *event_out;
86 
87 	plugstate_t state;
88 	plugstate_t stash;
89 
90 	xpress_uuid_t uuid;
91 	xpress_state_t modu;
92 };
93 
94 static const xpress_state_t empty_state = {
95 	.zone = 0,
96 
97 	.pitch = 0.f,
98 	.pressure = 0.f,
99 	.timbre = 0.f,
100 
101 	.dPitch = 0.f,
102 	.dPressure = 0.f,
103 	.dTimbre = 0.f
104 };
105 
106 static inline float
_clip(float min,float val,float max)107 _clip(float min, float val, float max)
108 {
109 	if(val < min)
110 		return min;
111 	else if(val > max)
112 		return max;
113 	return val;
114 }
115 
116 static inline float
_op(plughandle_t * handle,float dst,float val)117 _op(plughandle_t *handle, float dst, float val)
118 {
119 	switch((op_t)handle->state.op)
120 	{
121 		case OP_ADD:
122 			return dst + val;
123 		case OP_SUB:
124 			return dst - val;
125 		case OP_MUL:
126 			return dst * val;
127 		case OP_DIV:
128 			return (val == 0.f) ? 0.f : dst / val;
129 		case OP_POW:
130 			return powf(dst, val);
131 		case OP_SET:
132 			return val;
133 	}
134 
135 	return 0.f;
136 }
137 
138 static inline void
_modulate(plughandle_t * handle,xpress_state_t * state)139 _modulate(plughandle_t *handle, xpress_state_t *state)
140 {
141 	float val = 0.f;
142 
143 	switch((enum_t)handle->state.enum_mod)
144 	{
145 		case ENUM_PITCH:
146 		{
147 			val = handle->modu.pitch;
148 		}	break;
149 		case ENUM_PRESSURE:
150 		{
151 			val = handle->modu.pressure;
152 		}	break;
153 		case ENUM_TIMBRE:
154 		{
155 			val = handle->modu.timbre;
156 		}	break;
157 		case ENUM_DPITCH:
158 		{
159 			val = handle->modu.dPitch;
160 		}	break;
161 		case ENUM_DPRESSURE:
162 		{
163 			val = handle->modu.dPressure;
164 		}	break;
165 		case ENUM_DTIMBRE:
166 		{
167 			val = handle->modu.dTimbre;
168 		}	break;
169 	}
170 
171 	val *= handle->state.multiplier;
172 	val += handle->state.adder;
173 
174 	switch((enum_t)handle->state.enum_src)
175 	{
176 		case ENUM_PITCH:
177 		{
178 			state->pitch = _op(handle, state->pitch, val);
179 			state->pitch = _clip(0.f, state->pitch, 1.f);
180 		}	break;
181 		case ENUM_PRESSURE:
182 		{
183 			state->pressure = _op(handle, state->pressure, val);
184 			state->pressure = _clip(0.f, state->pressure, 1.f);
185 		}	break;
186 		case ENUM_TIMBRE:
187 		{
188 			state->timbre = _op(handle, state->timbre, val);
189 			state->timbre = _clip(0.f, state->timbre, 1.f);
190 		}	break;
191 		case ENUM_DPITCH:
192 		{
193 			state->dPitch = _op(handle, state->dPitch, val);
194 		}	break;
195 		case ENUM_DPRESSURE:
196 		{
197 			state->dPressure = _op(handle, state->dPressure, val);
198 		}	break;
199 		case ENUM_DTIMBRE:
200 		{
201 			state->dTimbre = _op(handle, state->dTimbre, val);
202 		}	break;
203 	}
204 }
205 
206 static inline void
_upd(plughandle_t * handle,int64_t frames)207 _upd(plughandle_t *handle, int64_t frames)
208 {
209 	XPRESS_VOICE_FOREACH(&handle->xpressO, voice)
210 	{
211 		LV2_Atom_Forge *forge = &handle->forge;
212 
213 		targetO_t *dst = voice->target;
214 
215 		xpress_state_t new_state = dst->state;
216 		new_state.zone += handle->state.zone_offset;
217 		_modulate(handle, &new_state);
218 
219 		if(handle->ref)
220 			handle->ref = xpress_token(&handle->xpressO, forge, frames, voice->uuid, &new_state);
221 	}
222 }
223 
224 static void
_intercept(void * data,int64_t frames,props_impl_t * impl)225 _intercept(void *data, int64_t frames, props_impl_t *impl)
226 {
227 	plughandle_t *handle = data;
228 
229 	_upd(handle, frames);
230 }
231 
232 static const props_def_t defs [MAX_NPROPS] = {
233 	{
234 		.property = ESPRESSIVO_URI"#modulator_zone_mask_src",
235 		.offset = offsetof(plugstate_t, zone_mask_src),
236 		.type = LV2_ATOM__Int
237 	},
238 	{
239 		.property = ESPRESSIVO_URI"#modulator_zone_mask_mod",
240 		.offset = offsetof(plugstate_t, zone_mask_mod),
241 		.type = LV2_ATOM__Int
242 	},
243 	{
244 		.property = ESPRESSIVO_URI"#modulator_enum_src",
245 		.offset = offsetof(plugstate_t, enum_src),
246 		.type = LV2_ATOM__Int,
247 		.event_cb = _intercept
248 	},
249 	{
250 		.property = ESPRESSIVO_URI"#modulator_enum_mod",
251 		.offset = offsetof(plugstate_t, enum_mod),
252 		.type = LV2_ATOM__Int,
253 		.event_cb = _intercept
254 	},
255 	{
256 		.property = ESPRESSIVO_URI"#modulator_zone_offset",
257 		.offset = offsetof(plugstate_t, zone_offset),
258 		.type = LV2_ATOM__Int
259 	},
260 	{
261 		.property = ESPRESSIVO_URI"#modulator_multiplier",
262 		.offset = offsetof(plugstate_t, multiplier),
263 		.type = LV2_ATOM__Float,
264 		.event_cb = _intercept
265 	},
266 	{
267 		.property = ESPRESSIVO_URI"#modulator_adder",
268 		.offset = offsetof(plugstate_t, adder),
269 		.type = LV2_ATOM__Float,
270 		.event_cb = _intercept
271 	},
272 	{
273 		.property = ESPRESSIVO_URI"#modulator_op",
274 		.offset = offsetof(plugstate_t, op),
275 		.type = LV2_ATOM__Int,
276 		.event_cb = _intercept
277 	},
278 	{
279 		.property = ESPRESSIVO_URI"#modulator_reset",
280 		.offset = offsetof(plugstate_t, reset),
281 		.type = LV2_ATOM__Bool
282 	}
283 };
284 
285 static void
_add(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)286 _add(void *data, int64_t frames, const xpress_state_t *state,
287 	xpress_uuid_t uuid, void *target)
288 {
289 	plughandle_t *handle = data;
290 	targetI_t *src = target;
291 	src->zone_mask = 1 << state->zone;
292 
293 	if(src->zone_mask & handle->state.zone_mask_src)
294 	{
295 		LV2_Atom_Forge *forge = &handle->forge;
296 
297 		targetO_t *dst = xpress_create(&handle->xpressO, &src->uuid);
298 		dst->state = *state;
299 
300 		xpress_state_t new_state = dst->state;
301 		new_state.zone += handle->state.zone_offset;
302 		_modulate(handle, &new_state);
303 
304 		if(handle->ref)
305 			handle->ref = xpress_token(&handle->xpressO, forge, frames, src->uuid, &new_state);
306 	}
307 
308 	if(src->zone_mask & handle->state.zone_mask_mod)
309 	{
310 		if(handle->uuid == 0) // no modulator registered, yet
311 		{
312 			handle->uuid = uuid;
313 			handle->modu = *state;
314 
315 			_upd(handle, frames);
316 		}
317 	}
318 }
319 
320 static void
_set(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)321 _set(void *data, int64_t frames, const xpress_state_t *state,
322 	xpress_uuid_t uuid, void *target)
323 {
324 	plughandle_t *handle = data;
325 	targetI_t *src = target;
326 
327 	if(src->zone_mask & handle->state.zone_mask_src)
328 	{
329 		LV2_Atom_Forge *forge = &handle->forge;
330 
331 		targetO_t *dst = xpress_get(&handle->xpressO, src->uuid);
332 		dst->state = *state;
333 
334 		xpress_state_t new_state = dst->state;
335 		new_state.zone += handle->state.zone_offset;
336 		_modulate(handle, &new_state);
337 
338 		if(handle->ref)
339 			handle->ref = xpress_token(&handle->xpressO, forge, frames, src->uuid, &new_state);
340 	}
341 
342 	if(src->zone_mask & handle->state.zone_mask_mod)
343 	{
344 		if(handle->uuid == uuid) // this is our modulator
345 		{
346 			handle->modu = *state;
347 
348 			_upd(handle, frames);
349 		}
350 	}
351 }
352 
353 static void
_del(void * data,int64_t frames,xpress_uuid_t uuid,void * target)354 _del(void *data, int64_t frames,
355 	xpress_uuid_t uuid, void *target)
356 {
357 	plughandle_t *handle = data;
358 	targetI_t *src = target;
359 
360 	if(src->zone_mask & handle->state.zone_mask_src)
361 	{
362 		LV2_Atom_Forge *forge = &handle->forge;
363 
364 		xpress_free(&handle->xpressO, src->uuid);
365 
366 		if(handle->ref)
367 			handle->ref = xpress_alive(&handle->xpressO, forge, frames);
368 	}
369 
370 	if(src->zone_mask & handle->state.zone_mask_mod)
371 	{
372 		if(handle->uuid == uuid) // this is our modulator
373 		{
374 			handle->uuid = 0;
375 			if(handle->state.reset)
376 				handle->modu = empty_state;
377 
378 			_upd(handle, frames);
379 		}
380 	}
381 }
382 
383 static const xpress_iface_t ifaceI = {
384 	.size = sizeof(targetI_t),
385 
386 	.add = _add,
387 	.set = _set,
388 	.del = _del
389 };
390 
391 static const xpress_iface_t ifaceO = {
392 	.size = sizeof(targetO_t)
393 };
394 
395 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)396 instantiate(const LV2_Descriptor* descriptor, double rate,
397 	const char *bundle_path, const LV2_Feature *const *features)
398 {
399 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
400 	if(!handle)
401 		return NULL;
402 
403 	xpress_map_t *voice_map = NULL;
404 
405 	for(unsigned i=0; features[i]; i++)
406 	{
407 		if(!strcmp(features[i]->URI, LV2_URID__map))
408 			handle->map = features[i]->data;
409 		else if(!strcmp(features[i]->URI, XPRESS__voiceMap))
410 			voice_map = features[i]->data;
411 	}
412 
413 	if(!handle->map)
414 	{
415 		fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
416 		free(handle);
417 		return NULL;
418 	}
419 
420 	lv2_atom_forge_init(&handle->forge, handle->map);
421 
422 	if(  !xpress_init(&handle->xpressI, MAX_NVOICES, handle->map, voice_map,
423 			XPRESS_EVENT_ALL, &ifaceI, handle->targetI, handle)
424 		|| !xpress_init(&handle->xpressO, MAX_NVOICES, handle->map, voice_map,
425 			XPRESS_EVENT_NONE, &ifaceO, handle->targetO, handle) )
426 	{
427 		free(handle);
428 		return NULL;
429 	}
430 
431 	if(!props_init(&handle->props, descriptor->URI,
432 		defs, MAX_NPROPS, &handle->state, &handle->stash,
433 		handle->map, handle))
434 	{
435 		fprintf(stderr, "failed to allocate property structure\n");
436 		free(handle);
437 		return NULL;
438 	}
439 
440 	return handle;
441 }
442 
443 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)444 connect_port(LV2_Handle instance, uint32_t port, void *data)
445 {
446 	plughandle_t *handle = instance;
447 
448 	switch(port)
449 	{
450 		case 0:
451 			handle->event_in = (const LV2_Atom_Sequence *)data;
452 			break;
453 		case 1:
454 			handle->event_out = (LV2_Atom_Sequence *)data;
455 			break;
456 		default:
457 			break;
458 	}
459 }
460 
461 static void
run(LV2_Handle instance,uint32_t nsamples)462 run(LV2_Handle instance, uint32_t nsamples)
463 {
464 	plughandle_t *handle = instance;
465 
466 	// prepare midi atom forge
467 	const uint32_t capacity = handle->event_out->atom.size;
468 	LV2_Atom_Forge *forge = &handle->forge;
469 	lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->event_out, capacity);
470 	LV2_Atom_Forge_Frame frame;
471 	handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
472 
473 	props_idle(&handle->props, forge, 0, &handle->ref);
474 	xpress_pre(&handle->xpressI);
475 	xpress_rst(&handle->xpressO);
476 
477 	LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev)
478 	{
479 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
480 		const int64_t frames = ev->time.frames;
481 
482 		if(!props_advance(&handle->props, forge, frames, obj, &handle->ref))
483 		{
484 			xpress_advance(&handle->xpressI, forge, frames, obj, &handle->ref);
485 		}
486 	}
487 
488 	xpress_post(&handle->xpressI, nsamples-1);
489 	if(handle->ref && !xpress_synced(&handle->xpressO))
490 		handle->ref = xpress_alive(&handle->xpressO, forge, nsamples-1);
491 
492 	if(handle->ref)
493 		lv2_atom_forge_pop(forge, &frame);
494 	else
495 		lv2_atom_sequence_clear(handle->event_out);
496 }
497 
498 static void
cleanup(LV2_Handle instance)499 cleanup(LV2_Handle instance)
500 {
501 	plughandle_t *handle = instance;
502 
503 	if(handle)
504 	{
505 		xpress_deinit(&handle->xpressI);
506 		xpress_deinit(&handle->xpressO);
507 		free(handle);
508 	}
509 }
510 
511 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)512 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
513 	LV2_State_Handle state, uint32_t flags,
514 	const LV2_Feature *const *features)
515 {
516 	plughandle_t *handle = instance;
517 
518 	return props_save(&handle->props, store, state, flags, features);
519 }
520 
521 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)522 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
523 	LV2_State_Handle state, uint32_t flags,
524 	const LV2_Feature *const *features)
525 {
526 	plughandle_t *handle = instance;
527 
528 	return props_restore(&handle->props, retrieve, state, flags, features);
529 }
530 
531 static const LV2_State_Interface state_iface = {
532 	.save = _state_save,
533 	.restore = _state_restore
534 };
535 
536 static const void *
extension_data(const char * uri)537 extension_data(const char *uri)
538 {
539 	if(!strcmp(uri, LV2_STATE__interface))
540 		return &state_iface;
541 	return NULL;
542 }
543 
544 const LV2_Descriptor modulator = {
545 	.URI						= ESPRESSIVO_MODULATOR_URI,
546 	.instantiate		= instantiate,
547 	.connect_port		= connect_port,
548 	.activate				= NULL,
549 	.run						= run,
550 	.deactivate			= NULL,
551 	.cleanup				= cleanup,
552 	.extension_data	= extension_data
553 };
554