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