commit 8e0c4794c6e3d8f87cdde74dbf9ef7129ff3d5ac
parent e65483585d7aaf225f92965718fbffac315c4dbf
Author: fundamental <[email protected]>
Date: Sun, 14 Mar 2010 06:43:38 -0400
Merge branch 'dssi'
Diffstat:
6 files changed, 684 insertions(+), 232 deletions(-)
diff --git a/AUTHORS.txt b/AUTHORS.txt
@@ -15,4 +15,5 @@ Contributors:
Alexis Ballier (const char* <-> string mismatch, NULLMidi prototype fix)
Tobias Doerffel (static-instance variables fix, missing include fix)
James Morris (Memory leaks in FLTK GUI)
+ Stephen Parry (DSSI rebuild)
diff --git a/src/Makefile b/src/Makefile
@@ -1,9 +1,9 @@
include Makefile.inc
ifneq ($(MAKECMDGOALS),debug)
- CXXFLAGS= -O2 -Wall -g
+ CXXFLAGS= -O2 -Wall -g -fPIC
else
- CXXFLAGS= -O2 -Wall -Wpointer-arith
+ CXXFLAGS= -O2 -Wall -Wpointer-arith -fPIC
endif
CXXFLAGS += -DOS_$(OS_PORT) -D$(MIDIIN)MIDIIN -DFFTW_VERSION_$(FFTW_VERSION) -DASM_F2I_$(ASM_F2I) -ggdb
diff --git a/src/Makefile.inc b/src/Makefile.inc
@@ -68,6 +68,7 @@ ifeq ($(OS_PORT),LINUX)
AUDIOOUT=$(LINUX_AUDIOOUT)
WINDOWS_VST=NO
ifeq ($(LINUX_DSSI),YES)
+ DISABLE_GUI=YES
MIDIIN=DSSI
AUDIOOUT=DSSI
endif
diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp
@@ -20,268 +20,666 @@
*/
+/*
+ * Inital working DSSI output code contributed by Stephen G. Parry
+ */
+
//this file contains code used from trivial_synth.c from
-//the DSSI (published by Steve Harris under public domain) as a template
-//the code is incomplete
+//the DSSI (published by Steve Harris under public domain) as a template.
+
#include <string.h>
#include "DSSIaudiooutput.h"
+#include "../Misc/Config.h"
+#include "../Misc/Bank.h"
+#include <limits.h>
+
+//
+// Static stubs for LADSPA member functions
+//
+// LADSPA is essentially a C handle based API; This plug-in implementation is
+// a C++ OO one so we need stub functions to map from C API calls to C++ object
+// method calls.
+void DSSIaudiooutput::stub_connectPort(LADSPA_Handle instance, unsigned long port, LADSPA_Data * data)
+{
+ getInstance(instance)->connectPort(port, data);
+}
-static LADSPA_Descriptor *tsLDescriptor = NULL;
-static DSSI_Descriptor *tsDDescriptor = NULL;
-
-typedef struct {
- LADSPA_Data *outl;
- LADSPA_Data *outr;
-// note_data data[MIDI_NOTES];
-// float omega[MIDI_NOTES];
-} TS;
+void DSSIaudiooutput::stub_activate(LADSPA_Handle instance)
+{
+ getInstance(instance)->activate();
+}
+void DSSIaudiooutput::stub_run(LADSPA_Handle instance, unsigned long sample_count)
+{
+ getInstance(instance)->run(sample_count);
+}
-static void cleanupTS(LADSPA_Handle instance)
+void DSSIaudiooutput::stub_deactivate(LADSPA_Handle instance)
{
- free(instance);
+ getInstance(instance)->deactivate();
}
-static void connectPortTS(LADSPA_Handle instance, unsigned long port,
- LADSPA_Data *data)
+
+
+void DSSIaudiooutput::stub_cleanup(LADSPA_Handle instance)
{
- TS *plugin;
- plugin = (TS *) instance;
- switch(port) {
- case 0:
- plugin->outl = data;
- break;
- case 1:
- plugin->outr = data;
- break;
- }
+ DSSIaudiooutput* plugin_instance = getInstance(instance);
+ plugin_instance->cleanup();
+ delete plugin_instance;
}
+
const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
{
- switch(index) {
- case 0:
- return tsLDescriptor;
- default:
+ return DSSIaudiooutput::getLadspaDescriptor(index);
+}
+
+//
+// Static stubs for DSSI member functions
+//
+// DSSI is essentially a C handle based API; This plug-in implementation is
+// a C++ OO one so we need stub functions to map from C API calls to C++ object
+// method calls.
+const DSSI_Program_Descriptor* DSSIaudiooutput::stub_getProgram (LADSPA_Handle instance, unsigned long index)
+{
+ return getInstance(instance)->getProgram(index);
+}
+
+void DSSIaudiooutput::stub_selectProgram(LADSPA_Handle instance, unsigned long bank, unsigned long program)
+{
+ getInstance(instance)->selectProgram(bank, program);
+}
+
+int DSSIaudiooutput::stub_getMidiControllerForPort(LADSPA_Handle instance, unsigned long port)
+{
+ return getInstance(instance)->getMidiControllerForPort(port);
+}
+
+void DSSIaudiooutput::stub_runSynth(LADSPA_Handle instance, unsigned long sample_count,
+ snd_seq_event_t *events, unsigned long event_count)
+{
+ getInstance(instance)->runSynth(sample_count, events, event_count);
+}
+
+const DSSI_Descriptor *dssi_descriptor(unsigned long index)
+{
+ return DSSIaudiooutput::getDssiDescriptor(index);
+}
+
+//
+// LADSPA member functions
+//
+
+/**
+ * Instantiates a plug-in.
+ *
+ * This LADSPA member function instantiates a plug-in.
+ * Note that instance initialisation should generally occur in
+ * activate() rather than here.
+ *
+ * Zyn Implementation
+ * ------------------
+ * This implementation creates a C++ class object and hides its pointer
+ * in the handle by type casting.
+ *
+ * @param descriptor [in] the descriptor for this plug-in
+ * @param s_rate [in] the sample rate
+ * @return the plug-in instance handle if successful else NULL
+ */
+LADSPA_Handle DSSIaudiooutput::instantiate(const LADSPA_Descriptor * descriptor, unsigned long s_rate)
+{
+ if(descriptor->UniqueID == dssiDescriptor->LADSPA_Plugin->UniqueID)
+ {
+ return (LADSPA_Handle)(new DSSIaudiooutput(s_rate));
+ }
+ else
+ {
return NULL;
}
}
-const DSSI_Descriptor *dssi_descriptor(unsigned long index)
+/**
+ * Connects a port on an instantiated plug-in.
+ *
+ * This LADSPA member function connects a port on an instantiated plug-in to a
+ * memory location at which a block of data for the port will be read/written.
+ * The data location is expected to be an array of LADSPA_Data for audio ports
+ * or a single LADSPA_Data value for control ports. Memory issues will be
+ * managed by the host. The plug-in must read/write the data at these locations
+ * every time run() or run_adding() is called and the data present at the time
+ * of this connection call should not be considered meaningful.
+ *
+ * Zyn Implementation
+ * ------------------
+ * The buffer pointers are stored as member variables
+ *
+ * @param port [in] the port to be connected
+ * @param data [in] the data buffer to write to / read from
+ */
+void DSSIaudiooutput::connectPort(unsigned long port, LADSPA_Data * data)
{
-// FILE *a=fopen("/tmp/zzzzz11z","w");
-// fprintf(a,"aaaaaaaaaaa TEST\n");
-// fclose(a);
- switch(index) {
+ switch (port) {
case 0:
- return tsDDescriptor;
- default:
- return NULL;
+ outl = data;
+ break;
+ case 1:
+ outr = data;
+ break;
}
}
-static LADSPA_Handle instantiateTS(const LADSPA_Descriptor *descriptor,
- unsigned long s_rate)
+/**
+ * Initialises a plug-in instance and activates it for use.
+ *
+ * This LADSPA member function initialises a plug-in instance and activates it
+ * for use. This is separated from instantiate() to aid real-time support and
+ * so that hosts can reinitialise a plug-in instance by calling deactivate() and
+ * then activate(). In this case the plug-in instance must reset all state
+ * information dependent on the history of the plug-in instance except for any
+ * data locations provided by connect_port() and any gain set by
+ * set_run_adding_gain().
+ *
+ * Zyn Implementation
+ * ------------------
+ * Currently this does nothing; Care must be taken as to code placed here as
+ * too much code here seems to cause time-out problems in jack-dssi-host.
+*/
+void DSSIaudiooutput::activate()
{
- TS *plugin_data = (TS *) malloc(sizeof(TS));
- /* for (i=0; i<MIDI_NOTES; i++) {
- plugin_data->omega[i] = M_PI * 2.0 / (double)s_rate *
- pow(2.0, (i-69.0) / 12.0);
- }
- */
- return (LADSPA_Handle) plugin_data;
}
-static void activateTS(LADSPA_Handle instance)
+/**
+ * Runs an instance of a plug-in for a block.
+ *
+ * This LADSPA member function runs an instance of a plug-in for a block.
+ * Note that if an activate() function exists then it must be called before
+ * run() or run_adding(). If deactivate() is called for a plug-in instance then
+ * the plug-in instance may not be reused until activate() has been called again.
+ *
+ * Zyn Implementation
+ * ------------------
+ * This is a LADSPA function that does not process any MIDI events; it is hence
+ * implemented by simply calling runSynth() with an empty event list.
+ *
+ * @param sample_count [in] the block size (in samples) for which the plug-in instance may run
+ */
+void DSSIaudiooutput::run(unsigned long sample_count)
+{
+ runSynth(sample_count,NULL,(unsigned long)0);
+}
+
+/**
+ * Counterpart to activate().
+ *
+ * This LADSPA member function is the counterpart to activate() (see above).
+ * Deactivation is not similar to pausing as the plug-in instance will be
+ * reinitialised when activate() is called to reuse it.
+ *
+ * Zyn Implementation
+ * ------------------
+ * Currently this function does nothing.
+ */
+void DSSIaudiooutput::deactivate()
{
- TS *plugin_data = (TS *) instance;
-// for (i=0; i<MIDI_NOTES; i++) {
-// plugin_data->data[i].active = 0;
-// }
}
+/**
+ * Deletes a plug-in instance that is no longer required.
+ *
+ * LADSPA member function; once an instance of a plug-in has been finished with
+ * it can be deleted using this function. The instance handle ceases to be
+ * valid after this call.
+ *
+ * If activate() was called for a plug-in instance then a corresponding call to
+ * deactivate() must be made before cleanup() is called.
+ *
+ * Zyn Implementation
+ * ------------------
+ * Currently cleanup is deferred to the destructor that is invoked after cleanup()
+ */
+void DSSIaudiooutput::cleanup()
+{
+}
+
+/**
+ * Initial entry point for the LADSPA plug-in library.
+ *
+ * This LADSPA function is the initial entry point for the plug-in library.
+ * The LADSPA host looks for this entry point in each shared library object it
+ * finds and then calls the function to enumerate the plug-ins within the
+ * library.
+ *
+ * Zyn Implementation
+ * ------------------
+ * As the Zyn plug-in is a DSSI plug-in, the LADSPA descriptor is embedded inside
+ * the DSSI descriptor, which is created by DSSIaudiooutput::initDssiDescriptor()
+ * statically when the library is loaded. This function then merely returns a pointer
+ * to that embedded descriptor.
+ *
+ * @param index [in] the index number of the plug-in within the library.
+ * @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL
+ */
+const LADSPA_Descriptor* DSSIaudiooutput::getLadspaDescriptor(unsigned long index)
+{
+ if(index > 0 || dssiDescriptor == NULL)
+ return NULL;
+ else
+ return dssiDescriptor->LADSPA_Plugin;
+}
-static void runTS(LADSPA_Handle instance, unsigned long sample_count,
- snd_seq_event_t *events, unsigned long event_count)
+//
+// DSSI member functions
+//
+
+/**
+ * Provides a description of a program available on this synth.
+ *
+ * This DSSI member function pointer provides a description of a program (named
+ * preset sound) available on this synth.
+ *
+ * Zyn Implementation
+ * ------------------
+ * The instruments in all Zyn's bank directories, as shown by the `instrument
+ * -> show instrument bank` command, are enumerated to the host by this
+ * function, allowing access to all those instruments.
+ * The first time an instrument is requested, the bank it is in and any
+ * unmapped ones preceding that are mapped; all the instruments names and
+ * filenames from those banks are stored in the programMap member variable for
+ * later use. This is done on demand in this way, rather than up front in one
+ * go because loading all the instrument names in one go can lead to timeouts
+ * and zombies.
+ *
+ * @param index [in] index into the plug-in's list of
+ * programs, not a program number as represented by the Program
+ * field of the DSSI_Program_Descriptor. (This distinction is
+ * needed to support synths that use non-contiguous program or
+ * bank numbers.)
+ * @return a DSSI_Program_Descriptor pointer that is
+ * guaranteed to be valid only until the next call to get_program,
+ * deactivate, or configure, on the same plug-in instance, or NULL if index is out of range.
+ */
+const DSSI_Program_Descriptor* DSSIaudiooutput::getProgram (unsigned long index)
{
- TS *plugin_data = (TS *) instance;
-// LADSPA_Data *const output = plugin_data->output;
-// LADSPA_Data freq = *(plugin_data->freq);
-// LADSPA_Data vol = *(plugin_data->vol);
-// note_data *data = plugin_data->data;
- unsigned long pos;
- unsigned long event_pos;
- unsigned long note;
-
- /* if (freq < 1.0) {
- freq = 440.0f;
- }
- if (vol < 0.000001) {
- vol = 1.0f;
- }
+ static DSSI_Program_Descriptor retVal;
- if (event_count > 0) {
- printf("trivial_synth: have %ld events\n", event_count);
- }
+ /* Make sure we have the list of banks loaded */
+ initBanks();
+
+ /* Make sure that the bank containing the instrument has been mapped */
+ while (index >= programMap.size() && mapNextBank())
+ /* DO NOTHING MORE */;
- for (pos = 0, event_pos = 0; pos < sample_count; pos++) {
+ if(index >= programMap.size())
+ {
+ /* No more instruments */
+ return NULL;
+ }
+ else
+ {
+ /* OK, return the instrument */
+ retVal.Name = programMap[index].name.c_str();
+ retVal.Program = programMap[index].program;
+ retVal.Bank = programMap[index].bank;
+ return &retVal;
+ }
+}
- while (event_pos < event_count
- && pos == events[event_pos].time.tick) {
+/**
+ * Selects a new program for this synth.
+ *
+ * This DSSI member function selects a new program for this synth. The program
+ * change will take effect immediately at the start of the next run_synth()
+ * call. An invalid bank / instrument combination is ignored.
+ *
+ * Zyn Implementation
+ * ------------------
+ * the banks and instruments are as shown in the `instrument -> show instrument
+ * bank` command in Zyn. The bank no is a 1-based index into the list of banks
+ * Zyn loads and shows in the drop down and the program number is the
+ * instrument within that bank.
+ *
+ * @param bank [in] the bank number to select
+ * @param program [in] the program number within the bank to select
+ */
+void DSSIaudiooutput::selectProgram(unsigned long bank, unsigned long program)
+{
+ initBanks();
+// cerr << "selectProgram(" << (bank & 0x7F) << ':' << ((bank >> 7) & 0x7F) << "," << program << ")" << '\n';
+ if(bank < MAX_NUM_BANKS && program < BANK_SIZE)
+ {
+ char* bankdir = master->bank.banks[ bank ].dir;
+ if(bankdir != NULL)
+ {
+ pthread_mutex_lock(&master->mutex);
+
+ /* We have to turn off the CheckPADsynth functionality, else
+ * the program change takes way too long and we get timeouts
+ * and hence zombies (!) */
+ int save = config.cfg.CheckPADsynth;
+ config.cfg.CheckPADsynth = 0;
+
+ /* Load the bank... */
+ master->bank.loadbank(bankdir);
+
+ /* restore the CheckPADsynth flag */
+ config.cfg.CheckPADsynth = save;
+
+ /* Now load the instrument... */
+ master->bank.loadfromslot((unsigned int)program, master->part[0]);
+
+ pthread_mutex_unlock(&master->mutex);
+ }
+ }
+}
- printf("trivial_synth: event type %d\n", events[event_pos].type);
+/**
+ * Returns the MIDI controller number or NRPN for a input control port
+ *
+ * This DSSI member function returns the MIDI controller number or NRPN that
+ * should be mapped to the given input control port. If the given port should
+ * not have any MIDI controller mapped to it, the function will return DSSI_NONE.
+ * The behaviour of this function is undefined if the given port
+ * number does not correspond to an input control port.
+ *
+ * Zyn Implementation
+ * ------------------
+ * Currently Zyn does not define any controller ports, but may do in the future.
+ *
+ * @param port [in] the input controller port
+ * @return the CC and NRPN values shifted and ORed together.
+ */
+int DSSIaudiooutput::getMidiControllerForPort(unsigned long port)
+{
+ return DSSI_NONE;
+}
- if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
- data[events[event_pos].data.note.note].amp =
- events[event_pos].data.note.velocity / 512.0f;
- data[events[event_pos].data.note.note].
- active = events[event_pos].data.note.velocity > 0;
- data[events[event_pos].data.note.note].
- phase = 0.0;
- } else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF) {
- data[events[event_pos].data.note.note].
- active = 0;
- }
- event_pos++;
+/**
+ * Runs the synth for a block.
+ *
+ * This DSSI member function runs the synth for a block. This is identical in
+ * function to the LADSPA run() function, except that it also supplies events
+ * to the synth.
+ *
+ * Zyn Implementation
+ * ------------------
+ * Zyn implements synthesis in Master::GetAudioOutSamples; runSynth calls this
+ * function in chunks delimited by the sample_count and the frame indexes in
+ * the events block, calling the appropriate NoteOn, NoteOff and SetController
+ * members of Master to process the events supplied between each chunk.
+ *
+ * @param sample_count [in] the block size (in samples) for which the synth
+ * instance may run.
+ * @param events [in] The Events pointer points to a block of ALSA
+ * sequencer events, used to communicate MIDI and related events to the synth.
+ * Each event must be timestamped relative to the start of the block,
+ * (mis)using the ALSA "tick time" field as a frame count. The host is
+ * responsible for ensuring that events with differing timestamps are already
+ * ordered by time. Must not include NOTE (only NOTE_ON / NOTE_OFF), LSB or MSB
+ * events.
+ * @param event_count [in] the number of entries in the `events` block
+ */
+void DSSIaudiooutput::runSynth(unsigned long sample_count, snd_seq_event_t *events, unsigned long event_count)
+{
+ unsigned long from_frame = 0;
+ unsigned long event_index = 0;
+ unsigned long next_event_frame = 0;
+ unsigned long to_frame = 0;
+ pthread_mutex_lock(&master->mutex);
+
+ do {
+ /* Find the time of the next event, if any */
+ if(events == NULL || event_index >= event_count)
+ next_event_frame = ULONG_MAX;
+ else
+ next_event_frame = events[event_index].time.tick;
+
+ /* find the end of the sub-sample to be processed this time round... */
+ /* if the next event falls within the desired sample interval... */
+ if(next_event_frame < sample_count && next_event_frame >= to_frame)
+ /* set the end to be at that event */
+ to_frame = next_event_frame;
+ else
+ /* ...else go for the whole remaining sample */
+ to_frame = sample_count;
+ if(from_frame<to_frame)
+ {
+ // call master to fill from `from_frame` to `to_frame`:
+ master->GetAudioOutSamples(to_frame - from_frame, (int)sampleRate, &(outl[from_frame]), &(outr[from_frame]));
+ // next sub-sample please...
+ from_frame = to_frame;
}
- output[pos] = 0.0f;
- for (note = 0; note < MIDI_NOTES; note++) {
- if (data[note].active) {
- output[pos] += sin(data[note].phase) * data[note].amp * vol;
- data[note].phase += plugin_data->omega[note] * freq;
- if (data[note].phase > M_PI * 2.0) {
- data[note].phase -= M_PI * 2.0;
+ // Now process any event(s) at the current timing point
+ while(events != NULL && event_index < event_count && events[event_index].time.tick == to_frame)
+ {
+ if(events[event_index].type == SND_SEQ_EVENT_NOTEON)
+ {
+ master->NoteOn(events[event_index].data.note.channel, events[event_index].data.note.note, events[event_index].data.note.velocity);
}
+ else if(events[event_index].type == SND_SEQ_EVENT_NOTEOFF)
+ {
+ master->NoteOff(events[event_index].data.note.channel, events[event_index].data.note.note);
}
+ else if(events[event_index].type == SND_SEQ_EVENT_CONTROLLER)
+ {
+ master->SetController(events[event_index].data.control.channel, events[event_index].data.control.param, events[event_index].data.control.value);
+ }
+ else
+ {
+ }
+ event_index++;
}
- }
- */
-}
+ // Keep going until we have the desired total length of sample...
+ } while(to_frame < sample_count);
-static void runTSWrapper(LADSPA_Handle instance,
- unsigned long sample_count)
-{
- runTS(instance, sample_count, NULL, 0);
+ pthread_mutex_unlock(&master->mutex);
}
-int getControllerTS(LADSPA_Handle instance, unsigned long port)
+/**
+ * Initial entry point for the DSSI plug-in library.
+ *
+ * This DSSI function is the initial entry point for the plug-in library.
+ * The DSSI host looks for this entry point in each shared library object it
+ * finds and then calls the function to enumerate the plug-ins within the
+ * library.
+ *
+ * Zyn Implementation
+ * ------------------
+ * The descriptor is created statically by DSSIaudiooutput::initDssiDescriptor()
+ * when the plug-in library is loaded. This function merely returns a pointer to
+ * that descriptor.
+ *
+ * @param index [in] the index number of the plug-in within the library.
+ * @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL
+ */
+const DSSI_Descriptor* DSSIaudiooutput::getDssiDescriptor(unsigned long index)
{
- return -1;
+ if(index > 0 || dssiDescriptor == NULL)
+ return NULL;
+ else
+ return dssiDescriptor;
}
-void _init()
+//
+// Internal member functions
+//
+
+// Initialise the DSSI descriptor, statically:
+DSSI_Descriptor* DSSIaudiooutput::dssiDescriptor = DSSIaudiooutput::initDssiDescriptor();
+
+/**
+ * Initializes the DSSI (and LADSPA) descriptor, returning it is an object.
+ */
+DSSI_Descriptor* DSSIaudiooutput::initDssiDescriptor()
{
- char **port_names;
- LADSPA_PortDescriptor *port_descriptors;
- LADSPA_PortRangeHint *port_range_hints;
-
- FILE *a = fopen("/tmp/zzzzzz", "w");
- fprintf(a, "aaaaaaaaaaa TEST\n");
- fclose(a);
-
-
- tsLDescriptor = (LADSPA_Descriptor *) malloc(sizeof(LADSPA_Descriptor));
- if(tsLDescriptor) {
- tsLDescriptor->UniqueID = 100;
- tsLDescriptor->Label = "ZASF";
- tsLDescriptor->Properties = 0;
- tsLDescriptor->Name = "ZynAddSubFX";
- tsLDescriptor->Maker =
- "Nasca Octavian Paul <[email protected]>";
- tsLDescriptor->Copyright = "GNU General Public License v.2";
- tsLDescriptor->PortCount = 2;
-
- port_descriptors = (LADSPA_PortDescriptor *)
- calloc(tsLDescriptor->PortCount, sizeof
- (LADSPA_PortDescriptor));
- tsLDescriptor->PortDescriptors =
- (const LADSPA_PortDescriptor *) port_descriptors;
-
- port_range_hints = (LADSPA_PortRangeHint *)
- calloc(tsLDescriptor->PortCount, sizeof
- (LADSPA_PortRangeHint));
- tsLDescriptor->PortRangeHints =
- (const LADSPA_PortRangeHint *) port_range_hints;
-
- port_names = (char **) calloc(tsLDescriptor->PortCount, sizeof(char *));
- tsLDescriptor->PortNames = (const char **) port_names;
-
- port_descriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
- port_names[0] = "Output L";
- port_range_hints[0].HintDescriptor = 0;
- port_descriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
- port_names[1] = "Output R";
- port_range_hints[1].HintDescriptor = 0;
-
- tsLDescriptor->activate = activateTS;
- tsLDescriptor->cleanup = cleanupTS;
- tsLDescriptor->connect_port = connectPortTS;
- tsLDescriptor->deactivate = NULL;
- tsLDescriptor->instantiate = instantiateTS;
- tsLDescriptor->run = runTSWrapper;
- tsLDescriptor->run_adding = NULL;
- tsLDescriptor->set_run_adding_gain = NULL;
+ DSSI_Descriptor* newDssiDescriptor = new DSSI_Descriptor;
+
+ LADSPA_PortDescriptor* newPortDescriptors;
+ char** newPortNames;
+ LADSPA_PortRangeHint* newPortRangeHints;
+
+ if (newDssiDescriptor)
+ {
+ LADSPA_Descriptor* newLadspaDescriptor = new LADSPA_Descriptor;
+ if (newLadspaDescriptor)
+ {
+ newLadspaDescriptor->UniqueID = 100;
+ newLadspaDescriptor->Label = "ZASF";
+ newLadspaDescriptor->Properties = 0;
+ newLadspaDescriptor->Name = "ZynAddSubFX";
+ newLadspaDescriptor->Maker = "Nasca Octavian Paul <[email protected]>";
+ newLadspaDescriptor->Copyright = "GNU General Public License v.2";
+ newLadspaDescriptor->PortCount = 2;
+
+ newPortNames = new char *[newLadspaDescriptor->PortCount];
+ newPortNames[0] = "Output L";
+ newPortNames[1] = "Output R";
+ newLadspaDescriptor->PortNames = newPortNames;
+
+ newPortDescriptors = new LADSPA_PortDescriptor[newLadspaDescriptor->PortCount];
+ newPortDescriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
+ newPortDescriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
+ newLadspaDescriptor->PortDescriptors = newPortDescriptors;
+
+ newPortRangeHints = new LADSPA_PortRangeHint[newLadspaDescriptor->PortCount];
+ newPortRangeHints[0].HintDescriptor = 0;
+ newPortRangeHints[1].HintDescriptor = 0;
+ newLadspaDescriptor->PortRangeHints = newPortRangeHints;
+
+ newLadspaDescriptor->activate = stub_activate;
+ newLadspaDescriptor->cleanup = stub_cleanup;
+ newLadspaDescriptor->connect_port = stub_connectPort;
+ newLadspaDescriptor->deactivate = stub_deactivate;
+ newLadspaDescriptor->instantiate = instantiate;
+ newLadspaDescriptor->run = stub_run;
+ newLadspaDescriptor->run_adding = NULL;
+ newLadspaDescriptor->set_run_adding_gain = NULL;
+ }
+ newDssiDescriptor->LADSPA_Plugin = newLadspaDescriptor;
+ newDssiDescriptor->DSSI_API_Version = 1;
+ newDssiDescriptor->configure = NULL;
+ newDssiDescriptor->get_program = stub_getProgram;
+ newDssiDescriptor->get_midi_controller_for_port = stub_getMidiControllerForPort;
+ newDssiDescriptor->select_program = stub_selectProgram;
+ newDssiDescriptor->run_synth = stub_runSynth;
+ newDssiDescriptor->run_synth_adding = NULL;
+ newDssiDescriptor->run_multiple_synths = NULL;
+ newDssiDescriptor->run_multiple_synths_adding = NULL;
}
- tsDDescriptor = (DSSI_Descriptor *) malloc(sizeof(DSSI_Descriptor));
- if(tsDDescriptor) {
- tsDDescriptor->DSSI_API_Version = 1;
- tsDDescriptor->LADSPA_Plugin = tsLDescriptor;
- tsDDescriptor->configure = NULL;
- tsDDescriptor->get_program = NULL;
- tsDDescriptor->get_midi_controller_for_port = getControllerTS;
- tsDDescriptor->select_program = NULL;
- tsDDescriptor->run_synth = runTS;
- tsDDescriptor->run_synth_adding = NULL;
- tsDDescriptor->run_multiple_synths = NULL;
- tsDDescriptor->run_multiple_synths_adding = NULL;
- }
-}
+ dssiDescriptor = newDssiDescriptor;
-void _fini()
-{}
+ return dssiDescriptor;
+}
+/**
+ * Converts a LADSPA / DSSI handle into a DSSIaudiooutput instance.
+ *
+ * @param instance [in]
+ * @return the instance
+ */
+DSSIaudiooutput* DSSIaudiooutput::getInstance(LADSPA_Handle instance)
+{
+ return (DSSIaudiooutput*)(instance);
+}
+/**
+ * The private sole constructor for the DSSIaudiooutput class.
+ *
+ * Only ever called via instantiate().
+ * @param sampleRate [in] the sample rate to be used by the synth.
+ * @return
+ */
+DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate)
+{
+ this->sampleRate = sampleRate;
+ this->banksInited = false;
+ config.init();
+ srand(time(NULL));
+ denormalkillbuf=new REALTYPE [SOUND_BUFFER_SIZE];
+ for (int i=0;i<SOUND_BUFFER_SIZE;i++) denormalkillbuf[i]=(RND-0.5)*1e-16;
+ this->master = new Master();
+}
+/**
+ * The destructor for the DSSIaudiooutput class
+ * @return
+ */
+DSSIaudiooutput::~DSSIaudiooutput()
+{
+}
-//the constructor and the destructor are defined in main.C
-/*
-void VSTSynth::process (float **inputs, float **outputs, long sampleframes){
- float *outl=outputs[0];
- float *outr=outputs[1];
- pthread_mutex_lock(&vmaster->mutex);
- vmaster->GetAudioOutSamples(sampleframes,(int) getSampleRate(),outl,outr);
- pthread_mutex_unlock(&vmaster->mutex);
-};
-
-void VSTSynth::processReplacing (float **inputs, float **outputs, long sampleframes){
- process(inputs,outputs,sampleframes);
-};
-
-long int VSTSynth::canDo(char *txt){
- if (strcmp(txt,"receiveVstEvents")==0) return (1);
- if (strcmp(txt,"receiveVstMidiEvent")==0) return (1);
- return(-1);
-};
-
-bool VSTSynth::getVendorString(char *txt){
- strcpy(txt,"Nasca O. Paul");
- return(true);
-};
-
-bool VSTSynth::getProductString(char *txt){
- strcpy(txt,"ZynAddSubFX");
- return(true);
-};
-
-void VSTSynth::resume(){
- wantEvents();
-};
+/**
+ * Ensures the list of bank (directories) has been initialised.
+ */
+void DSSIaudiooutput::initBanks(void)
+{
+ if(!banksInited)
+ {
+ pthread_mutex_lock(&master->mutex);
+ master->bank.rescanforbanks();
+ banksInited = true;
+ pthread_mutex_unlock(&master->mutex);
+ }
+}
-*/
+/**
+ * constructor for the internally used ProgramDescriptor class
+ *
+ * @param _bank [in] bank number
+ * @param _program [in] program number
+ * @param _name [in] instrument / sample name
+ * @return
+ */
+DSSIaudiooutput::ProgramDescriptor::ProgramDescriptor(unsigned long _bank, unsigned long _program, char* _name) :
+ bank(_bank), program(_program), name(_name)
+{
+}
+/**
+ * The map of programs available; held as a single shared statically allocated object.
+ */
+vector <DSSIaudiooutput::ProgramDescriptor> DSSIaudiooutput::programMap = vector<DSSIaudiooutput::ProgramDescriptor>();
+
+/**
+ * Index controlling the map of banks
+ */
+long DSSIaudiooutput::bankNoToMap = 1;
+
+/**
+ * Queries and maps the next available bank of instruments.
+ *
+ * If the program index requested to getProgram() lies beyond the banks mapped to date,
+ * this member function is called to map the next one.
+ * @return true if a new bank has been found and mapped, else false.
+ */
+bool DSSIaudiooutput::mapNextBank()
+{
+ pthread_mutex_lock(&master->mutex);
+ Bank& bank = master->bank;
+ bool retval;
+ if(bankNoToMap >= MAX_NUM_BANKS || bank.banks[bankNoToMap].dir == NULL)
+ {
+ retval = false;
+ }
+ else
+ {
+ bank.loadbank(bank.banks[bankNoToMap].dir);
+ for(unsigned long instrument = 0; instrument < BANK_SIZE; instrument++)
+ {
+ char* insName = bank.getname(instrument);
+ if(insName != NULL && insName[0] != '\0' && insName[0] != ' ')
+ {
+ programMap.push_back(ProgramDescriptor(bankNoToMap,instrument,insName));
+ }
+ }
+ bankNoToMap ++;
+ retval = true;
+ }
+ pthread_mutex_unlock(&master->mutex);
+ return retval;
+}
diff --git a/src/Output/DSSIaudiooutput.h b/src/Output/DSSIaudiooutput.h
@@ -26,34 +26,86 @@
#include "../globals.h"
#include "../Misc/Master.h"
-#include "../UI/MasterUI.h"
#include <dssi.h>
#include <ladspa.h>
+#include <vector>
-/*
-class VSTSynth:public AudioEffectX{
- public:
- VSTSynth (audioMasterCallback audioMaster);
- ~VSTSynth();
-
- virtual void process (float **inputs, float **outputs, long sampleframes);
- virtual void processReplacing (float **inputs, float **outputs, long sampleframes);
- virtual long processEvents(VstEvents *events);//this is used for Midi input
- virtual long int canDo(char *txt);
- virtual bool getVendorString(char *txt);
- virtual bool getProductString(char *txt);
- virtual void resume();
-
- virtual long getChunk(void** data,bool isPreset=false);
- virtual void setChunk(void *data,long size,bool isPreset=false);
-
- MasterUI *ui;
- int Pexitprogram;
-
- Master *vmaster;
- pthread_t thr;
+class DSSIaudiooutput
+{
+public:
+ //
+ // Static stubs for LADSPA member functions
+ //
+ static void stub_connectPort(LADSPA_Handle instance, unsigned long port, LADSPA_Data * data);
+ static void stub_activate(LADSPA_Handle instance);
+ static void stub_run(LADSPA_Handle instance, unsigned long sample_count);
+ static void stub_deactivate(LADSPA_Handle Instance);
+ static void stub_cleanup(LADSPA_Handle instance);
+
+ //
+ // Static stubs for DSSI member functions
+ //
+ static const DSSI_Program_Descriptor* stub_getProgram (LADSPA_Handle instance, unsigned long Index);
+ static void stub_selectProgram(LADSPA_Handle instance, unsigned long bank, unsigned long program);
+ static int stub_getMidiControllerForPort(LADSPA_Handle instance, unsigned long port);
+ static void stub_runSynth(LADSPA_Handle instance, unsigned long sample_count,
+ snd_seq_event_t *events, unsigned long event_count);
+
+ /*
+ * LADSPA member functions
+ */
+ static LADSPA_Handle instantiate(const LADSPA_Descriptor * descriptor, unsigned long s_rate);
+ void connectPort(unsigned long port, LADSPA_Data * data);
+ void activate();
+ void run(unsigned long sample_count);
+ void deactivate();
+ void cleanup();
+ static const LADSPA_Descriptor* getLadspaDescriptor(unsigned long index);
+
+ /*
+ * DSSI member functions
+ */
+ const DSSI_Program_Descriptor* getProgram (unsigned long Index);
+ void selectProgram(unsigned long bank, unsigned long program);
+ int getMidiControllerForPort(unsigned long port);
+ void runSynth(unsigned long sample_count, snd_seq_event_t *events, unsigned long event_count);
+ static const DSSI_Descriptor* getDssiDescriptor(unsigned long index);
+
+ struct ProgramDescriptor
+ {
+ unsigned long bank;
+ unsigned long program;
+ string name;
+ ProgramDescriptor(unsigned long _bank, unsigned long _program, char* _name);
+ };
+
+private:
+
+ DSSIaudiooutput(unsigned long sampleRate);
+ ~DSSIaudiooutput();
+ static DSSI_Descriptor* initDssiDescriptor();
+ static DSSIaudiooutput* getInstance(LADSPA_Handle instance);
+ void initBanks();
+ bool mapNextBank();
+
+ LADSPA_Data *outl;
+ LADSPA_Data *outr;
+ long sampleRate;
+ Master* master;
+ static DSSI_Descriptor* dssiDescriptor;
+ static string bankDirNames[];
+ static
+ vector <ProgramDescriptor> programMap;
+
+ /**
+ * Flag controlling the list of bank directories
+ */
+ bool banksInited;
+
+ static
+ long bankNoToMap;
};
-*/
+
#endif
diff --git a/src/main.cpp b/src/main.cpp
@@ -28,7 +28,7 @@
#ifdef OS_LINUX
#include <getopt.h>
-#elif OS_WINDOIWS
+#elif OS_WINDOWS
#include <winbase.h>
#include <windows.h>
#endif
@@ -46,7 +46,7 @@ extern Dump dump;
#include "Input/OSSMidiIn.h"
#endif
-#if (defined(NONEMIDIIN) || defined(VSTMIDIIN))
+#if (defined(NONEMIDIIN) || defined(VSTMIDIIN) || defined(DSSIMIDIIN))
#include "Input/NULLMidiIn.h"
#endif