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 (4*0x10)
26
27 typedef struct _targetO_t targetO_t;
28 typedef struct _plugstate_t plugstate_t;
29 typedef struct _plughandle_t plughandle_t;
30
31 typedef enum _pressure_mode_t
32 {
33 MODE_CONTROLLER = 0,
34 MODE_NOTE_PRESSURE = 1,
35 MODE_CHANNEL_PRESSURE = 2,
36 MODE_NOTE_VELOCITY = 3
37 } pressure_mode_t;
38
39 struct _targetO_t {
40 uint8_t chan;
41 uint8_t key;
42 xpress_uuid_t uuid;
43
44 xpress_state_t state;
45
46 float range;
47 uint8_t pressure;
48 uint8_t timbre;
49 pressure_mode_t mode;
50
51 uint8_t pressure_lsb;
52 uint8_t timbre_lsb;
53 };
54
55 struct _plugstate_t {
56 float range [0x10];
57 int32_t pressure [0x10];
58 int32_t timbre [0x10];
59 int32_t mode [0x10];
60 };
61
62 struct _plughandle_t {
63 LV2_URID_Map *map;
64 struct {
65 LV2_URID midi_MidiEvent;
66 LV2_URID range [0x10];
67 } uris;
68 LV2_Atom_Forge forge;
69 LV2_Atom_Forge_Ref ref;
70
71 const LV2_Atom_Sequence *control;
72 LV2_Atom_Sequence *notify;
73
74 PROPS_T(props, MAX_NPROPS);
75
76 XPRESS_T(xpressO, MAX_NVOICES);
77 targetO_t targetO [MAX_NVOICES];
78
79 plugstate_t state;
80 plugstate_t stash;
81
82 uint16_t midi_rpn [0x10];
83 uint16_t midi_data [0x10];
84 int16_t midi_bender [0x10];
85 };
86
87 static const targetO_t targetO_vanilla;
88
89 static inline float
_get_pitch(plughandle_t * handle,targetO_t * target)90 _get_pitch(plughandle_t *handle, targetO_t *target)
91 {
92 const float offset = handle->midi_bender[target->chan] / 0x1fff * target->range;
93
94 return ((float)target->key + offset) / 0x7f;
95 }
96
97 #define RANGE(NUM) \
98 { \
99 .property = ESPRESSIVO_URI"#midi_range_"#NUM, \
100 .offset = offsetof(plugstate_t, range) + (NUM-1)*sizeof(float), \
101 .type = LV2_ATOM__Float, \
102 }
103
104 #define PRESSURE(NUM) \
105 { \
106 .property = ESPRESSIVO_URI"#midi_pressure_controller_"#NUM, \
107 .offset = offsetof(plugstate_t, pressure) + (NUM-1)*sizeof(int32_t), \
108 .type = LV2_ATOM__Int, \
109 }
110
111 #define TIMBRE(NUM) \
112 { \
113 .property = ESPRESSIVO_URI"#midi_timbre_controller_"#NUM, \
114 .offset = offsetof(plugstate_t, timbre) + (NUM-1)*sizeof(int32_t), \
115 .type = LV2_ATOM__Int, \
116 }
117
118 #define MODE(NUM) \
119 { \
120 .property = ESPRESSIVO_URI"#midi_pressure_mode_"#NUM, \
121 .offset = offsetof(plugstate_t, mode) + (NUM-1)*sizeof(int32_t), \
122 .type = LV2_ATOM__Int, \
123 }
124
125 static const props_def_t defs [MAX_NPROPS] = {
126 RANGE(1),
127 RANGE(2),
128 RANGE(3),
129 RANGE(4),
130 RANGE(5),
131 RANGE(6),
132 RANGE(7),
133 RANGE(8),
134 RANGE(9),
135 RANGE(10),
136 RANGE(11),
137 RANGE(12),
138 RANGE(13),
139 RANGE(14),
140 RANGE(15),
141 RANGE(16),
142
143 PRESSURE(1),
144 PRESSURE(2),
145 PRESSURE(3),
146 PRESSURE(4),
147 PRESSURE(5),
148 PRESSURE(6),
149 PRESSURE(7),
150 PRESSURE(8),
151 PRESSURE(9),
152 PRESSURE(10),
153 PRESSURE(11),
154 PRESSURE(12),
155 PRESSURE(13),
156 PRESSURE(14),
157 PRESSURE(15),
158 PRESSURE(16),
159
160 TIMBRE(1),
161 TIMBRE(2),
162 TIMBRE(3),
163 TIMBRE(4),
164 TIMBRE(5),
165 TIMBRE(6),
166 TIMBRE(7),
167 TIMBRE(8),
168 TIMBRE(9),
169 TIMBRE(10),
170 TIMBRE(11),
171 TIMBRE(12),
172 TIMBRE(13),
173 TIMBRE(14),
174 TIMBRE(15),
175 TIMBRE(16),
176
177 MODE(1),
178 MODE(2),
179 MODE(3),
180 MODE(4),
181 MODE(5),
182 MODE(6),
183 MODE(7),
184 MODE(8),
185 MODE(9),
186 MODE(10),
187 MODE(11),
188 MODE(12),
189 MODE(13),
190 MODE(14),
191 MODE(15),
192 MODE(16)
193 };
194
195 static const xpress_iface_t ifaceO = {
196 .size = sizeof(targetO_t)
197 };
198
199 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)200 instantiate(const LV2_Descriptor* descriptor, double rate,
201 const char *bundle_path, const LV2_Feature *const *features)
202 {
203 plughandle_t *handle = calloc(1, sizeof(plughandle_t));
204 if(!handle)
205 return NULL;
206
207 xpress_map_t *voice_map = NULL;
208
209 for(unsigned i=0; features[i]; i++)
210 {
211 if(!strcmp(features[i]->URI, LV2_URID__map))
212 handle->map = features[i]->data;
213 else if(!strcmp(features[i]->URI, ESPRESSIVO_URI"#voiceMap"))
214 voice_map = features[i]->data;
215 }
216
217 if(!handle->map)
218 {
219 fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
220 free(handle);
221 return NULL;
222 }
223
224 handle->uris.midi_MidiEvent = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
225 handle->uris.range[0x0] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_1");
226 handle->uris.range[0x1] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_2");
227 handle->uris.range[0x2] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_3");
228 handle->uris.range[0x3] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_4");
229 handle->uris.range[0x4] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_5");
230 handle->uris.range[0x5] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_6");
231 handle->uris.range[0x6] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_7");
232 handle->uris.range[0x7] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_8");
233 handle->uris.range[0x8] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_9");
234 handle->uris.range[0x9] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_10");
235 handle->uris.range[0xa] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_11");
236 handle->uris.range[0xb] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_12");
237 handle->uris.range[0xc] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_13");
238 handle->uris.range[0xd] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_14");
239 handle->uris.range[0xe] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_15");
240 handle->uris.range[0xf] = handle->map->map(handle->map->handle, ESPRESSIVO_URI"#midi_range_16");
241
242 lv2_atom_forge_init(&handle->forge, handle->map);
243
244 if( !xpress_init(&handle->xpressO, MAX_NVOICES, handle->map, voice_map,
245 XPRESS_EVENT_NONE, &ifaceO, handle->targetO, handle) )
246 {
247 free(handle);
248 return NULL;
249 }
250
251 if(!props_init(&handle->props, descriptor->URI,
252 defs, MAX_NPROPS, &handle->state, &handle->stash,
253 handle->map, handle))
254 {
255 fprintf(stderr, "failed to allocate property structure\n");
256 free(handle);
257 return NULL;
258 }
259
260 return handle;
261 }
262
263 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)264 connect_port(LV2_Handle instance, uint32_t port, void *data)
265 {
266 plughandle_t *handle = instance;
267
268 switch(port)
269 {
270 case 0:
271 handle->control = (const LV2_Atom_Sequence *)data;
272 break;
273 case 1:
274 handle->notify = (LV2_Atom_Sequence *)data;
275 break;
276 default:
277 break;
278 }
279 }
280
281 static targetO_t *
_midi_get(plughandle_t * handle,uint8_t chan,uint8_t key,xpress_uuid_t * uuid)282 _midi_get(plughandle_t *handle, uint8_t chan, uint8_t key, xpress_uuid_t *uuid)
283 {
284 XPRESS_VOICE_FOREACH(&handle->xpressO, voice)
285 {
286 targetO_t *dst = voice->target;
287
288 if( (dst->chan == chan) && (dst->key == key) )
289 {
290 *uuid = voice->uuid;
291 return dst;
292 }
293 }
294
295 *uuid = 0;
296 return NULL;
297 }
298
299 static void
_handle_midi_note_on(plughandle_t * handle,LV2_Atom_Forge * forge,int64_t frames,const uint8_t * m)300 _handle_midi_note_on(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames,
301 const uint8_t *m)
302 {
303 const uint8_t chan = m[0] & 0x0f;
304 const uint8_t key = m[1];
305
306 xpress_uuid_t uuid;
307 targetO_t *target = xpress_create(&handle->xpressO, &uuid);
308 if(target)
309 {
310 *target = targetO_vanilla;
311
312 // these will remain fixed per note
313 target->chan = chan;
314 target->key = key;
315 target->uuid = uuid;
316 target->range = handle->state.range[chan];
317 target->mode = handle->state.mode[chan];
318 target->pressure = handle->state.pressure[chan];
319 target->timbre = handle->state.timbre[chan];
320
321 const float pressure = (target->mode == MODE_NOTE_VELOCITY)
322 ? (float)m[2] / 0x7f
323 : 0.f; //FIXME make this configurable
324
325 target->state.zone = chan;
326 target->state.pitch = _get_pitch(handle, target);
327 target->state.pressure = pressure;
328
329 if(handle->ref)
330 handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
331 }
332 }
333
334 static void
_handle_midi_note_off(plughandle_t * handle,LV2_Atom_Forge * forge,int64_t frames,const uint8_t * m)335 _handle_midi_note_off(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames,
336 const uint8_t *m)
337 {
338 const uint8_t chan = m[0] & 0x0f;
339 const uint8_t key = m[1];
340
341 xpress_uuid_t uuid;
342 targetO_t *target = _midi_get(handle, chan, key, &uuid);
343 if(target)
344 {
345 xpress_free(&handle->xpressO, uuid);
346
347 if(handle->ref)
348 handle->ref = xpress_alive(&handle->xpressO, forge, frames);
349 }
350 }
351
352 static void
_handle_midi_note_pressure(plughandle_t * handle,LV2_Atom_Forge * forge,int64_t frames,const uint8_t * m)353 _handle_midi_note_pressure(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames,
354 const uint8_t *m)
355 {
356 const uint8_t chan = m[0] & 0x0f;
357 const uint8_t key = m[1];
358
359 xpress_uuid_t uuid;
360 targetO_t *target = _midi_get(handle, chan, key, &uuid);
361 if(target && (target->mode == MODE_NOTE_PRESSURE))
362 {
363 const float pressure = (float)m[2] / 0x7f;
364 target->state.pressure = pressure;
365
366 if(handle->ref)
367 handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
368 }
369 }
370
371 static void
_handle_midi_channel_pressure(plughandle_t * handle,LV2_Atom_Forge * forge,int64_t frames,const uint8_t * m)372 _handle_midi_channel_pressure(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames,
373 const uint8_t *m)
374 {
375 const uint8_t chan = m[0] & 0x0f;
376
377 // set pressure on all notes with matching channel
378 XPRESS_VOICE_FOREACH(&handle->xpressO, voice)
379 {
380 targetO_t *target = voice->target;
381
382 if(target && (target->chan == chan) && (target->mode == MODE_CHANNEL_PRESSURE) )
383 {
384 const float pressure = (float)m[1] / 0x7f;
385 target->state.pressure = pressure;
386
387 if(handle->ref)
388 handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
389 }
390 }
391 }
392
393 static void
_handle_midi_bender(plughandle_t * handle,LV2_Atom_Forge * forge,int64_t frames,const uint8_t * m)394 _handle_midi_bender(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames,
395 const uint8_t *m)
396 {
397 const uint8_t chan = m[0] & 0x0f;
398
399 handle->midi_bender[chan] = (((int16_t)m[2] << 7) | m[1]) - 0x2000;
400
401 XPRESS_VOICE_FOREACH(&handle->xpressO, voice)
402 {
403 targetO_t *target = voice->target;
404
405 if(target->chan != chan)
406 continue; // channel not matching
407
408 target->state.pitch = _get_pitch(handle, target);
409
410 if(handle->ref)
411 handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
412 }
413 }
414
415 static void
_handle_midi_controller(plughandle_t * handle,LV2_Atom_Forge * forge,int64_t frames,const uint8_t * m)416 _handle_midi_controller(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames,
417 const uint8_t *m)
418 {
419 const uint8_t chan = m[0] & 0x0f;
420 const uint8_t controller = m[1];
421 const uint8_t value = m[2];
422
423 switch(controller)
424 {
425 case LV2_MIDI_CTL_RPN_LSB:
426 {
427 handle->midi_rpn[chan] &= 0x3f80; // clear LSB
428 handle->midi_rpn[chan] |= m[2];
429 } break;
430 case LV2_MIDI_CTL_RPN_MSB:
431 {
432 handle->midi_rpn[chan] &= 0x7f; // clear MSB
433 handle->midi_rpn[chan] |= m[2] << 7;
434 } break;
435
436 case LV2_MIDI_CTL_LSB_DATA_ENTRY:
437 {
438 handle->midi_data[chan] &= 0x3f80; // clear LSB
439 handle->midi_data[chan] |= m[2];
440 } break;
441 case LV2_MIDI_CTL_MSB_DATA_ENTRY:
442 {
443 handle->midi_data[chan] &= 0x7f; // clear MSB
444 handle->midi_data[chan] |= m[2] << 7;
445
446 switch(handle->midi_rpn[chan])
447 {
448 case 0x0: // MIDI pitch bend range
449 {
450 const uint8_t semi = handle->midi_data[chan] >> 7; // MSB
451 const uint8_t cent = handle->midi_data[chan] & 0x7f; // LSB
452
453 handle->state.range[chan] = (float)semi + cent*0.01f;
454
455 props_set(&handle->props, &handle->forge, frames,
456 handle->uris.range[chan], &handle->ref);
457 } break;
458 }
459 } break;
460
461 default:
462 {
463 XPRESS_VOICE_FOREACH(&handle->xpressO, voice)
464 {
465 targetO_t *target = voice->target;
466 bool put = false;
467
468 if( (target->chan != chan) || (target->mode != MODE_CONTROLLER) )
469 {
470 continue; // channel and/or mode not matching
471 }
472
473 if(controller == (target->pressure | 0x20))
474 {
475 target->pressure_lsb = value;
476 }
477 else if(controller == target->pressure)
478 {
479 target->state.pressure = (float)( (value << 7) | target->pressure_lsb) / 0x3fff;
480 put = true;
481 }
482 else if(controller == (target->timbre | 0x20))
483 {
484 target->timbre_lsb = value;
485 }
486 else if(controller == target->timbre)
487 {
488 target->state.timbre = (float)( (value << 7) | target->timbre_lsb) / 0x3fff;
489 put = true;
490 }
491
492 if(put)
493 {
494 if(handle->ref)
495 handle->ref = xpress_token(&handle->xpressO, forge, frames, target->uuid, &target->state);
496 }
497 }
498 } break;
499 }
500 }
501
502 static void
_handle_midi(plughandle_t * handle,LV2_Atom_Forge * forge,int64_t frames,const uint8_t * m)503 _handle_midi(plughandle_t *handle, LV2_Atom_Forge *forge, int64_t frames,
504 const uint8_t *m)
505 {
506 const uint8_t comm = m[0] & 0xf0;
507
508 switch(comm)
509 {
510 case LV2_MIDI_MSG_NOTE_ON:
511 {
512 _handle_midi_note_on(handle, forge, frames, m);
513 } break;
514 case LV2_MIDI_MSG_NOTE_OFF:
515 {
516 _handle_midi_note_off(handle, forge, frames, m);
517 } break;
518 case LV2_MIDI_MSG_NOTE_PRESSURE:
519 {
520 _handle_midi_note_pressure(handle, forge, frames, m);
521 } break;
522 case LV2_MIDI_MSG_CHANNEL_PRESSURE:
523 {
524 _handle_midi_channel_pressure(handle, forge, frames, m);
525 } break;
526 case LV2_MIDI_MSG_BENDER:
527 {
528 _handle_midi_bender(handle, forge, frames, m);
529 } break;
530 case LV2_MIDI_MSG_CONTROLLER:
531 {
532 _handle_midi_controller(handle, forge, frames, m);
533 } break;
534 }
535 }
536
537 static void
run(LV2_Handle instance,uint32_t nsamples)538 run(LV2_Handle instance, uint32_t nsamples)
539 {
540 plughandle_t *handle = instance;
541
542 // prepare midi atom forge
543 const uint32_t capacity = handle->notify->atom.size;
544 LV2_Atom_Forge *forge = &handle->forge;
545 lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->notify, capacity);
546 LV2_Atom_Forge_Frame frame;
547 handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
548
549 props_idle(&handle->props, forge, 0, &handle->ref);
550 xpress_rst(&handle->xpressO);
551
552 LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev)
553 {
554 const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
555 const int64_t frames = ev->time.frames;
556
557 if(obj->atom.type == handle->uris.midi_MidiEvent)
558 {
559 const uint8_t *m = LV2_ATOM_BODY_CONST(&obj->atom);
560
561 _handle_midi(handle, forge, frames, m);
562 }
563 else
564 {
565 props_advance(&handle->props, forge, frames, obj, &handle->ref);
566 }
567 }
568
569 if(handle->ref && !xpress_synced(&handle->xpressO))
570 handle->ref = xpress_alive(&handle->xpressO, forge, nsamples-1);
571
572 if(handle->ref)
573 lv2_atom_forge_pop(forge, &frame);
574 else
575 lv2_atom_sequence_clear(handle->notify);
576 }
577
578 static void
cleanup(LV2_Handle instance)579 cleanup(LV2_Handle instance)
580 {
581 plughandle_t *handle = instance;
582
583 if(handle)
584 {
585 xpress_deinit(&handle->xpressO);
586 free(handle);
587 }
588 }
589
590 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)591 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
592 LV2_State_Handle state, uint32_t flags,
593 const LV2_Feature *const *features)
594 {
595 plughandle_t *handle = instance;
596
597 return props_save(&handle->props, store, state, flags, features);
598 }
599
600 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)601 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
602 LV2_State_Handle state, uint32_t flags,
603 const LV2_Feature *const *features)
604 {
605 plughandle_t *handle = instance;
606
607 return props_restore(&handle->props, retrieve, state, flags, features);
608 }
609
610 static const LV2_State_Interface state_iface = {
611 .save = _state_save,
612 .restore = _state_restore
613 };
614
615 static const void *
extension_data(const char * uri)616 extension_data(const char *uri)
617 {
618 if(!strcmp(uri, LV2_STATE__interface))
619 return &state_iface;
620 return NULL;
621 }
622
623 const LV2_Descriptor midi_in = {
624 .URI = ESPRESSIVO_MIDI_IN_URI,
625 .instantiate = instantiate,
626 .connect_port = connect_port,
627 .activate = NULL,
628 .run = run,
629 .deactivate = NULL,
630 .cleanup = cleanup,
631 .extension_data = extension_data
632 };
633