prevent a unlikely race: concurrent restore() + work_response ()
[ardour.git] / libs / plugins / a-fluidsynth.lv2 / a-fluidsynth.c
1 /* a-fluidsynth -- simple & robust x-platform fluidsynth LV2
2  *
3  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27
28 #define AFS_URN "urn:ardour:a-fluidsynth"
29
30 #ifdef HAVE_LV2_1_10_0
31 #define x_forge_object lv2_atom_forge_object
32 #else
33 #define x_forge_object lv2_atom_forge_blank
34 #endif
35
36 #include "fluidsynth.h"
37
38 #include <lv2/lv2plug.in/ns/lv2core/lv2.h>
39 #include <lv2/lv2plug.in/ns/ext/atom/atom.h>
40 #include <lv2/lv2plug.in/ns/ext/atom/forge.h>
41 #include <lv2/lv2plug.in/ns/ext/atom/util.h>
42 #include <lv2/lv2plug.in/ns/ext/log/logger.h>
43 #include <lv2/lv2plug.in/ns/ext/midi/midi.h>
44 #include <lv2/lv2plug.in/ns/ext/patch/patch.h>
45 #include <lv2/lv2plug.in/ns/ext/state/state.h>
46 #include <lv2/lv2plug.in/ns/ext/urid/urid.h>
47 #include <lv2/lv2plug.in/ns/ext/worker/worker.h>
48
49 enum {
50         FS_PORT_CONTROL = 0,
51         FS_PORT_NOTIFY,
52         FS_PORT_OUT_L,
53         FS_PORT_OUT_R,
54         FS_OUT_GAIN,
55         FS_REV_ENABLE,
56         FS_REV_ROOMSIZE,
57         FS_REV_DAMPING,
58         FS_REV_WIDTH,
59         FS_REV_LEVEL,
60         FS_CHR_ENABLE,
61         FS_CHR_N,
62         FS_CHR_SPEED,
63         FS_CHR_DEPTH,
64         FS_CHR_LEVEL,
65         FS_CHR_TYPE,
66         FS_PORT_LAST
67 };
68
69 enum {
70   CMD_APPLY    = 0,
71   CMD_FREE     = 1,
72 };
73
74 typedef struct {
75         /* ports */
76         const LV2_Atom_Sequence* control;
77   LV2_Atom_Sequence*       notify;
78
79         float* p_ports[FS_PORT_LAST];
80         float  v_ports[FS_PORT_LAST];
81
82         /* fluid synth */
83         fluid_settings_t* settings;
84         fluid_synth_t*    synth;
85         int               synthId;
86
87         /* lv2 URIDs */
88         LV2_URID atom_Blank;
89         LV2_URID atom_Object;
90         LV2_URID atom_URID;
91         LV2_URID atom_Path;
92         LV2_URID midi_MidiEvent;
93         LV2_URID patch_Get;
94         LV2_URID patch_Set;
95         LV2_URID patch_property;
96         LV2_URID patch_value;
97         LV2_URID afs_sf2file;
98
99         /* lv2 extensions */
100         LV2_Log_Log*         log;
101         LV2_Log_Logger       logger;
102   LV2_Worker_Schedule* schedule;
103         LV2_Atom_Forge       forge;
104         LV2_Atom_Forge_Frame frame;
105
106         /* state */
107         bool panic;
108         bool initialized;
109         bool inform_ui;
110
111         char current_sf2_file_path[1024];
112         char queue_sf2_file_path[1024];
113         bool reinit_in_progress; // set in run, cleared in work_response
114         bool queue_reinit; // set in restore, cleared in work_response
115
116         fluid_midi_event_t* fmidi_event;
117
118 } AFluidSynth;
119
120 /* *****************************************************************************
121  * helpers
122  */
123
124 static bool
125 load_sf2 (AFluidSynth* self, const char* fn)
126 {
127         const int synth_id = fluid_synth_sfload (self->synth, fn, 1);
128
129         if (synth_id == FLUID_FAILED) {
130                 return false;
131         }
132
133         fluid_sfont_t* const sfont = fluid_synth_get_sfont_by_id (self->synth, synth_id);
134         if (!sfont) {
135                 return false;
136         }
137
138         int chn;
139         fluid_preset_t preset;
140         sfont->iteration_start (sfont);
141         for (chn = 0; sfont->iteration_next (sfont, &preset) && chn < 15; ++chn) {
142                 fluid_synth_program_select (self->synth, chn, synth_id,
143                                 preset.get_banknum (&preset), preset.get_num (&preset));
144         }
145
146         if (chn == 0) {
147                 return false;
148         }
149
150         return true;
151 }
152
153 static const LV2_Atom*
154 parse_patch_msg (AFluidSynth* self, const LV2_Atom_Object* obj)
155 {
156         const LV2_Atom* property = NULL;
157         const LV2_Atom* file_path = NULL;
158
159         if (obj->body.otype != self->patch_Set) {
160                 return NULL;
161         }
162
163         lv2_atom_object_get (obj, self->patch_property, &property, 0);
164         if (!property || property->type != self->atom_URID) {
165                 return NULL;
166         } else if (((const LV2_Atom_URID*)property)->body != self->afs_sf2file) {
167                 return NULL;
168         }
169
170         lv2_atom_object_get (obj, self->patch_value, &file_path, 0);
171         if (!file_path || file_path->type != self->atom_Path) {
172                 return NULL;
173         }
174
175         return file_path;
176 }
177
178 static void
179 inform_ui (AFluidSynth* self)
180 {
181         if (strlen (self->current_sf2_file_path) == 0) {
182                 return;
183         }
184
185         LV2_Atom_Forge_Frame frame;
186         lv2_atom_forge_frame_time (&self->forge, 0);
187         x_forge_object (&self->forge, &frame, 1, self->patch_Set);
188         lv2_atom_forge_property_head (&self->forge, self->patch_property, 0);
189         lv2_atom_forge_urid (&self->forge, self->afs_sf2file);
190         lv2_atom_forge_property_head (&self->forge, self->patch_value, 0);
191         lv2_atom_forge_path (&self->forge, self->current_sf2_file_path, strlen (self->current_sf2_file_path));
192
193         lv2_atom_forge_pop (&self->forge, &frame);
194 }
195
196 static float
197 db_to_coeff (float db)
198 {
199         if (db <= -80) { return 0; }
200         else if (db >=  20) { return 10; }
201         return powf (10.f, .05f * db);
202 }
203
204 /* *****************************************************************************
205  * LV2 Plugin
206  */
207
208 static LV2_Handle
209 instantiate (const LV2_Descriptor*     descriptor,
210              double                    rate,
211              const char*               bundle_path,
212              const LV2_Feature* const* features)
213 {
214         AFluidSynth* self = (AFluidSynth*)calloc (1, sizeof (AFluidSynth));
215
216         if (!self) {
217                 return NULL;
218         }
219
220         LV2_URID_Map* map = NULL;
221
222         for (int i=0; features[i] != NULL; ++i) {
223                 if (!strcmp (features[i]->URI, LV2_URID__map)) {
224                         map = (LV2_URID_Map*)features[i]->data;
225                 } else if (!strcmp (features[i]->URI, LV2_LOG__log)) {
226                         self->log = (LV2_Log_Log*)features[i]->data;
227                 } else if (!strcmp (features[i]->URI, LV2_WORKER__schedule)) {
228                         self->schedule = (LV2_Worker_Schedule*)features[i]->data;
229                 }
230         }
231
232         lv2_log_logger_init (&self->logger, map, self->log);
233
234         if (!map) {
235                 lv2_log_error (&self->logger, "a-fluidsynth.lv2: Host does not support urid:map\n");
236                 free (self);
237                 return NULL;
238         }
239
240         if (!self->schedule) {
241                 lv2_log_error (&self->logger, "a-fluidsynth.lv2: Host does not support worker:schedule\n");
242                 free (self);
243                 return NULL;
244         }
245
246         /* initialize fluid synth */
247         self->settings = new_fluid_settings ();
248
249         if (!self->settings) {
250                 lv2_log_error (&self->logger, "a-fluidsynth.lv2: cannot allocate Fluid Settings\n");
251                 free (self);
252                 return NULL;
253         }
254
255         fluid_settings_setnum (self->settings, "synth.sample-rate", rate);
256         fluid_settings_setint (self->settings, "synth.parallel-render", 1);
257         fluid_settings_setint (self->settings, "synth.threadsafe-api", 0);
258
259         self->synth = new_fluid_synth (self->settings);
260
261         if (!self->synth) {
262                 lv2_log_error (&self->logger, "a-fluidsynth.lv2: cannot allocate Fluid Synth\n");
263     delete_fluid_settings (self->settings);
264                 free (self);
265                 return NULL;
266         }
267
268         fluid_synth_set_gain (self->synth, 1.0f);
269         fluid_synth_set_polyphony (self->synth, 32);
270         fluid_synth_set_sample_rate (self->synth, (float)rate);
271
272         self->fmidi_event = new_fluid_midi_event ();
273
274         if (!self->fmidi_event) {
275                 lv2_log_error (&self->logger, "a-fluidsynth.lv2: cannot allocate Fluid Event\n");
276                 delete_fluid_synth (self->synth);
277     delete_fluid_settings (self->settings);
278                 free (self);
279                 return NULL;
280         }
281
282         /* initialize plugin state */
283
284         self->panic = false;
285         self->inform_ui = false;
286         self->initialized = false;
287         self->reinit_in_progress = false;
288         self->queue_reinit = false;
289
290         lv2_atom_forge_init (&self->forge, map);
291
292         /* map URIDs */
293         self->atom_Blank         = map->map (map->handle, LV2_ATOM__Blank);
294         self->atom_Object        = map->map (map->handle, LV2_ATOM__Object);
295         self->atom_Path          = map->map (map->handle, LV2_ATOM__Path);
296         self->atom_URID          = map->map (map->handle, LV2_ATOM__URID);
297         self->midi_MidiEvent     = map->map (map->handle, LV2_MIDI__MidiEvent);
298         self->patch_Get          = map->map (map->handle, LV2_PATCH__Get);
299         self->patch_Set          = map->map (map->handle, LV2_PATCH__Set);
300         self->patch_property     = map->map (map->handle, LV2_PATCH__property);
301         self->patch_value        = map->map (map->handle, LV2_PATCH__value);
302         self->afs_sf2file        = map->map (map->handle, AFS_URN ":sf2file");
303
304         return (LV2_Handle)self;
305 }
306
307 static void
308 connect_port (LV2_Handle instance,
309               uint32_t   port,
310               void*      data)
311 {
312         AFluidSynth* self = (AFluidSynth*)instance;
313
314         switch (port) {
315                 case FS_PORT_CONTROL:
316                         self->control = (const LV2_Atom_Sequence*)data;
317                         break;
318                 case FS_PORT_NOTIFY:
319                         self->notify = (LV2_Atom_Sequence*)data;
320                         break;
321                 default:
322                         if (port < FS_PORT_LAST) {
323                                 self->p_ports[port] = (float*)data;
324                         }
325                         break;
326         }
327 }
328
329 static void
330 deactivate (LV2_Handle instance)
331 {
332         AFluidSynth* self = (AFluidSynth*)instance;
333         self->panic = true;
334 }
335
336 static void
337 run (LV2_Handle instance, uint32_t n_samples)
338 {
339         AFluidSynth* self = (AFluidSynth*)instance;
340
341         if (!self->control || !self->notify) {
342                 return;
343         }
344
345         const uint32_t capacity = self->notify->atom.size;
346         lv2_atom_forge_set_buffer (&self->forge, (uint8_t*)self->notify, capacity);
347         lv2_atom_forge_sequence_head (&self->forge, &self->frame, 0);
348
349         if (!self->initialized || self->reinit_in_progress) {
350                 memset (self->p_ports[FS_PORT_OUT_L], 0, n_samples * sizeof (float));
351                 memset (self->p_ports[FS_PORT_OUT_R], 0, n_samples * sizeof (float));
352         } else if (self->panic) {
353                 fluid_synth_all_notes_off (self->synth, -1);
354                 fluid_synth_all_sounds_off (self->synth, -1);
355                 self->panic = false;
356         }
357
358         if (self->initialized && !self->reinit_in_progress) {
359                 bool rev_change = false;
360                 bool chr_change = false;
361                 // TODO clamp values to ranges
362                 if (self->v_ports[FS_OUT_GAIN] != *self->p_ports[FS_OUT_GAIN]) {
363                         fluid_synth_set_gain (self->synth, db_to_coeff (*self->p_ports[FS_OUT_GAIN]));
364                 }
365                 if (self->v_ports[FS_REV_ENABLE] != *self->p_ports[FS_REV_ENABLE]) {
366                         fluid_synth_set_reverb_on (self->synth, *self->p_ports[FS_REV_ENABLE] > 0 ? 1 : 0);
367                         rev_change = true;
368                 }
369                 if (self->v_ports[FS_CHR_ENABLE] != *self->p_ports[FS_CHR_ENABLE]) {
370                         fluid_synth_set_chorus_on (self->synth, *self->p_ports[FS_CHR_ENABLE] > 0 ? 1 : 0);
371                         chr_change = true;
372                 }
373
374                 for (uint32_t p = FS_REV_ROOMSIZE; p <= FS_REV_LEVEL && !rev_change; ++p) {
375                         if (self->v_ports[p] != *self->p_ports[p]) {
376                                 rev_change = true;
377                         }
378                 }
379                 for (uint32_t p = FS_CHR_N; p <= FS_CHR_TYPE && !chr_change; ++p) {
380                         if (self->v_ports[p] != *self->p_ports[p]) {
381                                 chr_change = true;
382                         }
383                 }
384
385                 if (rev_change) {
386                         fluid_synth_set_reverb (self->synth,
387                                         *self->p_ports[FS_REV_ROOMSIZE],
388                                         *self->p_ports[FS_REV_DAMPING],
389                                         *self->p_ports[FS_REV_WIDTH],
390                                         *self->p_ports[FS_REV_LEVEL]);
391                 }
392
393                 if (chr_change) {
394                         fluid_synth_set_chorus (self->synth,
395                                         rintf (*self->p_ports[FS_CHR_N]),
396                                         db_to_coeff (*self->p_ports[FS_CHR_LEVEL]),
397                                         *self->p_ports[FS_CHR_SPEED],
398                                         *self->p_ports[FS_CHR_DEPTH],
399                                         (*self->p_ports[FS_CHR_TYPE] > 0) ? FLUID_CHORUS_MOD_SINE : FLUID_CHORUS_MOD_TRIANGLE);
400                 }
401                 for (uint32_t p = FS_OUT_GAIN; p < FS_PORT_LAST; ++p) {
402                         self->v_ports[p] = *self->p_ports[p];
403                 }
404         }
405
406         uint32_t offset = 0;
407
408         LV2_ATOM_SEQUENCE_FOREACH (self->control, ev) {
409                 const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
410                 if (ev->body.type == self->atom_Blank || ev->body.type == self->atom_Object) {
411                         if (obj->body.otype == self->patch_Get) {
412                                 self->inform_ui = false;
413                                 inform_ui (self);
414                         }
415                         else if (obj->body.otype == self->patch_Set) {
416                                 const LV2_Atom* file_path = parse_patch_msg (self, obj);
417                                 if (file_path && !self->reinit_in_progress && !self->queue_reinit) {
418                                         const char *fn = (const char*)(file_path+1);
419                                         strncpy (self->queue_sf2_file_path, fn, 1023);
420                                         self->queue_sf2_file_path[1023] = '\0';
421                                         self->reinit_in_progress = true;
422                                         int magic = 0x4711;
423                                         self->schedule->schedule_work (self->schedule->handle, sizeof (int), &magic);
424                                 }
425                         }
426                 }
427                 else if (ev->body.type == self->midi_MidiEvent && self->initialized && !self->reinit_in_progress) {
428                         if (ev->body.size > 3 || ev->time.frames >= n_samples) {
429                                 continue;
430                         }
431
432                         if (ev->time.frames > offset) {
433                                 fluid_synth_write_float (
434                                                 self->synth,
435                                                 ev->time.frames - offset,
436                                                 &self->p_ports[FS_PORT_OUT_L][offset], 0, 1,
437                                                 &self->p_ports[FS_PORT_OUT_R][offset], 0, 1);
438                         }
439
440                         offset = ev->time.frames;
441
442                         const uint8_t* const data = (const uint8_t*)(ev + 1);
443                         fluid_midi_event_set_type (self->fmidi_event, data[0] & 0xf0);
444                         fluid_midi_event_set_channel (self->fmidi_event, data[0] & 0x0f);
445                         if (ev->body.size > 1) {
446                                 fluid_midi_event_set_key (self->fmidi_event, data[1]);
447                         }
448                         if (ev->body.size > 2) {
449                                 fluid_midi_event_set_value (self->fmidi_event, data[2]);
450                         }
451                         fluid_synth_handle_midi_event (self->synth, self->fmidi_event);
452                 }
453         }
454
455         if (self->queue_reinit && !self->reinit_in_progress) {
456                 self->reinit_in_progress = true;
457                 int magic = 0x4711;
458                 self->schedule->schedule_work (self->schedule->handle, sizeof (int), &magic);
459         }
460
461         /* inform the GUI */
462         if (self->inform_ui) {
463                 self->inform_ui = false;
464                 inform_ui (self);
465         }
466
467         if (n_samples > offset && self->initialized && !self->reinit_in_progress) {
468                 fluid_synth_write_float (
469                                 self->synth,
470                                 n_samples - offset,
471                                 &self->p_ports[FS_PORT_OUT_L][offset], 0, 1,
472                                 &self->p_ports[FS_PORT_OUT_R][offset], 0, 1);
473         }
474 }
475
476 static void cleanup (LV2_Handle instance)
477 {
478         AFluidSynth* self = (AFluidSynth*)instance;
479         delete_fluid_synth (self->synth);
480         delete_fluid_settings (self->settings);
481         delete_fluid_midi_event (self->fmidi_event);
482         free (self);
483 }
484
485 /* *****************************************************************************
486  * LV2 Extensions
487  */
488
489 static LV2_Worker_Status
490 work (LV2_Handle                  instance,
491       LV2_Worker_Respond_Function respond,
492       LV2_Worker_Respond_Handle   handle,
493       uint32_t                    size,
494       const void*                 data)
495 {
496         AFluidSynth* self = (AFluidSynth*)instance;
497
498   if (size != sizeof (int)) {
499                 return LV2_WORKER_ERR_UNKNOWN;
500         }
501         int magic = *((const int*)data);
502         if (magic != 0x4711) {
503                 return LV2_WORKER_ERR_UNKNOWN;
504         }
505
506         self->initialized = load_sf2 (self, self->queue_sf2_file_path);
507
508         if (self->initialized) {
509                 fluid_synth_all_notes_off (self->synth, -1);
510                 fluid_synth_all_sounds_off (self->synth, -1);
511                 self->panic = false;
512         }
513
514         respond (handle, 1, "");
515         return LV2_WORKER_SUCCESS;
516 }
517
518 static LV2_Worker_Status
519 work_response (LV2_Handle  instance,
520                uint32_t    size,
521                const void* data)
522 {
523         AFluidSynth* self = (AFluidSynth*)instance;
524
525         if (self->initialized) {
526                 strcpy (self->current_sf2_file_path, self->queue_sf2_file_path);
527         } else {
528                 self->current_sf2_file_path[0] = 0;
529         }
530
531         self->reinit_in_progress = false;
532         self->inform_ui = true;
533         self->queue_reinit = false;
534         return LV2_WORKER_SUCCESS;
535 }
536
537 static LV2_State_Status
538 save (LV2_Handle                instance,
539       LV2_State_Store_Function  store,
540       LV2_State_Handle          handle,
541       uint32_t                  flags,
542       const LV2_Feature* const* features)
543 {
544         AFluidSynth* self = (AFluidSynth*)instance;
545
546         if (strlen (self->current_sf2_file_path) == 0) {
547                 return LV2_STATE_ERR_NO_PROPERTY;
548         }
549
550         LV2_State_Map_Path* map_path = NULL;
551
552         for (int i = 0; features[i]; ++i) {
553                 if (!strcmp (features[i]->URI, LV2_STATE__mapPath)) {
554                         map_path = (LV2_State_Map_Path*) features[i]->data;
555                 }
556         }
557
558         if (!map_path) {
559                 return LV2_STATE_ERR_NO_FEATURE;
560         }
561
562         char* apath = map_path->abstract_path (map_path->handle, self->current_sf2_file_path);
563         store (handle, self->afs_sf2file,
564                         apath, strlen (apath) + 1,
565                         self->atom_Path,
566                         LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
567
568         return LV2_STATE_SUCCESS;
569 }
570
571 static LV2_State_Status
572 restore (LV2_Handle                  instance,
573          LV2_State_Retrieve_Function retrieve,
574          LV2_State_Handle            handle,
575          uint32_t                    flags,
576          const LV2_Feature* const*   features)
577 {
578         AFluidSynth* self = (AFluidSynth*)instance;
579         if (self->reinit_in_progress || self->queue_reinit) {
580                 lv2_log_warning (&self->logger, "a-fluidsynth.lv2: sf2 load already queued.\n");
581                 return LV2_STATE_ERR_UNKNOWN;
582         }
583
584   size_t   size;
585   uint32_t type;
586   uint32_t valflags;
587
588   const void* value = retrieve (handle, self->afs_sf2file, &size, &type, &valflags);
589         if (value) {
590                 strncpy (self->queue_sf2_file_path, value, 1023);
591                 self->queue_sf2_file_path[1023] = '\0';
592                 self->queue_reinit = true;
593         }
594         return LV2_STATE_SUCCESS;
595 }
596
597 static const void*
598 extension_data (const char* uri)
599 {
600         static const LV2_Worker_Interface worker = { work, work_response, NULL };
601         static const LV2_State_Interface  state  = { save, restore };
602         if (!strcmp (uri, LV2_WORKER__interface)) {
603                 return &worker;
604         }
605         else if (!strcmp (uri, LV2_STATE__interface)) {
606                 return &state;
607         }
608         return NULL;
609 }
610
611 static const LV2_Descriptor descriptor = {
612         AFS_URN,
613         instantiate,
614         connect_port,
615         NULL,
616         run,
617         deactivate,
618         cleanup,
619         extension_data
620 };
621
622 #undef LV2_SYMBOL_EXPORT
623 #ifdef _WIN32
624 #    define LV2_SYMBOL_EXPORT __declspec(dllexport)
625 #else
626 #    define LV2_SYMBOL_EXPORT  __attribute__ ((visibility ("default")))
627 #endif
628 LV2_SYMBOL_EXPORT
629 const LV2_Descriptor*
630 lv2_descriptor (uint32_t index)
631 {
632         switch (index) {
633         case 0:
634                 return &descriptor;
635         default:
636                 return NULL;
637         }
638 }