diff options
author | Robin Gareus <robin@gareus.org> | 2016-12-06 15:56:36 +0100 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2016-12-06 17:00:12 +0100 |
commit | 8d8132aa3cc560f5b50dcd67a25636b301ffde89 (patch) | |
tree | 996e684ecf3ff51763cd9e325435b21c187b4023 /libs/plugins | |
parent | 0356d641958869cbfc1b49065ea298463cb1e313 (diff) |
rough-in a-fluid synth midnam support
Diffstat (limited to 'libs/plugins')
-rw-r--r-- | libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c | 148 |
1 files changed, 146 insertions, 2 deletions
diff --git a/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c b/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c index 9a83a029a7..f8bee49f76 100644 --- a/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c +++ b/libs/plugins/a-fluidsynth.lv2/a-fluidsynth.c @@ -33,6 +33,10 @@ #define x_forge_object lv2_atom_forge_blank #endif +#ifdef LV2_EXTENDED +#include "../../ardour/ardour/lv2_extensions.h" +#endif + #include "fluidsynth.h" #include <lv2/lv2plug.in/ns/lv2core/lv2.h> @@ -103,6 +107,10 @@ typedef struct { LV2_Atom_Forge forge; LV2_Atom_Forge_Frame frame; +#ifdef LV2_EXTENDED + LV2_Midnam* midnam; +#endif + /* state */ bool panic; bool initialized; @@ -226,6 +234,10 @@ instantiate (const LV2_Descriptor* descriptor, 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; +#ifdef LV2_EXTENDED + } else if (!strcmp (features[i]->URI, LV2_MIDNAM__update)) { + self->midnam = (LV2_Midnam*)features[i]->data; +#endif } } @@ -468,6 +480,9 @@ run (LV2_Handle instance, uint32_t n_samples) if (self->inform_ui) { self->inform_ui = false; inform_ui (self); +#ifdef LV2_EXTENDED + self->midnam->update (self->midnam->handle); +#endif } if (n_samples > offset && self->initialized && !self->reinit_in_progress) { @@ -603,17 +618,146 @@ restore (LV2_Handle instance, return LV2_STATE_SUCCESS; } +static char* xml_escape (const char* s) { + // crude, but hey + if (!s) { + return strdup (""); + } + char* tmp; + char* rv = strdup (s); + while ((tmp = strchr(rv, '"'))) { + *tmp = '\''; + } + while ((tmp = strchr(rv, '&'))) { + *tmp = '+'; + } + return rv; +} + +#ifdef LV2_EXTENDED +static char* +mn_file (LV2_Handle instance) +{ + AFluidSynth* self = (AFluidSynth*)instance; + char* rv = NULL; + char tmp[1024]; + + fluid_sfont_t* sfont = NULL; + if (self->initialized && !self->reinit_in_progress) { + sfont = fluid_synth_get_sfont (self->synth, 0); + } + // TODO collect program info during load_sf2(); + + rv = calloc (1, sizeof (char)); + +#define pf(...) \ + do { \ + snprintf (tmp, sizeof(tmp), __VA_ARGS__); \ + tmp[sizeof(tmp) - 1] = '\0'; \ + rv = (char*)realloc (rv, strlen (rv) + strlen(tmp) + 1); \ + strcat (rv, tmp); \ + } while (0) + + pf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE MIDINameDocument PUBLIC \"-//MIDI Manufacturers Association//DTD MIDINameDocument 1.0//EN\" \"http://dev.midi.org/dtds/MIDINameDocument10.dtd\">\n" + "<MIDINameDocument>\n" + " <Author/>\n" + " <MasterDeviceNames>\n" + " <Manufacturer>Ardour Foundation</Manufacturer>\n" + " <Model>%s:%p</Model>\n", AFS_URN, (void*) self); + + + pf (" <CustomDeviceMode Name=\"Default\">\n"); + pf (" <ChannelNameSetAssignments>\n"); + for (int c = 0; c < 16; ++c) { + pf (" <ChannelNameSetAssign Channel=\"%d\" NameSet=\"Presets\"/>\n", c + 1); + } + pf (" </ChannelNameSetAssignments>\n"); + pf (" </CustomDeviceMode>\n"); + + // TODO collect used banks, std::set<> would be a nice here + + pf (" <ChannelNameSet Name=\"Presets\">\n"); + pf (" <AvailableForChannels>\n"); + for (int c = 0; c < 16; ++c) { + pf (" <AvailableChannel Channel=\"%d\" Available=\"true\"/>\n", c + 1); + } + pf (" </AvailableForChannels>\n"); + pf (" <UsesControlNameList Name=\"Controls\"/>\n"); + pf (" <PatchBank Name=\"Patch Bank 1\">\n"); + pf (" <UsesPatchNameList Name=\"Programmes\"/>\n"); + pf (" </PatchBank>\n"); + pf (" </ChannelNameSet>\n"); + + + pf (" <PatchNameList Name=\"Programmes\">\n"); + if (sfont) { + fluid_preset_t preset; + sfont->iteration_start (sfont); + for (int num = 1; sfont->iteration_next (sfont, &preset); ++num) { + if (preset.get_banknum (&preset) != 0) { + continue; + } + char* pn = xml_escape (preset.get_name (&preset)); + pf (" <Patch Number=\"%d\" Name=\"%s\" ProgramChange=\"%d\"/>\n", + num, pn, preset.get_num (&preset)); + free (pn); + } + } + pf (" </PatchNameList>\n"); + + pf (" <ControlNameList Name=\"Controls\">\n"); + pf (" <Control Type=\"7bit\" Number=\"7\" Name=\"Channel Volume\"/>\n"); + pf (" <Control Type=\"7bit\" Number=\"10\" Name=\"Pan\"/>\n"); + pf (" <Control Type=\"7bit\" Number=\"39\" Name=\"Channel Volume (Fine)\"/>\n"); + pf (" <Control Type=\"7bit\" Number=\"42\" Name=\"Pan (Fine)\"/>\n"); + pf (" <Control Type=\"7bit\" Number=\"64\" Name=\"Damper Pedal (Sustain)\"/>\n"); + pf (" <Control Type=\"7bit\" Number=\"66\" Name=\"Sostenuto\"/>\n"); + pf (" </ControlNameList>\n"); + + + pf ( + " </MasterDeviceNames>\n" + "</MIDINameDocument>" + ); + + return rv; +} + +static char* +mn_model (LV2_Handle instance) +{ + AFluidSynth* self = (AFluidSynth*)instance; + char* rv = malloc (64 * sizeof (char)); + snprintf (rv, 64, "%s:%p", AFS_URN, (void*) self); + rv[63] = 0; + return rv; +} + +static void +mn_free (char* v) +{ + free (v); +} +#endif + 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)) { + static const LV2_Worker_Interface worker = { work, work_response, NULL }; return &worker; } else if (!strcmp (uri, LV2_STATE__interface)) { + static const LV2_State_Interface state = { save, restore }; return &state; } +#ifdef LV2_EXTENDED + else if (!strcmp (uri, LV2_MIDNAM__interface)) { + static const LV2_Midnam_Interface midnam = { mn_file, mn_model, mn_free }; + return &midnam; + } +#endif return NULL; } |