a-fluidsynth
authorRobin Gareus <robin@gareus.org>
Wed, 24 Aug 2016 01:18:14 +0000 (03:18 +0200)
committerRobin Gareus <robin@gareus.org>
Wed, 24 Aug 2016 01:18:14 +0000 (03:18 +0200)
libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c [new file with mode: 0644]
libs/plugins/a-fluidsynth.lv2/a-fluidsynth.ttl.in [new file with mode: 0644]
libs/plugins/a-fluidsynth.lv2/manifest.ttl.in [new file with mode: 0644]
libs/plugins/a-fluidsynth.lv2/wscript [new file with mode: 0644]
wscript

diff --git a/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c b/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c
new file mode 100644 (file)
index 0000000..c6b743e
--- /dev/null
@@ -0,0 +1,560 @@
+/* a-fluidsynth -- simple & robust x-platform fluidsynth LV2
+ *
+ * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define AFS_URN "urn:ardour:a-fluidsynth"
+
+#ifdef HAVE_LV2_1_10_0
+#define x_forge_object lv2_atom_forge_object
+#else
+#define x_forge_object lv2_atom_forge_blank
+#endif
+
+#include "fluidsynth.h"
+
+#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
+#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
+#include <lv2/lv2plug.in/ns/ext/atom/forge.h>
+#include <lv2/lv2plug.in/ns/ext/atom/util.h>
+#include <lv2/lv2plug.in/ns/ext/log/logger.h>
+#include <lv2/lv2plug.in/ns/ext/midi/midi.h>
+#include <lv2/lv2plug.in/ns/ext/patch/patch.h>
+#include <lv2/lv2plug.in/ns/ext/state/state.h>
+#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
+#include <lv2/lv2plug.in/ns/ext/worker/worker.h>
+
+enum {
+       FS_PORT_CONTROL = 0,
+       FS_PORT_NOTIFY,
+       FS_PORT_OUT_L,
+       FS_PORT_OUT_R
+};
+
+enum {
+  CMD_APPLY    = 0,
+  CMD_FREE     = 1,
+};
+
+typedef struct {
+       /* ports */
+       const LV2_Atom_Sequence* control;
+  LV2_Atom_Sequence*       notify;
+       float*                   output[2];
+
+       /* fluid synth */
+       fluid_settings_t* settings;
+       fluid_synth_t*    synth;
+       int               synthId;
+
+       /* lv2 URIDs */
+       LV2_URID atom_Blank;
+       LV2_URID atom_Object;
+       LV2_URID atom_URID;
+       LV2_URID atom_Path;
+       LV2_URID midi_MidiEvent;
+       LV2_URID patch_Get;
+       LV2_URID patch_Set;
+       LV2_URID patch_property;
+       LV2_URID patch_value;
+       LV2_URID afs_sf2file;
+
+       /* lv2 extensions */
+       LV2_Log_Log*         log;
+       LV2_Log_Logger       logger;
+  LV2_Worker_Schedule* schedule;
+       LV2_Atom_Forge       forge;
+       LV2_Atom_Forge_Frame frame;
+
+       /* state */
+       bool panic;
+       bool initialized;
+       bool inform_ui;
+
+       char current_sf2_file_path[1024];
+       char queue_sf2_file_path[1024];
+       bool reinit_in_progress; // set in run, cleared in work_response
+       bool queue_reinit; // set in restore, cleared in work_response
+
+       fluid_midi_event_t* fmidi_event;
+
+} AFluidSynth;
+
+/* *****************************************************************************
+ * helpers
+ */
+static bool
+load_sf2 (AFluidSynth* self, const char* fn)
+{
+       const int synth_id = fluid_synth_sfload (self->synth, fn, 1);
+
+       if (synth_id == FLUID_FAILED) {
+               return false;
+       }
+
+       fluid_sfont_t* const sfont = fluid_synth_get_sfont_by_id (self->synth, synth_id);
+       if (!sfont) {
+               return false;
+       }
+
+       int chn;
+       fluid_preset_t preset;
+       sfont->iteration_start (sfont);
+       for (chn = 0; sfont->iteration_next (sfont, &preset) && chn < 15; ++chn) {
+               fluid_synth_program_select (self->synth, chn, synth_id,
+                               preset.get_banknum (&preset), preset.get_num (&preset));
+       }
+
+       if (chn == 0) {
+               return false;
+       }
+
+       return true;
+}
+
+static const LV2_Atom*
+parse_patch_msg (AFluidSynth* self, const LV2_Atom_Object* obj)
+{
+       const LV2_Atom* property = NULL;
+       const LV2_Atom* file_path = NULL;
+
+       if (obj->body.otype != self->patch_Set) {
+               return NULL;
+       }
+
+       lv2_atom_object_get (obj, self->patch_property, &property, 0);
+       if (!property || property->type != self->atom_URID) {
+               return NULL;
+       } else if (((const LV2_Atom_URID*)property)->body != self->afs_sf2file) {
+               return NULL;
+       }
+
+       lv2_atom_object_get(obj, self->patch_value, &file_path, 0);
+       if (!file_path || file_path->type != self->atom_Path) {
+               return NULL;
+       }
+
+       return file_path;
+}
+
+
+static void
+inform_ui (AFluidSynth* self)
+{
+       if (strlen (self->current_sf2_file_path) == 0) {
+               return;
+       }
+
+       LV2_Atom_Forge_Frame frame;
+       lv2_atom_forge_frame_time (&self->forge, 0);
+       x_forge_object(&self->forge, &frame, 1, self->patch_Set);
+       lv2_atom_forge_property_head (&self->forge, self->patch_property, 0);
+       lv2_atom_forge_urid (&self->forge, self->afs_sf2file);
+       lv2_atom_forge_property_head (&self->forge, self->patch_value, 0);
+       lv2_atom_forge_path( &self->forge, self->current_sf2_file_path, strlen(self->current_sf2_file_path));
+
+       lv2_atom_forge_pop (&self->forge, &frame);
+}
+
+/* *****************************************************************************
+ * LV2 Plugin
+ */
+
+static LV2_Handle
+instantiate (const LV2_Descriptor*     descriptor,
+             double                    rate,
+             const char*               bundle_path,
+             const LV2_Feature* const* features)
+{
+       AFluidSynth* self = (AFluidSynth*)calloc (1, sizeof (AFluidSynth));
+
+       if (!self) {
+               return NULL;
+       }
+
+       LV2_URID_Map* map = NULL;
+
+       for (int i=0; features[i] != NULL; ++i) {
+               if (!strcmp (features[i]->URI, LV2_URID__map)) {
+                       map = (LV2_URID_Map*)features[i]->data;
+               } else if (!strcmp (features[i]->URI, LV2_LOG__log)) {
+                       self->log = (LV2_Log_Log*)features[i]->data;
+               } else if (!strcmp (features[i]->URI, LV2_WORKER__schedule)) {
+                       self->schedule = (LV2_Worker_Schedule*)features[i]->data;
+               }
+       }
+
+       lv2_log_logger_init (&self->logger, map, self->log);
+
+       if (!map) {
+               lv2_log_error (&self->logger, "a-fluidsynth.lv2: Host does not support urid:map\n");
+               free (self);
+               return NULL;
+       }
+
+       if (!self->schedule) {
+               lv2_log_error (&self->logger, "a-fluidsynth.lv2: Host does not support worker:schedule\n");
+               free (self);
+               return NULL;
+       }
+
+       /* initialize fluid synth */
+       self->settings = new_fluid_settings ();
+
+       if (!self->settings) {
+               lv2_log_error (&self->logger, "a-fluidsynth.lv2: cannot allocate Fluid Settings\n");
+               free (self);
+               return NULL;
+       }
+
+       fluid_settings_setnum (self->settings, "synth.sample-rate", rate);
+       fluid_settings_setint (self->settings, "synth.parallel-render", 1);
+       fluid_settings_setint (self->settings, "synth.threadsafe-api", 0);
+
+       self->synth = new_fluid_synth (self->settings);
+
+       if (!self->synth) {
+               lv2_log_error (&self->logger, "a-fluidsynth.lv2: cannot allocate Fluid Synth\n");
+    delete_fluid_settings (self->settings);
+               free (self);
+               return NULL;
+       }
+
+       fluid_synth_set_gain (self->synth, 1.0f);
+       fluid_synth_set_polyphony (self->synth, 32);
+       fluid_synth_set_sample_rate (self->synth, (float)rate);
+
+       self->fmidi_event = new_fluid_midi_event ();
+
+       if (!self->fmidi_event) {
+               lv2_log_error (&self->logger, "a-fluidsynth.lv2: cannot allocate Fluid Event\n");
+               delete_fluid_synth (self->synth);
+    delete_fluid_settings (self->settings);
+               free (self);
+               return NULL;
+       }
+
+       /* initialize plugin state */
+
+       self->panic = true;
+       self->inform_ui = false;
+       self->initialized = false;
+       self->reinit_in_progress = false;
+       self->queue_reinit = false;
+
+       lv2_atom_forge_init (&self->forge, map);
+
+       /* map URIDs */
+       self->atom_Blank         = map->map (map->handle, LV2_ATOM__Blank);
+       self->atom_Object        = map->map (map->handle, LV2_ATOM__Object);
+       self->atom_Path          = map->map (map->handle, LV2_ATOM__Path);
+       self->atom_URID          = map->map (map->handle, LV2_ATOM__URID);
+       self->midi_MidiEvent     = map->map (map->handle, LV2_MIDI__MidiEvent);
+       self->patch_Get          = map->map (map->handle, LV2_PATCH__Get);
+       self->patch_Set          = map->map (map->handle, LV2_PATCH__Set);
+       self->patch_property     = map->map (map->handle, LV2_PATCH__property);
+       self->patch_value        = map->map (map->handle, LV2_PATCH__value);
+       self->afs_sf2file        = map->map (map->handle, AFS_URN ":sf2file");
+
+       return (LV2_Handle)self;
+}
+
+static void
+connect_port (LV2_Handle instance,
+              uint32_t   port,
+              void*      data)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+
+       switch (port) {
+               case FS_PORT_CONTROL:
+                       self->control = (const LV2_Atom_Sequence*)data;
+                       break;
+               case FS_PORT_NOTIFY:
+                       self->notify = (LV2_Atom_Sequence*)data;
+                       break;
+               case FS_PORT_OUT_L:
+                       self->output[0] = (float*)data;
+                       break;
+               case FS_PORT_OUT_R:
+                       self->output[1] = (float*)data;
+                       break;
+       }
+}
+
+static void
+activate (LV2_Handle instance)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+       self->panic = true;
+}
+
+static void
+run (LV2_Handle instance, uint32_t n_samples)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+
+       if (!self->control || !self->notify) {
+               return;
+       }
+
+       const uint32_t capacity = self->notify->atom.size;
+       lv2_atom_forge_set_buffer (&self->forge, (uint8_t*)self->notify, capacity);
+       lv2_atom_forge_sequence_head (&self->forge, &self->frame, 0);
+
+       if (!self->initialized || self->reinit_in_progress) {
+               memset (self->output[0], 0, n_samples * sizeof (float));
+               memset (self->output[1], 0, n_samples * sizeof (float));
+       } else if (self->panic) {
+               fluid_synth_all_notes_off (self->synth, -1);
+               fluid_synth_all_sounds_off (self->synth, -1);
+               self->panic = false;
+       }
+
+       uint32_t offset = 0;
+
+       LV2_ATOM_SEQUENCE_FOREACH (self->control, ev) {
+               const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
+               if (ev->body.type == self->atom_Blank || ev->body.type == self->atom_Object) {
+                       if (obj->body.otype == self->patch_Get) {
+                               self->inform_ui = false;
+                               inform_ui (self);
+                       }
+                       else if (obj->body.otype == self->patch_Set) {
+                               const LV2_Atom* file_path = parse_patch_msg (self, obj);
+                               if (file_path && !self->reinit_in_progress && !self->queue_reinit) {
+                                       const char *fn = (const char*)(file_path+1);
+                                       strncpy (self->queue_sf2_file_path, fn, 1023);
+                                       self->queue_sf2_file_path[1023] = '\0';
+                                       self->reinit_in_progress = true;
+                                       int magic = 0x4711;
+                                       self->schedule->schedule_work (self->schedule->handle, sizeof(int), &magic);
+                               }
+                       }
+               }
+               else if (ev->body.type == self->midi_MidiEvent && self->initialized && !self->reinit_in_progress) {
+                       if (ev->body.size > 3 || ev->time.frames >= n_samples) {
+                               continue;
+                       }
+
+                       if (ev->time.frames > offset) {
+                               fluid_synth_write_float (
+                                               self->synth,
+                                               ev->time.frames - offset,
+                                               &self->output[0][offset], 0, 1,
+                                               &self->output[1][offset], 0, 1);
+                       }
+
+                       offset = ev->time.frames;
+
+                       const uint8_t* const data = (const uint8_t*)(ev + 1);
+                       fluid_midi_event_set_type (self->fmidi_event, data[0] & 0xf0);
+                       fluid_midi_event_set_channel (self->fmidi_event, data[0] & 0x0f);
+                       if (ev->body.size > 1) {
+                               fluid_midi_event_set_key (self->fmidi_event, data[1]);
+                       }
+                       if (ev->body.size > 2) {
+                               fluid_midi_event_set_value (self->fmidi_event, data[2]);
+                       }
+                       fluid_synth_handle_midi_event (self->synth, self->fmidi_event);
+               }
+       }
+
+       if (self->queue_reinit && !self->reinit_in_progress) {
+               self->reinit_in_progress = true;
+               int magic = 0x4711;
+               self->schedule->schedule_work (self->schedule->handle, sizeof(int), &magic);
+       }
+
+       /* inform the GUI */
+       if (self->inform_ui) {
+               self->inform_ui = false;
+               inform_ui (self);
+       }
+
+       if (n_samples > offset && self->initialized && !self->reinit_in_progress) {
+               fluid_synth_write_float (
+                               self->synth,
+                               n_samples - offset,
+                               &self->output[0][offset], 0, 1,
+                               &self->output[1][offset], 0, 1);
+       }
+}
+
+static void cleanup (LV2_Handle instance)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+       delete_fluid_synth (self->synth);
+       delete_fluid_settings (self->settings);
+       delete_fluid_midi_event (self->fmidi_event);
+       free (self);
+}
+
+/* *****************************************************************************
+ * LV2 Extensions
+ */
+
+static LV2_Worker_Status
+work (LV2_Handle                  instance,
+      LV2_Worker_Respond_Function respond,
+      LV2_Worker_Respond_Handle   handle,
+      uint32_t                    size,
+      const void*                 data)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+
+  if (size != sizeof(int)) {
+               return LV2_WORKER_ERR_UNKNOWN;
+       }
+       int magic = *((const int*)data);
+       if (magic != 0x4711) {
+               return LV2_WORKER_ERR_UNKNOWN;
+       }
+
+       self->initialized = load_sf2 (self, self->queue_sf2_file_path);
+       respond (handle, 1, "");
+       return LV2_WORKER_SUCCESS;
+}
+
+static LV2_Worker_Status
+work_response (LV2_Handle  instance,
+               uint32_t    size,
+               const void* data)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+       self->reinit_in_progress = false;
+       self->queue_reinit = false;
+       self->inform_ui = true;
+       self->panic = true;
+
+       if (self->initialized) {
+               strcpy (self->current_sf2_file_path, self->queue_sf2_file_path);
+       } else {
+               self->current_sf2_file_path[0] = 0;
+       }
+       return LV2_WORKER_SUCCESS;
+}
+
+static LV2_State_Status
+save (LV2_Handle                instance,
+      LV2_State_Store_Function  store,
+      LV2_State_Handle          handle,
+      uint32_t                  flags,
+      const LV2_Feature* const* features)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+
+       if (strlen (self->current_sf2_file_path) == 0) {
+               return LV2_STATE_ERR_NO_PROPERTY;
+       }
+
+       LV2_State_Map_Path* map_path = NULL;
+
+       for (int i = 0; features[i]; ++i) {
+               if (!strcmp (features[i]->URI, LV2_STATE__mapPath)) {
+                       map_path = (LV2_State_Map_Path*) features[i]->data;
+               }
+       }
+
+       if (!map_path) {
+               return LV2_STATE_ERR_NO_FEATURE;
+       }
+
+       char* apath = map_path->abstract_path (map_path->handle, self->current_sf2_file_path);
+       store (handle, self->afs_sf2file,
+                       apath, strlen (apath) + 1,
+                       self->atom_Path,
+                       LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+       return LV2_STATE_SUCCESS;
+}
+
+static LV2_State_Status
+restore (LV2_Handle                  instance,
+         LV2_State_Retrieve_Function retrieve,
+         LV2_State_Handle            handle,
+         uint32_t                    flags,
+         const LV2_Feature* const*   features)
+{
+       AFluidSynth* self = (AFluidSynth*)instance;
+       if (self->reinit_in_progress || self->queue_reinit) {
+               lv2_log_warning (&self->logger, "a-fluidsynth.lv2: sf2 load already queued.\n");
+               return LV2_STATE_ERR_UNKNOWN;
+       }
+
+  size_t   size;
+  uint32_t type;
+  uint32_t valflags;
+
+  const void* value = retrieve (handle, self->afs_sf2file, &size, &type, &valflags);
+       if (value) {
+               strncpy (self->queue_sf2_file_path, value, 1023);
+               self->queue_sf2_file_path[1023] = '\0';
+               self->queue_reinit = true;
+       }
+       return LV2_STATE_SUCCESS;
+}
+
+static const void*
+extension_data (const char* uri)
+{
+       static const LV2_Worker_Interface worker = { work, work_response, NULL };
+       static const LV2_State_Interface  state  = { save, restore };
+       if (!strcmp (uri, LV2_WORKER__interface)) {
+               return &worker;
+       }
+       else if (!strcmp (uri, LV2_STATE__interface)) {
+               return &state;
+       }
+       return NULL;
+}
+
+static const LV2_Descriptor descriptor = {
+       AFS_URN,
+       instantiate,
+       connect_port,
+       activate,
+       run,
+       NULL,
+       cleanup,
+       extension_data
+};
+
+#undef LV2_SYMBOL_EXPORT
+#ifdef _WIN32
+#    define LV2_SYMBOL_EXPORT __declspec(dllexport)
+#else
+#    define LV2_SYMBOL_EXPORT  __attribute__ ((visibility ("default")))
+#endif
+LV2_SYMBOL_EXPORT
+const LV2_Descriptor*
+lv2_descriptor (uint32_t index)
+{
+       switch (index) {
+       case 0:
+               return &descriptor;
+       default:
+               return NULL;
+       }
+}
diff --git a/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.ttl.in b/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.ttl.in
new file mode 100644 (file)
index 0000000..3363d18
--- /dev/null
@@ -0,0 +1,67 @@
+@prefix atom:  <http://lv2plug.in/ns/ext/atom#> .
+@prefix doap:  <http://usefulinc.com/ns/doap#> .
+@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
+@prefix lv2:   <http://lv2plug.in/ns/lv2core#> .
+@prefix midi:  <http://lv2plug.in/ns/ext/midi#> .
+@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
+@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix state: <http://lv2plug.in/ns/ext/state#> .
+@prefix unit:  <http://lv2plug.in/ns/extensions/units#> .
+@prefix urid:  <http://lv2plug.in/ns/ext/urid#> .
+@prefix work:  <http://lv2plug.in/ns/ext/worker#> .
+
+<http://ardour.org/credits.html>
+       a foaf:Person ;
+       foaf:name "Ardour Team" ;
+       foaf:homepage <http://ardour.org/> .
+
+<urn:ardour:a-fluidsynth:sf2file>
+       a lv2:Parameter ;
+       rdfs:label "SF2 File" ;
+       rdfs:range atom:Path .
+
+<urn:ardour:a-fluidsynth>
+       a doap:Project, lv2:InstrumentPlugin, lv2:Plugin ;
+
+       doap:name "a-Fluid Synth" ;
+       rdfs:comment "SF2 Synthesizer using Fluidsynth" ;
+
+       doap:maintainer <http://ardour.org/credits.html> ;
+       doap:license <http://usefulinc.com/doap/licenses/gpl> ;
+
+       lv2:microVersion 2 ; lv2:minorVersion 0 ;
+
+       lv2:requiredFeature urid:map, work:schedule ;
+       lv2:extensionData work:interface, state:interface ;
+       lv2:optionalFeature lv2:hardRTCapable;
+
+       patch:writable <urn:ardour:a-fluidsynth:sf2file> ;
+
+    lv2:port [
+        a lv2:InputPort, atom:AtomPort ;
+        atom:bufferType atom:Sequence ;
+                               atom:supports patch:Message, midi:MidiEvent;
+                               lv2:designation lv2:control ;
+        lv2:index 0 ;
+        lv2:symbol "control" ;
+        lv2:name "Midi In" ;
+    ] , [
+        a lv2:OutputPort, atom:AtomPort ;
+        atom:bufferType atom:Sequence ;
+                               atom:supports patch:Message;
+                               lv2:designation lv2:control ;
+        lv2:index 1 ;
+        lv2:symbol "notify" ;
+        lv2:name "UI Notifications" ;
+    ] , [
+        a lv2:OutputPort, lv2:AudioPort ;
+        lv2:index 2 ;
+        lv2:symbol "outL" ;
+        lv2:name "Out Left" ;
+    ] , [
+        a lv2:OutputPort, lv2:AudioPort ;
+        lv2:index 3 ;
+        lv2:symbol "outR" ;
+        lv2:name "Output Right" ;
+    ] .
diff --git a/libs/plugins/a-fluidsynth.lv2/manifest.ttl.in b/libs/plugins/a-fluidsynth.lv2/manifest.ttl.in
new file mode 100644 (file)
index 0000000..39576ff
--- /dev/null
@@ -0,0 +1,7 @@
+@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<urn:ardour:a-fluidsynth>
+       a lv2:Plugin ;
+       lv2:binary <a-fluidsynth@LIB_EXT@>  ;
+       rdfs:seeAlso <a-fluidsynth.ttl> .
diff --git a/libs/plugins/a-fluidsynth.lv2/wscript b/libs/plugins/a-fluidsynth.lv2/wscript
new file mode 100644 (file)
index 0000000..50f727e
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+import os
+import re
+import shutil
+import waflib.extras.autowaf as autowaf
+import waflib.Options as Options, waflib.Utils as Utils
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+    autowaf.set_options(opt)
+
+def configure(conf):
+    conf.load('compiler_c')
+    autowaf.configure(conf)
+    if Options.options.lv2:
+        autowaf.check_pkg(conf, 'lv2', atleast_version='1.0.0',
+                uselib_store='LV2_1_0_0')
+
+def build(bld):
+    bundle = 'a-fluidsynth.lv2'
+    module_pat = re.sub('^lib', '', bld.env.cshlib_PATTERN)
+    module_ext = module_pat[module_pat.rfind('.'):]
+
+    if bld.is_defined ('HAVE_LV2'):
+        # Build RDF files
+        for i in ['manifest.ttl', 'a-fluidsynth.ttl']:
+            bld(features     = 'subst',
+                source       = i + '.in',
+                target       = '../../LV2/%s/%s' % (bundle, i),
+                install_path = '${LV2DIR}/%s' % bundle,
+                chmod        = Utils.O644,
+                LIB_EXT      = module_ext)
+
+        # Build plugin library
+        obj = bld(features     = 'c cshlib',
+                  source       = 'a-fluidsynth.c',
+                  name         = 'a-fluidsynth',
+                  cflags       = [ '-fPIC',  bld.env['compiler_flags_dict']['c99'] ],
+                  includes     = [ '../../ardour' ],
+                  target       = '../../LV2/%s/a-fluidsynth' % bundle,
+                  install_path = '${LV2DIR}/%s' % bundle,
+                  uselib       = ['LIBFLUIDSYNTH'],
+                  use          = ['LV2_1_0_0']
+                  )
+
+        if bld.is_defined('USE_EXTERNAL_LIBS'):
+            obj.uselib.extend(['LIBFLUIDSYNTH'])
+        else:
+            obj.use.extend(['libfluidsynth_includes', 'libfluidsynth'])
+
+        obj.env.cshlib_PATTERN = module_pat
+        obj.env.cxxshlib_PATTERN = module_pat
+
+# vi:set ts=4 sw=4 et:
diff --git a/wscript b/wscript
index a4ee4ab59062f8c47eef108ef3588db0493341f7..8edd38d1763070afc06fede2ae6db8e6dddc867e 100644 (file)
--- a/wscript
+++ b/wscript
@@ -224,6 +224,7 @@ children = [
         'libs/plugins/a-delay.lv2',
         'libs/plugins/a-eq.lv2',
         'libs/plugins/a-reverb.lv2',
+        'libs/plugins/a-fluidsynth.lv2',
         'gtk2_ardour',
         'export',
         'midi_maps',