a-fluidsynth
This commit is contained in:
parent
30afda5536
commit
870cb19737
560
libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c
Normal file
560
libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
67
libs/plugins/a-fluidsynth.lv2/a-fluidsynth.ttl.in
Normal file
67
libs/plugins/a-fluidsynth.lv2/a-fluidsynth.ttl.in
Normal file
@ -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" ;
|
||||
] .
|
7
libs/plugins/a-fluidsynth.lv2/manifest.ttl.in
Normal file
7
libs/plugins/a-fluidsynth.lv2/manifest.ttl.in
Normal file
@ -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> .
|
57
libs/plugins/a-fluidsynth.lv2/wscript
Normal file
57
libs/plugins/a-fluidsynth.lv2/wscript
Normal file
@ -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:
|
Loading…
Reference in New Issue
Block a user