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 2
26 
27 typedef struct _targetI_t targetI_t;
28 typedef struct _targetO_t targetO_t;
29 typedef struct _plugstate_t plugstate_t;
30 typedef struct _plughandle_t plughandle_t;
31 
32 struct _targetI_t {
33 	xpress_uuid_t uuid;
34 	int32_t zone_mask;
35 };
36 
37 struct _targetO_t {
38 	//empty
39 };
40 
41 struct _plugstate_t {
42 	int32_t zone_mask;
43 	int32_t zone_offset;
44 };
45 
46 struct _plughandle_t {
47 	LV2_URID_Map *map;
48 	LV2_Atom_Forge forge;
49 	LV2_Atom_Forge_Ref ref;
50 
51 	PROPS_T(props, MAX_NPROPS);
52 	XPRESS_T(xpressI, MAX_NVOICES);
53 	XPRESS_T(xpressO, MAX_NVOICES);
54 	targetI_t targetI [MAX_NVOICES];
55 	targetO_t targetO [MAX_NVOICES];
56 
57 	const LV2_Atom_Sequence *event_in;
58 	LV2_Atom_Sequence *event_out;
59 
60 	plugstate_t state;
61 	plugstate_t stash;
62 };
63 
64 static const props_def_t defs [MAX_NPROPS] = {
65 	{
66 		.property = ESPRESSIVO_URI"#through_zone_mask",
67 		.offset = offsetof(plugstate_t, zone_mask),
68 		.type = LV2_ATOM__Int,
69 	},
70 	{
71 		.property = ESPRESSIVO_URI"#through_zone_offset",
72 		.offset = offsetof(plugstate_t, zone_offset),
73 		.type = LV2_ATOM__Int,
74 	}
75 };
76 
77 static void
_add(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)78 _add(void *data, int64_t frames, const xpress_state_t *state,
79 	xpress_uuid_t uuid, void *target)
80 {
81 	plughandle_t *handle = data;
82 	targetI_t *src = target;
83 	src->zone_mask = 1 << state->zone;
84 
85 	if(src->zone_mask & handle->state.zone_mask)
86 	{
87 		LV2_Atom_Forge *forge = &handle->forge;
88 
89 		targetO_t *dst = xpress_create(&handle->xpressO, &src->uuid);
90 		(void)dst;
91 
92 		xpress_state_t new_state = *state;
93 		new_state.zone += handle->state.zone_offset;
94 
95 		if(handle->ref)
96 			handle->ref = xpress_token(&handle->xpressO, forge, frames, src->uuid, &new_state);
97 	}
98 }
99 
100 static void
_set(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)101 _set(void *data, int64_t frames, const xpress_state_t *state,
102 	xpress_uuid_t uuid, void *target)
103 {
104 	plughandle_t *handle = data;
105 	targetI_t *src = target;
106 
107 	if(src->zone_mask & handle->state.zone_mask)
108 	{
109 		LV2_Atom_Forge *forge = &handle->forge;
110 
111 		xpress_state_t new_state = *state;
112 		new_state.zone += handle->state.zone_offset;
113 
114 		if(handle->ref)
115 			handle->ref = xpress_token(&handle->xpressO, forge, frames, src->uuid, &new_state);
116 	}
117 }
118 
119 static void
_del(void * data,int64_t frames,xpress_uuid_t uuid,void * target)120 _del(void *data, int64_t frames,
121 	xpress_uuid_t uuid, void *target)
122 {
123 	plughandle_t *handle = data;
124 	targetI_t *src = target;
125 
126 	if(src->zone_mask & handle->state.zone_mask)
127 	{
128 		LV2_Atom_Forge *forge = &handle->forge;
129 
130 		xpress_free(&handle->xpressO, src->uuid);
131 
132 		if(handle->ref)
133 			handle->ref = xpress_alive(&handle->xpressO, forge, frames);
134 	}
135 }
136 
137 static const xpress_iface_t ifaceI = {
138 	.size = sizeof(targetI_t),
139 
140 	.add = _add,
141 	.set = _set,
142 	.del = _del
143 };
144 
145 static const xpress_iface_t ifaceO = {
146 	.size = sizeof(targetO_t)
147 };
148 
149 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)150 instantiate(const LV2_Descriptor* descriptor, double rate,
151 	const char *bundle_path, const LV2_Feature *const *features)
152 {
153 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
154 	if(!handle)
155 		return NULL;
156 
157 	xpress_map_t *voice_map = NULL;
158 
159 	for(unsigned i=0; features[i]; i++)
160 	{
161 		if(!strcmp(features[i]->URI, LV2_URID__map))
162 			handle->map = features[i]->data;
163 		else if(!strcmp(features[i]->URI, XPRESS__voiceMap))
164 			voice_map = features[i]->data;
165 	}
166 
167 	if(!handle->map)
168 	{
169 		fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
170 		free(handle);
171 		return NULL;
172 	}
173 
174 	lv2_atom_forge_init(&handle->forge, handle->map);
175 
176 	if(  !xpress_init(&handle->xpressI, MAX_NVOICES, handle->map, voice_map,
177 			XPRESS_EVENT_ALL, &ifaceI, handle->targetI, handle)
178 		|| !xpress_init(&handle->xpressO, MAX_NVOICES, handle->map, voice_map,
179 			XPRESS_EVENT_NONE, &ifaceO, handle->targetO, handle) )
180 	{
181 		free(handle);
182 		return NULL;
183 	}
184 
185 	if(!props_init(&handle->props, descriptor->URI,
186 		defs, MAX_NPROPS, &handle->state, &handle->stash,
187 		handle->map, handle))
188 	{
189 		fprintf(stderr, "failed to allocate property structure\n");
190 		free(handle);
191 		return NULL;
192 	}
193 
194 	return handle;
195 }
196 
197 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)198 connect_port(LV2_Handle instance, uint32_t port, void *data)
199 {
200 	plughandle_t *handle = instance;
201 
202 	switch(port)
203 	{
204 		case 0:
205 			handle->event_in = (const LV2_Atom_Sequence *)data;
206 			break;
207 		case 1:
208 			handle->event_out = (LV2_Atom_Sequence *)data;
209 			break;
210 		default:
211 			break;
212 	}
213 }
214 
215 static void
run(LV2_Handle instance,uint32_t nsamples)216 run(LV2_Handle instance, uint32_t nsamples)
217 {
218 	plughandle_t *handle = instance;
219 
220 	// prepare midi atom forge
221 	const uint32_t capacity = handle->event_out->atom.size;
222 	LV2_Atom_Forge *forge = &handle->forge;
223 	lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->event_out, capacity);
224 	LV2_Atom_Forge_Frame frame;
225 	handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
226 
227 	props_idle(&handle->props, forge, 0, &handle->ref);
228 	xpress_pre(&handle->xpressI);
229 	xpress_rst(&handle->xpressO);
230 
231 	LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev)
232 	{
233 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
234 		const int64_t frames = ev->time.frames;
235 
236 		if(!props_advance(&handle->props, forge, frames, obj, &handle->ref))
237 		{
238 			xpress_advance(&handle->xpressI, forge, frames, obj, &handle->ref);
239 		}
240 	}
241 
242 	xpress_post(&handle->xpressI, nsamples-1);
243 	if(handle->ref && !xpress_synced(&handle->xpressO))
244 		handle->ref = xpress_alive(&handle->xpressO, forge, nsamples-1);
245 
246 	if(handle->ref)
247 		lv2_atom_forge_pop(forge, &frame);
248 	else
249 		lv2_atom_sequence_clear(handle->event_out);
250 }
251 
252 static void
cleanup(LV2_Handle instance)253 cleanup(LV2_Handle instance)
254 {
255 	plughandle_t *handle = instance;
256 
257 	if(handle)
258 	{
259 		xpress_deinit(&handle->xpressI);
260 		xpress_deinit(&handle->xpressO);
261 		free(handle);
262 	}
263 }
264 
265 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)266 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
267 	LV2_State_Handle state, uint32_t flags,
268 	const LV2_Feature *const *features)
269 {
270 	plughandle_t *handle = instance;
271 
272 	return props_save(&handle->props, store, state, flags, features);
273 }
274 
275 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)276 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
277 	LV2_State_Handle state, uint32_t flags,
278 	const LV2_Feature *const *features)
279 {
280 	plughandle_t *handle = instance;
281 
282 	return props_restore(&handle->props, retrieve, state, flags, features);
283 }
284 
285 static const LV2_State_Interface state_iface = {
286 	.save = _state_save,
287 	.restore = _state_restore
288 };
289 
290 static const void *
extension_data(const char * uri)291 extension_data(const char *uri)
292 {
293 	if(!strcmp(uri, LV2_STATE__interface))
294 		return &state_iface;
295 	return NULL;
296 }
297 
298 const LV2_Descriptor through = {
299 	.URI						= ESPRESSIVO_THROUGH_URI,
300 	.instantiate		= instantiate,
301 	.connect_port		= connect_port,
302 	.activate				= NULL,
303 	.run						= run,
304 	.deactivate			= NULL,
305 	.cleanup				= cleanup,
306 	.extension_data	= extension_data
307 };
308