rough-in a-fluid synth midnam support
This commit is contained in:
parent
0356d64195
commit
8d8132aa3c
@ -33,6 +33,10 @@
|
|||||||
#define x_forge_object lv2_atom_forge_blank
|
#define x_forge_object lv2_atom_forge_blank
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LV2_EXTENDED
|
||||||
|
#include "../../ardour/ardour/lv2_extensions.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "fluidsynth.h"
|
#include "fluidsynth.h"
|
||||||
|
|
||||||
#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
|
#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
|
||||||
@ -103,6 +107,10 @@ typedef struct {
|
|||||||
LV2_Atom_Forge forge;
|
LV2_Atom_Forge forge;
|
||||||
LV2_Atom_Forge_Frame frame;
|
LV2_Atom_Forge_Frame frame;
|
||||||
|
|
||||||
|
#ifdef LV2_EXTENDED
|
||||||
|
LV2_Midnam* midnam;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
bool panic;
|
bool panic;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
@ -226,6 +234,10 @@ instantiate (const LV2_Descriptor* descriptor,
|
|||||||
self->log = (LV2_Log_Log*)features[i]->data;
|
self->log = (LV2_Log_Log*)features[i]->data;
|
||||||
} else if (!strcmp (features[i]->URI, LV2_WORKER__schedule)) {
|
} else if (!strcmp (features[i]->URI, LV2_WORKER__schedule)) {
|
||||||
self->schedule = (LV2_Worker_Schedule*)features[i]->data;
|
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) {
|
if (self->inform_ui) {
|
||||||
self->inform_ui = false;
|
self->inform_ui = false;
|
||||||
inform_ui (self);
|
inform_ui (self);
|
||||||
|
#ifdef LV2_EXTENDED
|
||||||
|
self->midnam->update (self->midnam->handle);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_samples > offset && self->initialized && !self->reinit_in_progress) {
|
if (n_samples > offset && self->initialized && !self->reinit_in_progress) {
|
||||||
@ -603,17 +618,146 @@ restore (LV2_Handle instance,
|
|||||||
return LV2_STATE_SUCCESS;
|
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*
|
static const void*
|
||||||
extension_data (const char* uri)
|
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)) {
|
if (!strcmp (uri, LV2_WORKER__interface)) {
|
||||||
|
static const LV2_Worker_Interface worker = { work, work_response, NULL };
|
||||||
return &worker;
|
return &worker;
|
||||||
}
|
}
|
||||||
else if (!strcmp (uri, LV2_STATE__interface)) {
|
else if (!strcmp (uri, LV2_STATE__interface)) {
|
||||||
|
static const LV2_State_Interface state = { save, restore };
|
||||||
return &state;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user