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 #include <math.h>
21
22 #include <espressivo.h>
23 #include <props.h>
24
25 #include <mpe.h>
26
27 #define MAX_NPROPS (4*0x10)
28
29 typedef struct _targetI_t targetI_t;
30 typedef struct _plugstate_t plugstate_t;
31 typedef struct _plughandle_t plughandle_t;
32
33 typedef enum _pressure_mode_t
34 {
35 MODE_CONTROLLER = 0,
36 MODE_NOTE_PRESSURE = 1,
37 MODE_CHANNEL_PRESSURE = 2,
38 MODE_NOTE_VELOCITY = 3
39 } pressure_mode_t;
40
41 struct _targetI_t {
42 uint8_t chan;
43 uint8_t key;
44
45 float range; //FIXME use this
46 uint8_t pressure; //FIXME use this
47 uint8_t timbre; //FIXME use this
48 pressure_mode_t mode; //FIXME use this
49 };
50
51 struct _plugstate_t {
52 float range [0x10];
53 int32_t pressure [0x10];
54 int32_t timbre [0x10];
55 int32_t mode [0x10];
56 };
57
58 struct _plughandle_t {
59 struct {
60 LV2_URID midi_MidiEvent;
61 } uris;
62
63 LV2_URID_Map *map;
64 LV2_Atom_Forge forge;
65 LV2_Atom_Forge_Ref ref;
66
67 XPRESS_T(xpressI, MAX_NVOICES);
68 targetI_t targetI [MAX_NVOICES];
69
70 const LV2_Atom_Sequence *event_in;
71 LV2_Atom_Sequence *event_out;
72
73 PROPS_T(props, MAX_NPROPS);
74
75 plugstate_t state;
76 plugstate_t stash;
77 };
78
79 static inline LV2_Atom_Forge_Ref
_midi_event(plughandle_t * handle,int64_t frames,const uint8_t * m,size_t len)80 _midi_event(plughandle_t *handle, int64_t frames, const uint8_t *m, size_t len)
81 {
82 LV2_Atom_Forge *forge = &handle->forge;
83 LV2_Atom_Forge_Ref ref;
84
85 ref = lv2_atom_forge_frame_time(forge, frames);
86 if(ref)
87 ref = lv2_atom_forge_atom(forge, len, handle->uris.midi_MidiEvent);
88 if(ref)
89 ref = lv2_atom_forge_write(forge, m, len);
90
91 return ref;
92 }
93
94 static void
_intercept_midi_range(void * data,int64_t frames,props_impl_t * impl)95 _intercept_midi_range(void *data, int64_t frames, props_impl_t *impl)
96 {
97 plughandle_t *handle = data;
98
99 const size_t chan = (float *)impl->value.body - handle->state.range;
100
101 if(chan <= 0xf)
102 {
103 const uint8_t rpn_lsb [3] = {
104 LV2_MIDI_MSG_CONTROLLER | chan,
105 LV2_MIDI_CTL_RPN_LSB,
106 0x0
107 };
108
109 const uint8_t rpn_msb [3] = {
110 LV2_MIDI_MSG_CONTROLLER | chan,
111 LV2_MIDI_CTL_RPN_MSB,
112 0x0
113 };
114
115 const float range = handle->state.range[chan];
116 const uint8_t semis = floorf(range);
117 const uint8_t cents = floorf( (range - semis) * 100.f);
118
119 const uint8_t data_lsb [3] = {
120 LV2_MIDI_MSG_CONTROLLER | chan,
121 LV2_MIDI_CTL_LSB_DATA_ENTRY,
122 cents
123 };
124
125 const uint8_t data_msb [3] = {
126 LV2_MIDI_MSG_CONTROLLER | chan,
127 LV2_MIDI_CTL_MSB_DATA_ENTRY,
128 semis
129 };
130
131 if(handle->ref)
132 handle->ref = _midi_event(handle, frames, rpn_lsb, 3);
133 if(handle->ref)
134 handle->ref = _midi_event(handle, frames, rpn_msb, 3);
135 if(handle->ref)
136 handle->ref = _midi_event(handle, frames, data_lsb, 3);
137 if(handle->ref)
138 handle->ref = _midi_event(handle, frames, data_msb, 3);
139 }
140 }
141
142 #define RANGE(NUM) \
143 { \
144 .property = ESPRESSIVO_URI"#midi_range_"#NUM, \
145 .offset = offsetof(plugstate_t, range) + (NUM-1)*sizeof(float), \
146 .type = LV2_ATOM__Float, \
147 .event_cb = _intercept_midi_range, \
148 }
149
150 #define PRESSURE(NUM) \
151 { \
152 .property = ESPRESSIVO_URI"#midi_pressure_"#NUM, \
153 .offset = offsetof(plugstate_t, pressure) + (NUM-1)*sizeof(int32_t), \
154 .type = LV2_ATOM__Int, \
155 }
156
157 #define TIMBRE(NUM) \
158 { \
159 .property = ESPRESSIVO_URI"#midi_timbre_"#NUM, \
160 .offset = offsetof(plugstate_t, timbre) + (NUM-1)*sizeof(int32_t), \
161 .type = LV2_ATOM__Int, \
162 }
163
164 #define MODE(NUM) \
165 { \
166 .property = ESPRESSIVO_URI"#midi_pressure_mode_"#NUM, \
167 .offset = offsetof(plugstate_t, mode) + (NUM-1)*sizeof(int32_t), \
168 .type = LV2_ATOM__Int, \
169 }
170
171 static const props_def_t defs [MAX_NPROPS] = {
172 RANGE(1),
173 RANGE(2),
174 RANGE(3),
175 RANGE(4),
176 RANGE(5),
177 RANGE(6),
178 RANGE(7),
179 RANGE(8),
180 RANGE(9),
181 RANGE(10),
182 RANGE(11),
183 RANGE(12),
184 RANGE(13),
185 RANGE(14),
186 RANGE(15),
187 RANGE(16),
188
189 PRESSURE(1),
190 PRESSURE(2),
191 PRESSURE(3),
192 PRESSURE(4),
193 PRESSURE(5),
194 PRESSURE(6),
195 PRESSURE(7),
196 PRESSURE(8),
197 PRESSURE(9),
198 PRESSURE(10),
199 PRESSURE(11),
200 PRESSURE(12),
201 PRESSURE(13),
202 PRESSURE(14),
203 PRESSURE(15),
204 PRESSURE(16),
205
206 TIMBRE(1),
207 TIMBRE(2),
208 TIMBRE(3),
209 TIMBRE(4),
210 TIMBRE(5),
211 TIMBRE(6),
212 TIMBRE(7),
213 TIMBRE(8),
214 TIMBRE(9),
215 TIMBRE(10),
216 TIMBRE(11),
217 TIMBRE(12),
218 TIMBRE(13),
219 TIMBRE(14),
220 TIMBRE(15),
221 TIMBRE(16),
222
223 MODE(1),
224 MODE(2),
225 MODE(3),
226 MODE(4),
227 MODE(5),
228 MODE(6),
229 MODE(7),
230 MODE(8),
231 MODE(9),
232 MODE(10),
233 MODE(11),
234 MODE(12),
235 MODE(13),
236 MODE(14),
237 MODE(15),
238 MODE(16)
239 };
240
241 static inline void
_upd(plughandle_t * handle,int64_t frames,const xpress_state_t * state,float val,targetI_t * src)242 _upd(plughandle_t *handle, int64_t frames, const xpress_state_t *state,
243 float val, targetI_t *src)
244 {
245 // bender
246 {
247 const uint16_t bnd = (val - src->key) * src->range * 0x1fff + 0x2000;
248 const uint8_t bnd_msb = bnd >> 7;
249 const uint8_t bnd_lsb = bnd & 0x7f;
250
251 const uint8_t bend [3] = {
252 LV2_MIDI_MSG_BENDER | src->chan,
253 bnd_lsb,
254 bnd_msb
255 };
256
257 if(handle->ref)
258 handle->ref = _midi_event(handle, frames, bend, 3);
259 }
260
261 // pressure
262 {
263 const uint16_t z = state->pressure * 0x3fff;
264 const uint8_t z_msb = z >> 7;
265 const uint8_t z_lsb = z & 0x7f;
266
267 switch(src->mode)
268 {
269 case MODE_NOTE_PRESSURE:
270 {
271 const uint8_t note_pressure [3] = {
272 LV2_MIDI_MSG_NOTE_PRESSURE | src->chan,
273 src->key,
274 z_msb
275 };
276
277 if(handle->ref)
278 handle->ref = _midi_event(handle, frames, note_pressure, 3);
279 } break;
280 case MODE_CHANNEL_PRESSURE:
281 {
282 const uint8_t channel_pressure [2] = {
283 LV2_MIDI_MSG_CHANNEL_PRESSURE | src->chan,
284 z_msb
285 };
286
287 if(handle->ref)
288 handle->ref = _midi_event(handle, frames, channel_pressure, 2);
289 } break;
290 case MODE_CONTROLLER:
291 {
292 const uint8_t pressure_lsb [3] = {
293 LV2_MIDI_MSG_CONTROLLER | src->chan,
294 src->pressure | 0x20,
295 z_lsb
296 };
297
298 const uint8_t pressure_msb [3] = {
299 LV2_MIDI_MSG_CONTROLLER | src->chan,
300 src->pressure,
301 z_msb
302 };
303
304 if(handle->ref)
305 handle->ref = _midi_event(handle, frames, pressure_lsb, 3);
306 if(handle->ref)
307 handle->ref = _midi_event(handle, frames, pressure_msb, 3);
308 } break;
309 case MODE_NOTE_VELOCITY:
310 {
311 // nothing to do
312 } break;
313 }
314 }
315
316 // timbre
317 {
318 const uint16_t z = state->timbre * 0x3fff;
319 const uint8_t z_msb = z >> 7;
320 const uint8_t z_lsb = z & 0x7f;
321
322 const uint8_t timbre_lsb [3] = {
323 LV2_MIDI_MSG_CONTROLLER | src->chan,
324 src->timbre | 0x20,
325 z_lsb
326 };
327
328 const uint8_t timbre_msb [3] = {
329 LV2_MIDI_MSG_CONTROLLER | src->chan,
330 src->timbre,
331 z_msb
332 };
333
334 if(handle->ref)
335 handle->ref = _midi_event(handle, frames, timbre_lsb, 3);
336 if(handle->ref)
337 handle->ref = _midi_event(handle, frames, timbre_msb, 3);
338 }
339
340 // FIXME dPitch, dPressure, dTimbre
341 }
342
343 static void
_add(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)344 _add(void *data, int64_t frames, const xpress_state_t *state,
345 xpress_uuid_t uuid, void *target)
346 {
347 plughandle_t *handle = data;
348 targetI_t *src = target;
349
350 const float val = state->pitch * 0x7f;
351
352 // these will remain fixed per note
353 src->chan = state->zone;
354 src->key = floorf(val);
355 src->mode = handle->state.mode[state->zone];
356 src->range = handle->state.range[state->zone];
357 src->pressure = handle->state.pressure[state->zone];
358 src->timbre = handle->state.timbre[state->zone];
359
360 const uint8_t vel = (src->mode == MODE_NOTE_VELOCITY)
361 ? state->pressure * 0x7f
362 : 0x7f; //FIXME make this configurable
363
364 const uint8_t note_on [3] = {
365 LV2_MIDI_MSG_NOTE_ON | src->chan,
366 src->key,
367 vel
368 };
369
370 if(handle->ref)
371 handle->ref = _midi_event(handle, frames, note_on, 3);
372
373 _upd(handle, frames, state, val, src);
374 }
375
376 static void
_set(void * data,int64_t frames,const xpress_state_t * state,xpress_uuid_t uuid,void * target)377 _set(void *data, int64_t frames, const xpress_state_t *state,
378 xpress_uuid_t uuid, void *target)
379 {
380 plughandle_t *handle = data;
381 targetI_t *src = target;
382
383 const float val = state->pitch * 0x7f;
384
385 _upd(handle, frames, state, val, src);
386 }
387
388 static void
_del(void * data,int64_t frames,xpress_uuid_t uuid,void * target)389 _del(void *data, int64_t frames,
390 xpress_uuid_t uuid, void *target)
391 {
392 plughandle_t *handle = data;
393 targetI_t *src = target;
394
395 const uint8_t vel = 0x0; //FIXME maybe we want src->pressure here ?
396
397 const uint8_t note_off [3] = {
398 LV2_MIDI_MSG_NOTE_OFF | src->chan,
399 src->key,
400 vel
401 };
402
403 if(handle->ref)
404 handle->ref = _midi_event(handle, frames, note_off, 3);
405 }
406
407 static const xpress_iface_t ifaceI = {
408 .size = sizeof(targetI_t),
409
410 .add = _add,
411 .set = _set,
412 .del = _del
413 };
414
415 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)416 instantiate(const LV2_Descriptor* descriptor, double rate,
417 const char *bundle_path, const LV2_Feature *const *features)
418 {
419 plughandle_t *handle = calloc(1, sizeof(plughandle_t));
420 if(!handle)
421 return NULL;
422
423 xpress_map_t *voice_map = NULL;
424
425 for(unsigned i=0; features[i]; i++)
426 {
427 if(!strcmp(features[i]->URI, LV2_URID__map))
428 handle->map = features[i]->data;
429 else if(!strcmp(features[i]->URI, XPRESS__voiceMap))
430 voice_map = features[i]->data;
431 }
432
433 if(!handle->map)
434 {
435 fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
436 free(handle);
437 return NULL;
438 }
439
440 handle->uris.midi_MidiEvent = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
441
442 lv2_atom_forge_init(&handle->forge, handle->map);
443
444 if(!xpress_init(&handle->xpressI, MAX_NVOICES, handle->map, voice_map,
445 XPRESS_EVENT_ALL, &ifaceI, handle->targetI, handle))
446 {
447 free(handle);
448 return NULL;
449 }
450
451 if(!props_init(&handle->props, descriptor->URI,
452 defs, MAX_NPROPS, &handle->state, &handle->stash,
453 handle->map, handle))
454 {
455 free(handle);
456 return NULL;
457 }
458
459 return handle;
460 }
461
462 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)463 connect_port(LV2_Handle instance, uint32_t port, void *data)
464 {
465 plughandle_t *handle = instance;
466
467 switch(port)
468 {
469 case 0:
470 handle->event_in = (const LV2_Atom_Sequence *)data;
471 break;
472 case 1:
473 handle->event_out = (LV2_Atom_Sequence *)data;
474 break;
475 default:
476 break;
477 }
478 }
479
480 static void
run(LV2_Handle instance,uint32_t nsamples)481 run(LV2_Handle instance, uint32_t nsamples)
482 {
483 plughandle_t *handle = instance;
484
485 // prepare midi atom forge
486 const uint32_t capacity = handle->event_out->atom.size;
487 LV2_Atom_Forge *forge = &handle->forge;
488 lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->event_out, capacity);
489 LV2_Atom_Forge_Frame frame;
490 handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
491
492 props_idle(&handle->props, forge, 0, &handle->ref);
493 xpress_pre(&handle->xpressI);
494
495 LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev)
496 {
497 const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
498 const int64_t frames = ev->time.frames;
499
500 if(!props_advance(&handle->props, forge, frames, obj, &handle->ref))
501 {
502 xpress_advance(&handle->xpressI, forge, frames, obj, &handle->ref);
503 }
504 }
505
506 xpress_post(&handle->xpressI, nsamples-1);
507
508 if(handle->ref)
509 lv2_atom_forge_pop(forge, &frame);
510 else
511 lv2_atom_sequence_clear(handle->event_out);
512 }
513
514 static void
cleanup(LV2_Handle instance)515 cleanup(LV2_Handle instance)
516 {
517 plughandle_t *handle = instance;
518
519 if(handle)
520 {
521 xpress_deinit(&handle->xpressI);
522 free(handle);
523 }
524 }
525
526 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)527 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
528 LV2_State_Handle state, uint32_t flags,
529 const LV2_Feature *const *features)
530 {
531 plughandle_t *handle = instance;
532
533 return props_save(&handle->props, store, state, flags, features);
534 }
535
536 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)537 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
538 LV2_State_Handle state, uint32_t flags,
539 const LV2_Feature *const *features)
540 {
541 plughandle_t *handle = instance;
542
543 return props_restore(&handle->props, retrieve, state, flags, features);
544 }
545
546 static const LV2_State_Interface state_iface = {
547 .save = _state_save,
548 .restore = _state_restore
549 };
550
551 static const void *
extension_data(const char * uri)552 extension_data(const char *uri)
553 {
554 if(!strcmp(uri, LV2_STATE__interface))
555 return &state_iface;
556 return NULL;
557 }
558
559 const LV2_Descriptor midi_out = {
560 .URI = ESPRESSIVO_MIDI_OUT_URI,
561 .instantiate = instantiate,
562 .connect_port = connect_port,
563 .activate = NULL,
564 .run = run,
565 .deactivate = NULL,
566 .cleanup = cleanup,
567 .extension_data = extension_data
568 };
569