summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/ChangeLog15
-rw-r--r--muse/configure.ac82
-rw-r--r--muse/muse/Makefile.am2
-rw-r--r--muse/muse/app.cpp39
-rw-r--r--muse/muse/arranger/tlist.cpp26
-rw-r--r--muse/muse/audiotrack.cpp112
-rw-r--r--muse/muse/dssihost.cpp1096
-rw-r--r--muse/muse/dssihost.h112
-rw-r--r--muse/muse/mixer/rack.cpp19
-rw-r--r--muse/muse/plugin.cpp1442
-rw-r--r--muse/muse/plugin.h166
-rw-r--r--muse/muse/song.cpp10
-rw-r--r--muse/muse/songfile.cpp9
-rw-r--r--muse/muse/synth.cpp96
-rw-r--r--muse/muse/synth.h59
-rw-r--r--muse/muse/ticksynth.cpp6
-rw-r--r--muse/muse/track.h1
-rw-r--r--muse/muse/vst.cpp11
-rw-r--r--muse/muse/vst.h6
19 files changed, 2495 insertions, 814 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index c7f8a2bb..5a0c5b0c 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,18 @@
+27.04.2010
+ * Changed: Building: Separate --enable-dssi --enable-osc configure options. (T356)
+ --enable-dssi (Enable dssi synths AND special handling of dssi-vst ladspa effect plugins. No guis if by itself.) and
+ --enable-osc (Enable dssi guis. Useless by itself at the moment).
+ Use both for best features.
+ * Feature: If dssi and osc support are enabled, audio track effects rack dssi-vst plugins can now show their NATIVE guis. (T356)
+ * Fixed: Storing dssi synth states. Remembers current program, all configure strings, and control settings - for current program ONLY. (T356)
+ - With dssi-vst synths, some better are than others at remembering program.
+ - Todo: Ignore unwanted dssi-vst config strings/values like "guiVisible" "<name-of-fifo-file>" (gives non-fatal error on reload).
+ * Fixed: Dssi native synths (hexter, LTS etc.) should actually work now. Their gui controls operate the sounds now. (T356)
+ - Todo: If using large audio buffers (Jack), my 'one-at-a-time-per-audio-process' osc control fifo streams kinda suck,
+ with a delay in their processing. Want to try MULTIPLE 'run's or 'run-multiple's PER audio process, for SAMPLE accuracy and
+ better quicker message processing. Just need to add a timestamp to my osc fifo items, then all forms of change - whether
+ control, midi event, or program - have a timestamp with which we can SPLIT UP the runs into 'runs between changes'.
+ * Tip: Currently a patch to dssi-vst is required for their guis to update properly. (For now, ask about this on our lists.)
21.04.2010
* Fixed: Shortcut for moving between tracks in arranger. Ctrl+Up/Down (rj)
19.04.2010
diff --git a/muse/configure.ac b/muse/configure.ac
index 9decee23..e79419f2 100644
--- a/muse/configure.ac
+++ b/muse/configure.ac
@@ -586,14 +586,63 @@ AM_CONDITIONAL(VST_SUPPORT, test x$vst_possible = xyes -a x$vst_requested = xyes
###################
+### OSC support ###
+###################
+
+osc_requested=no
+LO_LIB_FOUND="no"
+OSC="no"
+AC_ARG_ENABLE(osc,[ --enable-osc build OSC support. (disabled by default)
+ --enable-dssi is also recommended! ],
+ [ if test x$enable_osc = xyes ; then
+ osc_requested=yes;
+ fi
+ ]
+)
+
+if test x$osc_requested = xyes ; then
+ AC_MSG_CHECKING([support for OSC])
+## AC_CHECK_LIB(lo, lo_send, LO_LIB_FOUND="yes", LO_LIB_FOUND="no")
+## PKG_CHECK_MODULES(LO, lo >= 0.2, LO_LIB_FOUND="yes", LO_LIB_FOUND="no")
+ PKG_CHECK_MODULES(LO,liblo, [ LO_LIB_FOUND=yes ], [ LO_LIB_FOUND=no ])
+ if test x$LO_LIB_FOUND = xno; then
+ AC_MSG_ERROR([Library liblo from The Lightweight OSC Implementation is required])
+ fi
+fi
+
+if test x$LO_LIB_FOUND = xyes ; then
+ LO_CFLAGS="$LO_CFLAGS"
+ ##LO_LIBS="$LO_LIBS"
+ LO_LIBS="-llo"
+ OSC="yes"
+ AC_SUBST(LO_CFLAGS)
+ AC_SUBST(LO_LIBS)
+ AC_DEFINE(OSC_SUPPORT, 1, [support for OSC])
+fi
+
+AM_CONDITIONAL(OSC_SUPPORT, test x$LO_LIB_FOUND = xyes)
+
+## LO_LIBS="-llo"
+## AC_SUBST(LO_CFLAGS)
+## AC_SUBST(LO_LIBS)
+
+## PKG_CHECK_MODULES(LO, lo >= 0.23,
+## true,
+## AC_MSG_ERROR([need liblo >= 0.23 ])
+## )
+
+
+
+###################
### dssi plugins ###
###################
dssi_requested=no
-LO_LIB_FOUND="no"
+## LO_LIB_FOUND="no"
DSSI_H_FOUND="no"
DSSI="no"
-AC_ARG_ENABLE(dssi,[ --enable-dssi build DSSI + DSSI-Vst support. (disabled by default) ],
+AC_ARG_ENABLE(dssi,[ --enable-dssi build DSSI + DSSI-Vst support. (disabled by default)
+ --enable-osc is also recommended! ],
[ if test x$enable_dssi = xyes ; then
dssi_requested=yes;
fi
@@ -603,31 +652,33 @@ AC_ARG_ENABLE(dssi,[ --enable-dssi build DSSI + DSSI-Vst support. (di
if test x$dssi_requested = xyes ; then
AC_MSG_CHECKING([support for DSSI + DSSI-Vst plugins])
-## AC_CHECK_LIB(lo, lo_send, LO_LIB_FOUND="yes", LO_LIB_FOUND="no")
-## PKG_CHECK_MODULES(LO, lo >= 0.2, LO_LIB_FOUND="yes", LO_LIB_FOUND="no")
- PKG_CHECK_MODULES(LO,liblo, [ LO_LIB_FOUND=yes ], [ LO_LIB_FOUND=no ])
- if test x$LO_LIB_FOUND = xno; then
- AC_MSG_ERROR([Library liblo from The Lightweight OSC Implementation is required])
- fi
+ ## AC_CHECK_LIB(lo, lo_send, LO_LIB_FOUND="yes", LO_LIB_FOUND="no")
+ ## PKG_CHECK_MODULES(LO, lo >= 0.2, LO_LIB_FOUND="yes", LO_LIB_FOUND="no")
+## PKG_CHECK_MODULES(LO,liblo, [ LO_LIB_FOUND=yes ], [ LO_LIB_FOUND=no ])
+## if test x$LO_LIB_FOUND = xno; then
+## AC_MSG_ERROR([Library liblo from The Lightweight OSC Implementation is required])
+## fi
AC_CHECK_HEADER(dssi.h, DSSI_FOUND="yes", DSSI_FOUND="no")
-## PKG_CHECK_MODULES(DSSI [ DSSI_FOUND=yes ], [ DSSI_FOUND=no ])
+ ## PKG_CHECK_MODULES(DSSI [ DSSI_FOUND=yes ], [ DSSI_FOUND=no ])
if test x$DSSI_FOUND = xno; then
AC_MSG_ERROR([Header file dssi.h from DSSI (Disposable Soft Synth Interface) is required])
fi
fi
-if test x$LO_LIB_FOUND = xyes -a x$DSSI_FOUND = xyes ; then
- LO_CFLAGS="$LO_CFLAGS"
+## if test x$LO_LIB_FOUND = xyes -a x$DSSI_FOUND = xyes ; then
+if test x$DSSI_FOUND = xyes ; then
+## LO_CFLAGS="$LO_CFLAGS"
##LO_LIBS="$LO_LIBS"
- LO_LIBS="-llo"
+## LO_LIBS="-llo"
DSSI="yes"
- AC_SUBST(LO_CFLAGS)
- AC_SUBST(LO_LIBS)
+## AC_SUBST(LO_CFLAGS)
+## AC_SUBST(LO_LIBS)
AC_DEFINE(DSSI_SUPPORT, 1, [support for DSSI + DSSI-Vst plugins])
fi
-AM_CONDITIONAL(DSSI_SUPPORT, test x$LO_LIB_FOUND = xyes -a x$DSSI_FOUND = xyes)
+## AM_CONDITIONAL(DSSI_SUPPORT, test x$LO_LIB_FOUND = xyes -a x$DSSI_FOUND = xyes)
+AM_CONDITIONAL(DSSI_SUPPORT, test x$DSSI_FOUND = xyes)
## LO_LIBS="-llo"
## AC_SUBST(LO_CFLAGS)
@@ -720,6 +771,7 @@ AC_MSG_NOTICE([
MusE configured
LASH support: $LASH_FOUND
+ OSC support: $OSC
DSSI support: $DSSI
FluidSynth: $muse_enable_fluidlib
diff --git a/muse/muse/Makefile.am b/muse/muse/Makefile.am
index df5a552f..bbf6ae44 100644
--- a/muse/muse/Makefile.am
+++ b/muse/muse/Makefile.am
@@ -33,6 +33,8 @@ dist_muse_SOURCES = \
ticksynth.h ticksynth.cpp \
vst.h vst.cpp \
dssihost.h dssihost.cpp \
+ osc.cpp osc.h \
+ stringparam.cpp stringparam.h \
synth.h synth.cpp \
plugin.cpp plugin.h \
mtc.cpp mtc.h \
diff --git a/muse/muse/app.cpp b/muse/muse/app.cpp
index dac144c4..c896ff51 100644
--- a/muse/muse/app.cpp
+++ b/muse/muse/app.cpp
@@ -131,6 +131,9 @@ extern void exitDummyAudio();
extern void initVST_fst_init();
extern void initVST();
extern void initDSSI();
+// p3.3.39
+extern void initOSC();
+extern void exitOSC();
#ifdef HAVE_LASH
#include <lash/lash.h>
@@ -402,12 +405,25 @@ bool MusE::seqStart()
//audioWriteback->start(0);
}
*/
+
int pfprio = 0;
int midiprio = 0;
+
+ // NOTE: realTimeScheduling can be true (gotten using jack_is_realtime()),
+ // while the determined realTimePriority can be 0.
+ // realTimePriority is gotten using pthread_getschedparam() on the client thread
+ // in JackAudioDevice::realtimePriority() which is a bit flawed - it reports there's no RT...
if(realTimeScheduling)
{
- if(realTimePriority < 5)
- printf("MusE: WARNING: Recommend setting audio realtime priority to at least 5!\n");
+ //if(realTimePriority < 5)
+ // printf("MusE: WARNING: Recommend setting audio realtime priority to a higher value!\n");
+ /*
+ if(realTimePriority == 0)
+ {
+ pfprio = 1;
+ midiprio = 2;
+ }
+ else
if(realTimePriority == 1)
{
pfprio = 2;
@@ -444,11 +460,17 @@ bool MusE::seqStart()
midiprio = 6;
}
else
+ */
{
- pfprio = realTimePriority - 5;
+ //pfprio = realTimePriority - 5;
+ // p3.3.40
+ pfprio = realTimePriority + 1;
+
//midiprio = realTimePriority - 2;
// p3.3.37
- midiprio = realTimePriority + 1;
+ //midiprio = realTimePriority + 1;
+ // p3.3.40
+ midiprio = realTimePriority + 2;
}
}
@@ -1832,6 +1854,10 @@ void MusE::closeEvent(QCloseEvent*)
printf("Muse: Exiting Dsp\n");
AL::exitDsp();
+ if(debugMsg)
+ printf("Muse: Exiting OSC\n");
+ exitOSC();
+
qApp->quit();
}
@@ -2367,7 +2393,7 @@ static void usage(const char* prog, const char* txt)
fprintf(stderr, " -a no audio\n");
//fprintf(stderr, " -P n set real time priority to n (default: 50)\n");
fprintf(stderr, " -P n set audio driver real time priority to n (Dummy only, default 40. Else fixed by Jack.)\n");
- fprintf(stderr, " -Y n force midi real time priority to n (default: audio driver prio +1)\n");
+ fprintf(stderr, " -Y n force midi real time priority to n (default: audio driver prio +2)\n");
fprintf(stderr, " -p don't load LADSPA plugins\n");
#ifdef ENABLE_PYTHON
fprintf(stderr, " -y enable Python control support\n");
@@ -2626,6 +2652,9 @@ int main(int argc, char* argv[])
if(loadDSSI)
initDSSI();
+ // p3.3.39
+ initOSC();
+
initIcons();
initMetronome();
diff --git a/muse/muse/arranger/tlist.cpp b/muse/muse/arranger/tlist.cpp
index 1be0a240..e3c1a680 100644
--- a/muse/muse/arranger/tlist.cpp
+++ b/muse/muse/arranger/tlist.cpp
@@ -37,6 +37,11 @@
#include "event.h"
#include "midiedit/drummap.h"
#include "synth.h"
+#include "config.h"
+
+#ifdef DSSI_SUPPORT
+#include "dssihost.h"
+#endif
extern QPopupMenu* populateAddSynth(QWidget* parent, QObject* obj = 0, const char* slot = 0);
@@ -605,6 +610,16 @@ void TList::oportPropertyPopupMenu(Track* t, int x, int y)
p->setItemEnabled(0, synth->hasGui());
p->setItemChecked(0, synth->guiVisible());
+ #ifndef OSC_SUPPORT
+ #ifdef DSSI_SUPPORT
+ if(dynamic_cast<DssiSynthIF*>(synth->sif()))
+ {
+ p->setItemChecked(0, false);
+ p->setItemEnabled(0, false);
+ }
+ #endif
+ #endif
+
int n = p->exec(mapToGlobal(QPoint(x, y)), 0);
if (n == 0) {
bool show = !synth->guiVisible();
@@ -627,6 +642,17 @@ void TList::oportPropertyPopupMenu(Track* t, int x, int y)
p->setItemEnabled(0, port->hasGui());
p->setItemChecked(0, port->guiVisible());
+ #ifndef OSC_SUPPORT
+ #ifdef DSSI_SUPPORT
+ MidiDevice* dev = port->device();
+ if(dev && dev->isSynti() && (dynamic_cast<DssiSynthIF*>(((SynthI*)dev)->sif())))
+ {
+ p->setItemChecked(0, false);
+ p->setItemEnabled(0, false);
+ }
+ #endif
+ #endif
+
int n = p->exec(mapToGlobal(QPoint(x, y)), 0);
if (n == 0) {
bool show = !port->guiVisible();
diff --git a/muse/muse/audiotrack.cpp b/muse/muse/audiotrack.cpp
index fd6ba76a..ffc37ab8 100644
--- a/muse/muse/audiotrack.cpp
+++ b/muse/muse/audiotrack.cpp
@@ -211,47 +211,51 @@ Part* AudioTrack::newPart(Part*, bool /*clone*/)
//---------------------------------------------------------
void AudioTrack::addPlugin(PluginI* plugin, int idx)
+{
+ if (plugin == 0)
+ {
+ PluginI* oldPlugin = (*_efxPipe)[idx];
+ if (oldPlugin)
+ {
+ oldPlugin->setID(-1);
+ oldPlugin->setTrack(0);
+
+ int controller = oldPlugin->parameters();
+ for (int i = 0; i < controller; ++i)
{
- if (plugin == 0) {
- PluginI* oldPlugin = (*_efxPipe)[idx];
- if (oldPlugin) {
-
- oldPlugin->setID(-1);
- oldPlugin->setTrack(0);
-
- int controller = oldPlugin->parameters();
- for (int i = 0; i < controller; ++i) {
- int id = genACnum(idx, i);
- removeController(id);
- }
- }
- }
- efxPipe()->insert(plugin, idx);
- if (plugin) {
- plugin->setID(idx);
- plugin->setTrack(this);
-
- int controller = plugin->parameters();
- for (int i = 0; i < controller; ++i) {
- int id = genACnum(idx, i);
- const char* name = plugin->paramName(i);
- float min, max;
- plugin->range(i, &min, &max);
- CtrlValueType t = plugin->valueType();
- CtrlList* cl = new CtrlList(id);
- cl->setRange(min, max);
- cl->setName(QString(name));
- cl->setValueType(t);
- LADSPA_PortRangeHint range = plugin->range(i);
- if(LADSPA_IS_HINT_TOGGLED(range.HintDescriptor))
- cl->setMode(CtrlList::DISCRETE);
- else
- cl->setMode(CtrlList::INTERPOLATE);
- cl->setCurVal(plugin->param(i));
- addController(cl);
- }
- }
+ int id = genACnum(idx, i);
+ removeController(id);
}
+ }
+ }
+ efxPipe()->insert(plugin, idx);
+ if (plugin)
+ {
+ plugin->setID(idx);
+ plugin->setTrack(this);
+
+ int controller = plugin->parameters();
+ for (int i = 0; i < controller; ++i)
+ {
+ int id = genACnum(idx, i);
+ const char* name = plugin->paramName(i);
+ float min, max;
+ plugin->range(i, &min, &max);
+ CtrlValueType t = plugin->valueType();
+ CtrlList* cl = new CtrlList(id);
+ cl->setRange(min, max);
+ cl->setName(QString(name));
+ cl->setValueType(t);
+ LADSPA_PortRangeHint range = plugin->range(i);
+ if(LADSPA_IS_HINT_TOGGLED(range.HintDescriptor))
+ cl->setMode(CtrlList::DISCRETE);
+ else
+ cl->setMode(CtrlList::INTERPOLATE);
+ cl->setCurVal(plugin->param(i));
+ addController(cl);
+ }
+ }
+}
//---------------------------------------------------------
// addAuxSend
@@ -924,13 +928,14 @@ void AudioTrack::readAuxSend(Xml& xml)
bool AudioTrack::readProperties(Xml& xml, const QString& tag)
{
- if (tag == "plugin") {
+ if (tag == "plugin")
+ {
int rackpos;
for(rackpos = 0; rackpos < PipelineDepth; ++rackpos)
{
if(!(*_efxPipe)[rackpos])
- break;
- }
+ break;
+ }
if(rackpos < PipelineDepth)
{
PluginI* pi = new PluginI();
@@ -940,10 +945,10 @@ bool AudioTrack::readProperties(Xml& xml, const QString& tag)
delete pi;
else
(*_efxPipe)[rackpos] = pi;
- }
+ }
else
printf("can't load plugin - plugin rack is already full\n");
- }
+ }
else if (tag == "auxSend")
readAuxSend(xml);
else if (tag == "prefader")
@@ -1010,6 +1015,25 @@ bool AudioTrack::readProperties(Xml& xml, const QString& tag)
}
//---------------------------------------------------------
+// showPendingPluginNativeGuis
+// This is needed because OSC needs all tracks with plugins to be already
+// added to their track lists so it can find them and show their native guis.
+//---------------------------------------------------------
+
+void AudioTrack::showPendingPluginNativeGuis()
+{
+ for(int idx = 0; idx < PipelineDepth; ++idx)
+ {
+ PluginI* p = (*_efxPipe)[idx];
+ if(!p)
+ continue;
+
+ if(p->isShowNativeGuiPending())
+ p->showNativeGui(true);
+ }
+}
+
+//---------------------------------------------------------
// mapRackPluginsToControllers
//---------------------------------------------------------
diff --git a/muse/muse/dssihost.cpp b/muse/muse/dssihost.cpp
index d952d9f5..ec2e94a7 100644
--- a/muse/muse/dssihost.cpp
+++ b/muse/muse/dssihost.cpp
@@ -19,7 +19,6 @@
//=============================================================================
#include "config.h"
-
#ifdef DSSI_SUPPORT
// Turn on debugging messages
@@ -32,14 +31,14 @@
#include <signal.h>
#include <dlfcn.h>
#include <stdlib.h>
-#include <sys/stat.h>
+//#include <sys/stat.h>
//#include <dssi.h>
//#include <alsa/asoundlib.h>
#include <qdir.h>
-#include <qstringlist.h>
+//#include <qstringlist.h>
#include <qfileinfo.h>
#include <qpopupmenu.h>
-#include <qprocess.h>
+//#include <qprocess.h>
#include "dssihost.h"
#include "synth.h"
@@ -47,6 +46,8 @@
#include "jackaudio.h"
#include "midi.h"
#include "midiport.h"
+#include "stringparam.h"
+#include "plugin.h"
//#include "al/al.h"
//#include "al/xml.h"
#include "xml.h"
@@ -58,7 +59,9 @@
#include "globals.h"
#include "globaldefs.h"
//#include "al/dsp.h"
+#include "gconfig.h"
+/*
static lo_server_thread serverThread;
static char osc_path_tmp[1024];
static char* url;
@@ -130,13 +133,13 @@ int DssiSynthIF::oscUpdate(lo_arg **argv)
uiOscShowPath = (char *)malloc(pl + 10);
sprintf(uiOscShowPath, "%s/show", uiOscPath);
- /* At this point a more substantial host might also call
- * configure() on the UI to set any state that it had remembered
- * for the plugin instance. But we don't remember state for
- * plugin instances (see our own configure() implementation in
- * osc_configure_handler), and so we have nothing to send except
- * the optional project directory.
- */
+ // At this point a more substantial host might also call
+ // configure() on the UI to set any state that it had remembered
+ // for the plugin instance. But we don't remember state for
+ // plugin instances (see our own configure() implementation in
+ // osc_configure_handler), and so we have nothing to send except
+ // the optional project directory.
+
#ifdef DSSI_DEBUG
printf("DssiSynthIF::oscUpdate synth name:%s url:%s uiTarget:%p uiOscPath:%s uiOscConfigurePath:%s museProject:%s\n", synti->name().ascii(), url, uiTarget, uiOscPath, uiOscConfigurePath, museProject.ascii());
@@ -148,7 +151,7 @@ int DssiSynthIF::oscUpdate(lo_arg **argv)
DSSI_PROJECT_DIRECTORY_KEY, museProject.ascii());
#if 0
- /* Send current bank/program (-FIX- another race...) */
+ // Send current bank/program (-FIX- another race...)
if (instance->pendingProgramChange < 0) {
unsigned long bank = instance->currentBank;
unsigned long program = instance->currentProgram;
@@ -158,13 +161,13 @@ int DssiSynthIF::oscUpdate(lo_arg **argv)
}
}
- /* Send control ports */
+ // Send control ports
for (i = 0; i < instance->plugin->controlIns; i++) {
int in = i + instance->firstControlIn;
int port = pluginControlInPortNumbers[in];
lo_send(instance->uiTarget, instance->ui_osc_control_path, "if", port,
pluginControlIns[in]);
- /* Avoid overloading the GUI if there are lots and lots of ports */
+ // Avoid overloading the GUI if there are lots and lots of ports
if ((i+1) % 50 == 0)
usleep(300000);
}
@@ -283,6 +286,7 @@ int oscMessageHandler(const char* path, const char* types, lo_arg** argv,
return instance->oscExiting(argv);
return oscDebugHandler(path, types, argv, argc, data, user_data);
}
+*/
//---------------------------------------------------------
// scanDSSILib
@@ -291,14 +295,14 @@ int oscMessageHandler(const char* path, const char* types, lo_arg** argv,
static void scanDSSILib(const QFileInfo& fi)
{
//void* handle = dlopen(fi.filePath().toAscii().data(), RTLD_NOW);
- void* handle = dlopen(fi.filePath().ascii(), RTLD_NOW);
- //void* handle = dlopen(fi.absFilePath().ascii(), RTLD_NOW);
+ void* handle = dlopen(fi.filePath().latin1(), RTLD_NOW);
+ //void* handle = dlopen(fi.absFilePath().latin1(), RTLD_NOW);
if (handle == 0) {
fprintf(stderr, "scanDSSILib: dlopen(%s) failed: %s\n",
//fi.filePath().toAscii().data(), dlerror());
- fi.filePath().ascii(), dlerror());
- //fi.absFilePath().ascii(), dlerror());
+ fi.filePath().latin1(), dlerror());
+ //fi.absFilePath().latin1(), dlerror());
return;
}
@@ -316,7 +320,7 @@ static void scanDSSILib(const QFileInfo& fi)
"Are you sure this is a DSSI plugin file?\n",
//fi.filePath().toAscii().data(),
fi.filePath().ascii(),
- //fi.absFilePath().ascii(),
+ //fi.absFilePath().latin1(),
txt);
dlclose(handle);
@@ -358,7 +362,8 @@ static void scanDSSILib(const QFileInfo& fi)
{
Synth* s = *is;
//#ifdef DSSI_DEBUG
- // fprintf(stderr, "scanDSSILib: name:%s listname:%s lib:%s listlib:%s\n", label.ascii(), s->name().ascii(), fi.baseName(true).ascii(), s->baseName().ascii());
+ // fprintf(stderr, "scanDSSILib: name:%s listname:%s lib:%s listlib:%s\n",
+ // label.latin1(), s->name().latin1(), fi.baseName(true).latin1(), s->baseName().latin1());
//#endif
if(s->name() == label && s->baseName() == fi.baseName(true))
@@ -367,15 +372,14 @@ static void scanDSSILib(const QFileInfo& fi)
if(is != synthis.end())
continue;
- //DssiSynth* s = new DssiSynth(&fi, label);
- //DssiSynth* s = new DssiSynth(fi, label);
- DssiSynth* s = new DssiSynth(fi, label, QString(descr->LADSPA_Plugin->Name), QString(descr->LADSPA_Plugin->Maker), QString());
+ DssiSynth* s = new DssiSynth(fi, descr);
if(debugMsg)
{
- fprintf(stderr, "scanDSSILib: name:%s listname:%s lib:%s listlib:%s\n", label.ascii(), s->name().ascii(), fi.baseName(true).ascii(), s->baseName().ascii());
+ fprintf(stderr, "scanDSSILib: name:%s listname:%s lib:%s listlib:%s\n",
+ label.latin1(), s->name().latin1(), fi.baseName(true).latin1(), s->baseName().latin1());
int ai = 0, ao = 0, ci = 0, co = 0;
- for(int pt = 0; pt < descr->LADSPA_Plugin->PortCount; ++pt)
+ for(unsigned long pt = 0; pt < descr->LADSPA_Plugin->PortCount; ++pt)
{
LADSPA_PortDescriptor pd = descr->LADSPA_Plugin->PortDescriptors[pt];
if(LADSPA_IS_PORT_INPUT(pd) && LADSPA_IS_PORT_AUDIO(pd))
@@ -397,8 +401,10 @@ static void scanDSSILib(const QFileInfo& fi)
}
else
{
+ // NOTE: Just a test
//QFileInfo ffi(fi);
//plugins.add(&ffi, LADSPA_Descriptor_Function(NULL), descr->LADSPA_Plugin, false);
+ //plugins.add(&ffi, descr, false);
}
}
}
@@ -413,7 +419,7 @@ static void scanDSSIDir(const QString& s)
{
if(debugMsg)
//printf("scan DSSI plugin dir <%s>\n", s.toAscii().data());
- printf("scanDSSIDir: scan DSSI plugin dir <%s>\n", s.ascii());
+ printf("scanDSSIDir: scan DSSI plugin dir <%s>\n", s.latin1());
#ifdef __APPLE__
QDir pluginDir(s, QString("*.dylib"), QDir::Unsorted, QDir::Files);
@@ -433,7 +439,7 @@ static void scanDSSIDir(const QString& s)
for(unsigned int i = 0; i < list.count(); ++i)
{
if(debugMsg)
- printf("scanDSSIDir: found %s\n", (s + QString("/") + list[i]).ascii());
+ printf("scanDSSIDir: found %s\n", (s + QString("/") + list[i]).latin1());
QFileInfo fi(s + QString("/") + list[i]);
scanDSSILib(fi);
@@ -456,7 +462,7 @@ void initDSSI()
const char* p = dssiPath;
//QString pth = QString(dssiPath) + QString(":") + QString(ladspaPath);
- //const char* p = pth.ascii();
+ //const char* p = pth.latin1();
while (*p != '\0') {
const char* pe = p;
while (*pe != ':' && *pe != '\0')
@@ -474,18 +480,233 @@ void initDSSI()
if (*p == ':')
p++;
}
+
// Create OSC thread
+ //serverThread = lo_server_thread_new(0, oscError);
+ //snprintf(osc_path_tmp, 31, "/dssi");
+ //char* tmp = lo_server_thread_get_url(serverThread);
+ //url = (char *)malloc(strlen(tmp) + strlen(osc_path_tmp));
+ //sprintf(url, "%s%s", tmp, osc_path_tmp + 1);
+ //free(tmp);
+ //lo_server_thread_add_method(serverThread, 0, 0, oscMessageHandler, 0);
+ //lo_server_thread_start(serverThread);
+ }
+
+//---------------------------------------------------------
+// DssiSynth
+// Synth.label = plug.Label
+// Synth.descr = plug.Name
+// Synth.maker = plug.maker
+// Synth.version = nil (no such field in ladspa, maybe try copyright instead)
+//---------------------------------------------------------
- serverThread = lo_server_thread_new(0, oscError);
- snprintf(osc_path_tmp, 31, "/dssi");
- char* tmp = lo_server_thread_get_url(serverThread);
- url = (char *)malloc(strlen(tmp) + strlen(osc_path_tmp));
- sprintf(url, "%s%s", tmp, osc_path_tmp + 1);
- free(tmp);
+DssiSynth::DssiSynth(const QFileInfo& fi, const DSSI_Descriptor* d) :
+ //Synth(fi, label, descr, maker, ver)
+ Synth(fi, QString(d->LADSPA_Plugin->Label), QString(d->LADSPA_Plugin->Name), QString(d->LADSPA_Plugin->Maker), QString())
+{
+ df = 0;
+ handle = 0;
+ dssi = 0;
+ _hasGui = false;
+
+ const LADSPA_Descriptor* descr = d->LADSPA_Plugin;
+
+ _portCount = descr->PortCount;
+ //_portDescriptors = 0;
+ //if(_portCount)
+ // _portDescriptors = new LADSPA_PortDescriptor[_portCount];
+
+ _inports = 0;
+ _outports = 0;
+ _controlInPorts = 0;
+ _controlOutPorts = 0;
+ for(unsigned long k = 0; k < _portCount; ++k)
+ {
+ LADSPA_PortDescriptor pd = descr->PortDescriptors[k];
+ //_portDescriptors[k] = pd;
+ if(pd & LADSPA_PORT_AUDIO)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++_inports;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++_outports;
+ }
+ else
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++_controlInPorts;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++_controlOutPorts;
+ }
+ }
+
+ _inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(descr->Properties);
+
+ // Blacklist vst plugins in-place configurable for now.
+ if ((_inports != _outports) || (fi.baseName(true) == QString("dssi-vst") && !config.vstInPlace))
+ _inPlaceCapable = false;
+}
- lo_server_thread_add_method(serverThread, 0, 0, oscMessageHandler, 0);
- lo_server_thread_start(serverThread);
+DssiSynth::~DssiSynth()
+{
+
+}
+
+//---------------------------------------------------------
+// createSIF
+//---------------------------------------------------------
+
+SynthIF* DssiSynth::createSIF(SynthI* synti)
+{
+ if (_instances == 0)
+ {
+ //handle = dlopen(info.filePath().toAscii().data(), RTLD_NOW);
+ handle = dlopen(info.filePath().latin1(), RTLD_NOW);
+ //handle = dlopen(info.absFilePath().latin1(), RTLD_NOW);
+
+ if (handle == 0)
+ {
+ fprintf(stderr, "DssiSynth::createSIF dlopen(%s) failed: %s\n",
+ //info.filePath().toAscii().data(), dlerror());
+ info.filePath().latin1(), dlerror());
+ //info.absFilePath().latin1(), dlerror());
+
+ return 0;
+ }
+ df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor");
+
+ if (!df) {
+ const char *txt = dlerror();
+ fprintf(stderr,
+ "Unable to find dssi_descriptor() function in plugin "
+ "library file \"%s\": %s.\n"
+ "Are you sure this is a DSSI plugin file?\n",
+ //info.filePath().toAscii().data(),
+ info.filePath().latin1(),
+ //info.absFilePath().latin1(),
+
+ txt ? txt : "?");
+ dlclose(handle);
+ handle = 0;
+ return 0;
+ }
+ for (int i = 0;; ++i) {
+ dssi = df(i);
+ if (dssi == 0)
+ break;
+ QString label(dssi->LADSPA_Plugin->Label);
+ if (label == _name)
+ break;
+ }
+
+ if(dssi != 0)
+ {
+ _inports = 0;
+ _outports = 0;
+ _controlInPorts = 0;
+ _controlOutPorts = 0;
+
+ pIdx.clear();
+ opIdx.clear();
+ iIdx.clear();
+ oIdx.clear();
+ rpIdx.clear();
+ iUsedIdx.clear();
+ midiCtl2PortMap.clear();
+ port2MidiCtlMap.clear();
+ //synti->_guiUpdateControls.clear();
+
+ const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin;
+ //#ifdef DSSI_DEBUG
+ // printf("DssiSynth::createSIF ladspa plugin PortCount:%lu\n", d->PortCount);
+ //#endif
+
+ _portCount = descr->PortCount;
+
+ for (unsigned long k = 0; k < _portCount; ++k)
+ {
+ LADSPA_PortDescriptor pd = descr->PortDescriptors[k];
+
+ #ifdef DSSI_DEBUG
+ printf("DssiSynth::createSIF ladspa plugin Port:%ld Name:%s descriptor:%x\n", k, descr->PortNames[k], pd);
+ #endif
+
+ if (LADSPA_IS_PORT_AUDIO(pd))
+ {
+ if (LADSPA_IS_PORT_INPUT(pd))
+ {
+ ++_inports;
+ iIdx.push_back(k);
+ iUsedIdx.push_back(false); // Start out with all false.
+ }
+ else if (LADSPA_IS_PORT_OUTPUT(pd))
+ {
+ ++_outports;
+ oIdx.push_back(k);
+ }
+
+ rpIdx.push_back((unsigned long)-1);
+ }
+ else if (LADSPA_IS_PORT_CONTROL(pd))
+ {
+ if (LADSPA_IS_PORT_INPUT(pd))
+ {
+ rpIdx.push_back(_controlInPorts);
+ ++_controlInPorts;
+ pIdx.push_back(k);
+ // Set to false at first.
+ //synti->_guiUpdateControls.push_back(false);
+ }
+ else if (LADSPA_IS_PORT_OUTPUT(pd))
+ {
+ rpIdx.push_back((unsigned long)-1);
+ ++_controlOutPorts;
+ opIdx.push_back(k);
+ }
+ }
+ }
+
+ _inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(descr->Properties);
+ // Blacklist vst plugins in-place configurable for now.
+ if((_inports != _outports) || (info.baseName(true) == QString("dssi-vst") && !config.vstInPlace))
+ _inPlaceCapable = false;
+ }
+ }
+
+ if (dssi == 0)
+ {
+ //fprintf(stderr, "cannot found DSSI synti %s\n", _name.toAscii().data());
+ fprintf(stderr, "cannot find DSSI synti %s\n", _name.latin1());
+ dlclose(handle);
+ handle = 0;
+ df = 0;
+ return 0;
}
+
+ DssiSynthIF* sif = new DssiSynthIF(synti);
+ ++_instances;
+ sif->init(this);
+
+ //_plugin->incInstances(1);
+
+
+
+// static char oscUrl[1024];
+ //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().toAscii().data());
+ //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().latin1());
+// snprintf(oscUrl, 1024, "%s/%s/%s", url, info.baseName().latin1(), synti->name().latin1());
+ //QString guiPath(info.path() + "/" + info.baseName());
+ QString guiPath(info.dirPath() + "/" + info.baseName());
+ QDir guiDir(guiPath, "*", QDir::Unsorted, QDir::Files);
+ _hasGui = guiDir.exists();
+
+ //sif->initGui();
+
+ return sif;
+}
//---------------------------------------------------------
// guiVisible
@@ -493,7 +714,11 @@ void initDSSI()
bool DssiSynthIF::guiVisible() const
{
- return _guiVisible;
+ //return _guiVisible;
+ #ifdef OSC_SUPPORT
+ return _oscif.oscGuiVisible();
+ #endif
+ return false;
}
//---------------------------------------------------------
@@ -502,10 +727,17 @@ bool DssiSynthIF::guiVisible() const
void DssiSynthIF::showGui(bool v)
{
+ #ifdef OSC_SUPPORT
+
#ifdef DSSI_DEBUG
printf("DssiSynthIF::showGui(): v:%d visible:%d\n", v, guiVisible());
#endif
+ _oscif.oscShowGui(v);
+
+ #endif // OSC_SUPPORT
+
+ /*
if (v == guiVisible())
return;
@@ -522,7 +754,7 @@ void DssiSynthIF::showGui(bool v)
printf("DssiSynthIF::showGui(): No QProcess or process not running. Starting gui...\n");
#endif
- startGui();
+ initGui();
}
//for (int i = 0; i < 5; ++i) {
@@ -544,6 +776,7 @@ void DssiSynthIF::showGui(bool v)
lo_send(uiTarget, uiOscGuiPath, "");
_guiVisible = v;
+ */
}
//---------------------------------------------------------
@@ -574,6 +807,10 @@ bool DssiSynthIF::init(DssiSynth* s)
const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
handle = ld->instantiate(ld, sampleRate);
+ #ifdef OSC_SUPPORT
+ _oscif.oscSetSynthIF(this);
+ #endif
+
queryPrograms();
int inports = synth->_inports;
@@ -605,8 +842,8 @@ bool DssiSynthIF::init(DssiSynth* s)
}
}
- int controlPorts = synth->_controller;
- int controlOutPorts = synth->_controllerOut;
+ int controlPorts = synth->_controlInPorts;
+ int controlOutPorts = synth->_controlOutPorts;
if(controlPorts != 0)
controls = new Port[controlPorts];
@@ -620,12 +857,17 @@ bool DssiSynthIF::init(DssiSynth* s)
synth->midiCtl2PortMap.clear();
synth->port2MidiCtlMap.clear();
+ synti->_guiUpdateControls.clear();
+ synti->_guiUpdateProgram = false;
for (int k = 0; k < controlPorts; ++k) {
int i = synth->pIdx[k];
//controls[k].val = ladspaDefaultValue(ld, i);
ladspaDefaultValue(ld, i, &controls[k].val);
+ // Set to false at first.
+ synti->_guiUpdateControls.push_back(false);
+
#ifdef DSSI_DEBUG
printf("DssiSynthIF::init control port:%d port idx:%d name:%s\n", k, i, ld->PortNames[i]);
#endif
@@ -689,8 +931,6 @@ bool DssiSynthIF::init(DssiSynth* s)
for (int k = 0; k < controlOutPorts; ++k) {
int i = synth->opIdx[k];
- //controls[k].val = ladspaDefaultValue(ld, i);
- ladspaDefaultValue(ld, i, &controlsOut[k].val);
#ifdef DSSI_DEBUG
printf("DssiSynthIF::init control output port:%d port idx:%d name:%s\n", k, i, ld->PortNames[i]);
@@ -699,6 +939,9 @@ bool DssiSynthIF::init(DssiSynth* s)
// p3.3.39 Removed.
/*
+ //controls[k].val = ladspaDefaultValue(ld, i);
+ ladspaDefaultValue(ld, i, &controlsOut[k].val);
+
// This code is duplicated in ::getControllerInfo()
//
@@ -770,14 +1013,38 @@ bool DssiSynthIF::init(DssiSynth* s)
if (ld->activate)
ld->activate(handle);
- if (dssi->configure) {
- char *rv = dssi->configure(handle, DSSI_PROJECT_DIRECTORY_KEY,
- //song->projectPath().toAscii().data());
- museProject.ascii());
+ // Set current configuration values.
+ if(dssi->configure)
+ {
+ char *rv = dssi->configure(handle, DSSI_PROJECT_DIRECTORY_KEY,
+ museProject.latin1()); //song->projectPath()
+
+ if(rv)
+ {
+ fprintf(stderr, "MusE: Warning: plugin doesn't like project directory: \"%s\"\n", rv);
+ free(rv);
+ }
+
+ for(ciStringParamMap r = synti->_stringParamMap.begin(); r != synti->_stringParamMap.end(); ++r)
+ {
+ rv = 0;
+ rv = dssi->configure(handle, r->first.c_str(), r->second.c_str());
+ if(rv)
+ {
+ fprintf(stderr, "MusE: Warning: plugin config key: %s value: %s \"%s\"\n", r->first.c_str(), r->second.c_str(), rv);
+ free(rv);
+ }
+ }
+ }
- if (rv)
- fprintf(stderr, "MusE: Warning: plugin doesn't like project directory: \"%s\"\n", rv);
- }
+ // Set current program.
+ if(dssi->select_program)
+ dssi->select_program(handle, synti->_curBankL, synti->_curProgram);
+
+ //
+ // For stored initial control values, let SynthI::initInstance() take care of that via ::setParameter().
+ //
+
return true;
}
@@ -792,15 +1059,28 @@ DssiSynthIF::DssiSynthIF(SynthI* s)
printf("DssiSynthIF::DssiSynthIF\n");
#endif
- _guiVisible = false;
- uiTarget = 0;
- uiOscShowPath = 0;
- uiOscControlPath = 0;
- uiOscConfigurePath = 0;
- uiOscProgramPath = 0;
- uiOscPath = 0;
+ synth = 0;
+ handle = NULL;
+ controls = 0;
+ controlsOut = 0;
+
+ //_curBank = 0;
+ //_curProgram = 0;
+
+ //#ifdef OSC_SUPPORT
+ //_oscif.setSynthIF(this);
+ //#endif
+
+ //_guiVisible = false;
+ //uiTarget = 0;
+ //uiOscShowPath = 0;
+ //uiOscControlPath = 0;
+ //uiOscConfigurePath = 0;
+ //uiOscProgramPath = 0;
+ //uiOscPath = 0;
//guiPid = -1;
- guiQProc = 0;
+ //guiQProc = 0;
+
audioInBuffers = 0;
audioOutBuffers = 0;
}
@@ -855,6 +1135,7 @@ DssiSynthIF::~DssiSynthIF()
}
}
+ /*
//if (guiPid != -1)
// kill(guiPid, SIGHUP);
if(guiQProc)
@@ -871,6 +1152,20 @@ DssiSynthIF::~DssiSynthIF()
//delete guiQProc;
}
+ if(uiOscShowPath)
+ free(uiOscShowPath);
+ if(uiOscControlPath)
+ free(uiOscControlPath);
+ if(uiOscConfigurePath)
+ free(uiOscConfigurePath);
+ if(uiOscProgramPath)
+ free(uiOscProgramPath);
+ if(uiOscPath)
+ free(uiOscPath);
+ if(uiTarget)
+ lo_address_free(uiTarget);
+ */
+
if(audioInBuffers)
{
//for(int i = 0; i < synth->_inports; ++i)
@@ -878,7 +1173,7 @@ DssiSynthIF::~DssiSynthIF()
// if(audioInBuffers[i])
// delete[] audioInBuffers[i];
//}
- for(int i = 0; i < synth->_inports; ++i)
+ for(unsigned long i = 0; i < synth->_inports; ++i)
{
if(audioInBuffers[i])
free(audioInBuffers[i]);
@@ -893,7 +1188,7 @@ DssiSynthIF::~DssiSynthIF()
// if(audioOutBuffers[i])
// delete[] audioOutBuffers[i];
//}
- for(int i = 0; i < synth->_outports; ++i)
+ for(unsigned long i = 0; i < synth->_outports; ++i)
{
if(audioOutBuffers[i])
free(audioOutBuffers[i]);
@@ -902,19 +1197,52 @@ DssiSynthIF::~DssiSynthIF()
}
if(controls)
- delete controls;
+ delete[] controls;
if(controlsOut)
- delete controlsOut;
+ delete[] controlsOut;
+}
+
+//---------------------------------------------------------
+// getParameter
+//---------------------------------------------------------
+
+float DssiSynthIF::getParameter(unsigned long n)
+{
+ if(n >= synth->_controlInPorts)
+ {
+ printf("DssiSynthIF::getParameter param number %ld out of range of ports:%ld\n", n, synth->_controlInPorts);
+ return 0.0;
+ }
+
+ if(!controls)
+ return 0.0;
+
+ return controls[n].val;
}
//---------------------------------------------------------
// setParameter
//---------------------------------------------------------
-void DssiSynthIF::setParameter(int, float)
- {
- }
+void DssiSynthIF::setParameter(unsigned long n, float v)
+{
+ if(n >= synth->_controlInPorts)
+ {
+ printf("DssiSynthIF::setParameter param number %ld out of range of ports:%ld\n", n, synth->_controlInPorts);
+ return;
+ }
+
+ if(!controls)
+ return;
+
+ controls[n].val = v;
+
+ // Notify that changes are to be sent upon heartbeat.
+ // TODO: No, at least not for now. So far, setParameter is only called during loading of stored params,
+ // and we don't want this interfering with oscUpdate which also sends the values.
+ //synti->_guiUpdateControls[n] = true;
+}
//---------------------------------------------------------
// write
@@ -963,31 +1291,54 @@ void DssiSynthIF::write(int level, Xml& xml) const
printf("support for vst chunks not compiled in!\n");
#endif
- // p3.3.39 Store the state of program and bank and all input control values, but only if VSTSAVE above didn't do it already!
+ /*
+ // p3.3.39 Store the state of current program and bank and all input control values, but only if VSTSAVE above didn't do it already!
// TODO: Not quite good enough, we would want to store all controls for EACH program, not just the current one.
// Need to modify controls array to be inside a program array and act as a cache when the user changes a control on a particular program.
- /*
if(!vstsaved)
{
- if(synth->_controller)
+ if(synth->_controlInPorts)
{
+ // TODO: Hmm, what if these sizes change (platform etc.)? Hard code? Not good - need to store complete value.
const int fs = sizeof(float);
const int uls = sizeof(unsigned long);
- const unsigned long len = synth->_controller * fs + 2 * uls; // Controllers and bank + program.
- unsigned long prog = 0; // TODO: To be added to class. Dummy zero for now.
- unsigned long bnk = 0;
+ // Data length: Version major and minor bytes, bank + program, and controllers.
+ const unsigned long len = 2 + 2 * uls + synth->_controlInPorts * fs;
+
+ unsigned long prog = _curBank;
+ unsigned long bnk = _curProgram;
xml.tag(level++, "midistate");
xml.nput(level++, "<event type=\"%d\"", Sysex);
- xml.nput(" datalen=\"%d\">\n", len+9); // + "PARAMSAVE" length
+ xml.nput(" datalen=\"%d\">\n", len+9); // "PARAMSAVE" length + data length.
xml.nput(level, "");
xml.nput("50 41 52 41 4d 53 41 56 45 "); // Embed a save marker string "PARAMSAVE".
unsigned long i = 9;
- // Store program...
- void* p = &prog;
+ // Store PARAMSAVE version major...
+ char uc = DSSI_PARAMSAVE_VERSION_MAJOR;
+ if(i && ((i % 16) == 0))
+ {
+ xml.nput("\n");
+ xml.nput(level, "");
+ }
+ xml.nput("%02x ", uc & 0xff);
+ ++i;
+
+ // Store PARAMSAVE version minor...
+ uc = DSSI_PARAMSAVE_VERSION_MINOR;
+ if(i && ((i % 16) == 0))
+ {
+ xml.nput("\n");
+ xml.nput(level, "");
+ }
+ xml.nput("%02x ", uc & 0xff);
+ ++i;
+
+ // Store bank...
+ void* p = &bnk;
for(int j = 0; j < uls; ++j)
{
if(i && ((i % 16) == 0))
@@ -998,8 +1349,9 @@ void DssiSynthIF::write(int level, Xml& xml) const
xml.nput("%02x ", ((char*)(p))[j] & 0xff);
++i;
}
- // Store bank...
- p = &bnk;
+
+ // Store program...
+ p = &prog;
for(int j = 0; j < uls; ++j)
{
if(i && ((i % 16) == 0))
@@ -1010,8 +1362,9 @@ void DssiSynthIF::write(int level, Xml& xml) const
xml.nput("%02x ", ((char*)(p))[j] & 0xff);
++i;
}
+
// Store controls...
- for(int c = 0; c < synth->_controller; ++c)
+ for(unsigned long c = 0; c < synth->_controlInPorts; ++c)
{
float v = controls[c].val;
p = &v;
@@ -1032,6 +1385,14 @@ void DssiSynthIF::write(int level, Xml& xml) const
}
}
*/
+
+ // Store controls as parameters...
+ for(unsigned long c = 0; c < synth->_controlInPorts; ++c)
+ {
+ float f = controls[c].val;
+ xml.floatTag(level, "param", f);
+ //xml.tag(level, "param name=\"%s\" val=\"%s\"/", name, r->first.c_str(), r->second.c_str());
+ }
}
//---------------------------------------------------------
@@ -1106,8 +1467,18 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
int bank = (a >> 8) & 0xff;
int prog = a & 0xff;
+ //_curBank = bank;
+ //_curProgram = prog;
+ synti->_curBankH = 0;
+ synti->_curBankL = bank;
+ synti->_curProgram = prog;
+
if(dssi->select_program)
+ {
dssi->select_program(handle, bank, prog);
+ // Notify that changes are to be sent upon heartbeat.
+ synti->_guiUpdateProgram = true;
+ }
// Event pointer not filled. Return false.
return false;
}
@@ -1129,8 +1500,19 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
int bank = (b >> 8) & 0xff;
int prog = b & 0xff;
+
+ //_curBank = bank;
+ //_curProgram = prog;
+ synti->_curBankH = 0;
+ synti->_curBankL = bank;
+ synti->_curProgram = prog;
+
if(dssi->select_program)
+ {
dssi->select_program(handle, bank, prog);
+ // Notify that changes are to be sent upon heartbeat.
+ synti->_guiUpdateProgram = true;
+ }
// Event pointer not filled. Return false.
return false;
}
@@ -1264,9 +1646,9 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
}
//int num = ip->first;
- int k = ip->second;
+ unsigned long k = ip->second;
- int i = synth->pIdx[k];
+ unsigned long i = synth->pIdx[k];
int ctlnum = DSSI_NONE;
if(dssi->get_midi_controller_for_port)
@@ -1276,7 +1658,7 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
if(ctlnum == DSSI_NONE)
{
// Sanity check.
- if(k > synth->_controller)
+ if(k > synth->_controlInPorts)
return false;
// TODO: If necessary... choose non-existing numbers...
@@ -1292,7 +1674,7 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
else
{
#ifdef DSSI_DEBUG
- printf("DssiSynthIF::processEvent plugin requests DSSI-style ctlnum:%x(h) %d(d) be mapped to control port:%d...\n", ctlnum, ctlnum, i);
+ printf("DssiSynthIF::processEvent plugin requests DSSI-style ctlnum:%x(h) %d(d) be mapped to control port:%ld...\n", ctlnum, ctlnum, i);
#endif
int c = ctlnum;
@@ -1327,13 +1709,15 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
#ifdef DSSI_DEBUG
//fprintf(stderr, "DssiSynthIF::processEvent No midi controller for control port:%d port:%d dataA:%d Converting val from:%d to ladspa:%f\n", i, k, a, b, val);
- fprintf(stderr, "DssiSynthIF::processEvent control port:%d port:%d dataA:%d Converting val from:%d to ladspa:%f\n", i, k, a, b, val);
+ fprintf(stderr, "DssiSynthIF::processEvent control port:%ld port:%ld dataA:%d Converting val from:%d to ladspa:%f\n", i, k, a, b, val);
#endif
// Set the ladspa port value.
controls[k].val = val;
// FIXME: Testing - Works but is this safe in a RT process callback? Try hooking into gui heartbeat timer instead...
//lo_send(uiTarget, uiOscControlPath, "if", i, val);
+ // Notify that changes are to be sent upon heartbeat.
+ synti->_guiUpdateControls[k] = true;
// Since we absorbed the message as a ladspa control change, return false - the event is not filled.
return false;
@@ -1438,9 +1822,9 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
// Event not filled.
return false;
}
- // p3.3.39 Read the state of program and bank and all input control values.
- // TODO: Needs to be better. See write().
/*
+ // p3.3.39 Read the state of current bank and program and all input control values.
+ // TODO: Needs to be better. See write().
else
if (QString((const char*)e.data()).startsWith("PARAMSAVE"))
{
@@ -1451,16 +1835,21 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
unsigned long dlen = e.len() - 9; // Minus "PARAMSAVE"
if(dlen > 0)
{
- if(dlen < 2 * sizeof(unsigned long))
- printf("DssiSynthIF::processEvent Error: PARAMSAVE data length does not include at least program and bank!\n");
+ //if(dlen < 2 * sizeof(unsigned long))
+ if(dlen < (2 + 2 * sizeof(unsigned long))) // Version major and minor bytes, bank and program.
+ printf("DssiSynthIF::processEvent Error: PARAMSAVE data length does not include at least version major and minor, bank and program!\n");
else
{
- //unsigned long* const ulp = (unsigned long*)(e.data() + 9); // After "PARAMSAVE"
- //unsigned long prog = ulp[0];
- //unsigned long bnk = ulp[1];
- // TODO: TODO: Save them in class and set plugin program and bank.
+ // Not required, yet.
+ //char vmaj = *((char*)(e.data() + 9)); // After "PARAMSAVE"
+ //char vmin = *((char*)(e.data() + 10));
+
+ unsigned long* const ulp = (unsigned long*)(e.data() + 11); // After "PARAMSAVE" + version major and minor.
+ // TODO: TODO: Set plugin bank and program.
+ _curBank = ulp[0];
+ _curProgram = ulp[1];
- dlen -= 2 * sizeof(unsigned long); // After the program and bank.
+ dlen -= (2 + 2 * sizeof(unsigned long)); // After the version major and minor, bank and program.
if(dlen > 0)
{
@@ -1468,13 +1857,14 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
printf("DssiSynthIF::processEvent Error: PARAMSAVE float data length not integral multiple of float size!\n");
else
{
- const int n = dlen / sizeof(float);
- if(n != synth->_controller)
- printf("DssiSynthIF::processEvent Warning: PARAMSAVE number of floats:%d != number of controls:%d\n", n, synth->_controller);
+ const unsigned long n = dlen / sizeof(float);
+ if(n != synth->_controlInPorts)
+ printf("DssiSynthIF::processEvent Warning: PARAMSAVE number of floats:%ld != number of controls:%ld\n", n, synth->_controlInPorts);
- float* const fp = (float*)(e.data() + 9 + 2 * sizeof(unsigned long)); // After "PARAMSAVE" and progam and bank.
+ // Point to location after "PARAMSAVE", version major and minor, bank and progam.
+ float* const fp = (float*)(e.data() + 9 + 2 + 2 * sizeof(unsigned long));
- for(int i = 0; i < synth->_controller && i < n; ++i)
+ for(unsigned long i = 0; i < synth->_controlInPorts && i < n; ++i)
{
const float v = fp[i];
controls[i].val = v;
@@ -1610,6 +2000,42 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
++nevents;
}
+ // Now process OSC gui input control fifo events.
+ // It is probably more important that these are processed last so that they take precedence over all other
+ // events because OSC + DSSI/DSSI-VST are fussy about receiving feedback via these control ports, from GUI changes.
+ #ifdef OSC_SUPPORT
+ unsigned long ctls = synth->_controlInPorts;
+ for(unsigned long k = 0; k < ctls; ++k)
+ {
+ OscControlFifo* cfifo = _oscif.oscFifo(k);
+ if(!cfifo)
+ continue;
+
+ // If there are 'events' in the fifo, get exactly one 'event' per control per process cycle...
+ if(!cfifo->isEmpty())
+ {
+ OscControlValue v = cfifo->get();
+
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, "DssiSynthIF::getData OscControlFifo event input control number:%ld value:%f\n", k, v.value);
+ #endif
+
+ // Set the ladspa control port value.
+ controls[k].val = v.value;
+
+ // TODO: (From plugin module, adapt for synth if/when our own plugin gui is added to synths).
+ // Need to update the automation value, otherwise the block above overwrites with the last automation value.
+ ///if(_track)
+ ///{
+ // Since we are now in the audio thread context, there's no need to send a message,
+ // just modify directly.
+ //audio->msgSetPluginCtrlVal(this, genACnum(_id, i), controls[i].val);
+ /// _track->setPluginCtrlVal(k, v.value)
+ ///}
+ }
+ }
+ #endif
+
/* // This is from MESS... Tried this here, didn't work, need to re-adapt, try again.
int evTime = i->time();
if(evTime == 0)
@@ -1649,7 +2075,7 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
// All ports must be connected to something!
// First, copy the given input buffers to our local input buffers.
- int np, k;
+ unsigned long np, k;
//np = portsin > synth->_inports ? synth->_inports : portsin;
//for(k = 0; k < np; ++k)
// memcpy(audioInBuffers[k], inbuffer[k], sizeof(float) * n);
@@ -1733,6 +2159,13 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
if(synth->dssi->run_synth)
{
synth->dssi->run_synth(handle, n, events, nevents);
+
+ // NOTE: Just a test
+ //for(int m = 0; m < n; ++m)
+ //{
+ // synth->dssi->run_synth(handle, 1, events, nevents);
+ //}
+
}
else if (synth->dssi->run_multiple_synths)
{
@@ -1769,9 +2202,10 @@ bool DssiSynthIF::putEvent(const MidiPlayEvent& ev)
//---------------------------------------------------------
void DssiSynth::incInstances(int val)
- {
+{
_instances += val;
- if (_instances == 0) {
+ if (_instances == 0)
+ {
if (handle)
{
#ifdef DSSI_DEBUG
@@ -1780,143 +2214,33 @@ void DssiSynth::incInstances(int val)
dlclose(handle);
}
- dssi = 0;
- df = 0;
- }
+ handle = 0;
+ dssi = NULL;
+ df = NULL;
+ pIdx.clear();
+ opIdx.clear();
+ iIdx.clear();
+ oIdx.clear();
+ rpIdx.clear();
+ iUsedIdx.clear();
+ midiCtl2PortMap.clear();
+ port2MidiCtlMap.clear();
+ //synti->_guiUpdateControls.clear();
}
+}
//---------------------------------------------------------
-// createSIF
+// initGui
//---------------------------------------------------------
-
-SynthIF* DssiSynth::createSIF(SynthI* synti)
+bool DssiSynthIF::initGui()
{
- if (_instances == 0)
- {
- //handle = dlopen(info.filePath().toAscii().data(), RTLD_NOW);
- handle = dlopen(info.filePath().ascii(), RTLD_NOW);
- //handle = dlopen(info.absFilePath().ascii(), RTLD_NOW);
-
- if (handle == 0)
- {
- fprintf(stderr, "DssiSynth::createSIF dlopen(%s) failed: %s\n",
- //info.filePath().toAscii().data(), dlerror());
- info.filePath().ascii(), dlerror());
- //info.absFilePath().ascii(), dlerror());
-
- return 0;
- }
- df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor");
-
- if (!df) {
- const char *txt = dlerror();
- fprintf(stderr,
- "Unable to find dssi_descriptor() function in plugin "
- "library file \"%s\": %s.\n"
- "Are you sure this is a DSSI plugin file?\n",
- //info.filePath().toAscii().data(),
- info.filePath().ascii(),
- //info.absFilePath().ascii(),
-
- txt ? txt : "?");
- dlclose(handle);
- handle = 0;
- return 0;
- }
- for (int i = 0;; ++i) {
- dssi = df(i);
- if (dssi == 0)
- break;
- QString label(dssi->LADSPA_Plugin->Label);
- if (label == _name)
- break;
- }
-
- if(dssi != 0)
- {
- _inports = 0;
- _outports = 0;
- _controller = 0;
- _controllerOut = 0;
- const LADSPA_Descriptor* d = dssi->LADSPA_Plugin;
- //#ifdef DSSI_DEBUG
- // printf("DssiSynth::createSIF ladspa plugin PortCount:%lu\n", d->PortCount);
- //#endif
-
- for (unsigned k = 0; k < d->PortCount; ++k)
- {
- LADSPA_PortDescriptor pd = d->PortDescriptors[k];
-
- #ifdef DSSI_DEBUG
- printf("DssiSynth::createSIF ladspa plugin Port:%d Name:%s descriptor:%x\n", k, d->PortNames[k], pd);
- #endif
-
- if (LADSPA_IS_PORT_AUDIO(pd))
- {
- if (LADSPA_IS_PORT_INPUT(pd))
- {
- ++_inports;
- iIdx.push_back(k);
- iUsedIdx.push_back(false); // Start out with all false.
- }
- else if (LADSPA_IS_PORT_OUTPUT(pd))
- {
- ++_outports;
- oIdx.push_back(k);
- }
-
- rpIdx.push_back(-1);
- }
- else if (LADSPA_IS_PORT_CONTROL(pd))
- {
- if (LADSPA_IS_PORT_INPUT(pd))
- {
- rpIdx.push_back(_controller);
- ++_controller;
- pIdx.push_back(k);
- }
- else if (LADSPA_IS_PORT_OUTPUT(pd))
- {
- rpIdx.push_back(-1);
- ++_controllerOut;
- opIdx.push_back(k);
- }
- }
- }
- }
- }
- if (dssi == 0)
- {
- //fprintf(stderr, "cannot found DSSI synti %s\n", _name.toAscii().data());
- fprintf(stderr, "cannot find DSSI synti %s\n", _name.ascii());
- dlclose(handle);
- handle = 0;
- df = 0;
- return 0;
- }
- DssiSynthIF* sif = new DssiSynthIF(synti);
- ++_instances;
- sif->init(this);
-
- static char oscUrl[1024];
- //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().toAscii().data());
- //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().ascii());
- snprintf(oscUrl, 1024, "%s/%s/%s", url, info.baseName().ascii(), synti->name().ascii());
- //QString guiPath(info.path() + "/" + info.baseName());
- QString guiPath(info.dirPath() + "/" + info.baseName());
- QDir guiDir(guiPath, "*", QDir::Unsorted, QDir::Files);
- _hasGui = guiDir.exists();
+ #ifdef OSC_SUPPORT
+ return _oscif.oscInitGui();
+ #endif
- //sif->startGui();
+ return true;
- return sif;
-}
-
-//---------------------------------------------------------
-// startGui
-//---------------------------------------------------------
-bool DssiSynthIF::startGui()
-{
+ /*
// Are we already running? We don't want to allow another process do we...
if((guiQProc != 0) && (guiQProc->isRunning()))
return true;
@@ -1926,8 +2250,8 @@ bool DssiSynthIF::startGui()
//
static char oscUrl[1024];
//snprintf(oscUrl, 1024, "%s/%s", url, synti->name().toAscii().data());
- //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().ascii());
- snprintf(oscUrl, 1024, "%s/%s/%s", url, synth->info.baseName().ascii(), synti->name().ascii());
+ //snprintf(oscUrl, 1024, "%s/%s", url, synti->name().latin1());
+ snprintf(oscUrl, 1024, "%s/%s/%s", url, synth->info.baseName().latin1(), synti->name().latin1());
//QString guiPath(info.path() + "/" + info.baseName());
QString guiPath(synth->info.dirPath() + "/" + synth->info.baseName());
@@ -1951,25 +2275,25 @@ bool DssiSynthIF::startGui()
struct stat buf;
//if (stat(gui.toAscii().data(), &buf)) {
- if (stat(gui.ascii(), &buf)) {
+ if (stat(gui.latin1(), &buf)) {
perror("stat failed");
continue;
}
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::startGui %s %s %s %s %s\n",
+ fprintf(stderr, "DssiSynthIF::initGui %s %s %s %s\n",
//fi.filePath().toAscii().data(),
//fi.fileName().toAscii().data(),
- fi.filePath().ascii(),
- fi.fileName().ascii(),
+ fi.filePath().latin1(),
+ //fi.fileName().latin1(),
oscUrl,
- synth->info.filePath().ascii(),
+ synth->info.filePath().latin1(),
//name().toAscii().data(),
- synth->name().ascii());
+ synth->name().latin1());
#endif
if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) &&
@@ -1995,13 +2319,13 @@ bool DssiSynthIF::startGui()
guiQProc->addArgument(QString("channel 1"));
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::startGui starting QProcess\n");
+ fprintf(stderr, "DssiSynthIF::initGui starting QProcess\n");
#endif
if(guiQProc->start() == TRUE)
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::startGui started QProcess\n");
+ fprintf(stderr, "DssiSynthIF::initGui started QProcess\n");
#endif
//guiPid = guiQProc->processIdentifier();
@@ -2009,44 +2333,39 @@ bool DssiSynthIF::startGui()
else
{
- /*
- execlp(
- //fi.filePath().toAscii().data(),
- //fi.fileName().toAscii().data(),
- fi.filePath().ascii(),
- fi.fileName().ascii(),
+ // execlp(
+ // fi.filePath().toAscii().data(),
+ // fi.fileName().toAscii().data(),
+ // fi.filePath().latin1(),
+ // fi.fileName().latin1(),
- oscUrl,
+ // oscUrl,
- //info.filePath().toAscii().data(),
- //name().toAscii().data(),
- synth->info.filePath().ascii(),
- synth->name().ascii(),
+ // info.filePath().toAscii().data(),
+ // name().toAscii().data(),
+ // synth->info.filePath().latin1(),
+ // synth->name().latin1(),
- "channel 1", (void*)0);
- */
+ // "channel 1", (void*)0);
fprintf(stderr, "exec %s %s %s %s failed: %s\n",
- //fi.filePath().toAscii().data(),
- //fi.fileName().toAscii().data(),
- fi.filePath().ascii(),
- fi.fileName().ascii(),
-
+ // fi.filePath().toAscii().data(),
+ // fi.fileName().toAscii().data(),
+ fi.filePath().latin1(),
+ fi.fileName().latin1(),
oscUrl,
-
- //name().toAscii().data(),
- synth->name().ascii(),
-
+ // name().toAscii().data(),
+ synth->name().latin1(),
strerror(errno));
// It's Ok, Keep going. So nothing happens. So what. The timeout in showGui will just leave.
// Maybe it's a 'busy' issue somewhere - allow to try again later + save work now.
- //exit(1);
+ // exit(1);
}
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::startGui after QProcess\n");
+ fprintf(stderr, "DssiSynthIF::initGui after QProcess\n");
#endif
}
}
@@ -2056,29 +2375,134 @@ bool DssiSynthIF::startGui()
else {
printf("%s: no dir for dssi gui found: %s\n",
//name().toAscii().data(), guiPath.toAscii().data());
- synth->name().ascii(), guiPath.ascii());
+ synth->name().latin1(), guiPath.latin1());
//synth->_hasGui = false;
}
return true;
+ */
+}
+
+//---------------------------------------------------------
+// guiHeartBeat
+//---------------------------------------------------------
+
+void DssiSynthIF::guiHeartBeat()
+{
+ #ifdef OSC_SUPPORT
+ // Update the gui's program if needed.
+ if(synti->_guiUpdateProgram)
+ {
+ _oscif.oscSendProgram(synti->_curProgram, synti->_curBankL);
+ synti->_guiUpdateProgram = false;
+ }
+
+ // Update the gui's controls if needed.
+ unsigned long ports = synth->_controlInPorts;
+ if(ports > synti->_guiUpdateControls.size())
+ return;
+ for(unsigned long i = 0; i < ports; ++i)
+ {
+ if(synti->_guiUpdateControls[i])
+ {
+ unsigned long k = synth->pIdx[i];
+ _oscif.oscSendControl(k, controls[i].val);
+
+ // Reset.
+ synti->_guiUpdateControls[i] = false;
+ }
+ }
+ #endif
+}
+
+#ifdef OSC_SUPPORT
+//---------------------------------------------------------
+// oscUpdate
+//---------------------------------------------------------
+
+int DssiSynthIF::oscUpdate()
+{
+ // Send project directory.
+ _oscif.oscSendConfigure(DSSI_PROJECT_DIRECTORY_KEY, museProject.latin1()); // song->projectPath()
+
+ // Send current string configuration parameters.
+ //StringParamMap& map = synti->_stringParamMap;
+ int i = 0;
+ for(ciStringParamMap r = synti->_stringParamMap.begin(); r != synti->_stringParamMap.end(); ++r)
+ {
+ _oscif.oscSendConfigure(r->first.c_str(), r->second.c_str());
+ // Avoid overloading the GUI if there are lots and lots of params.
+ if((i+1) % 50 == 0)
+ usleep(300000);
+ ++i;
+ }
+
+ // Send current bank and program.
+ //unsigned long bank, prog;
+ //synti->currentProg(&prog, &bank, 0);
+ //_oscif.oscSendProgram(prog, bank);
+ _oscif.oscSendProgram(synti->_curProgram, synti->_curBankL);
+
+ // Send current control values.
+ unsigned long ports = synth->_controlInPorts;
+ for(unsigned long i = 0; i < ports; ++i)
+ {
+ unsigned long k = synth->pIdx[i];
+ _oscif.oscSendControl(k, controls[i].val);
+ // Avoid overloading the GUI if there are lots and lots of ports.
+ if((i+1) % 50 == 0)
+ usleep(300000);
+ }
+
+
+#if 0
+ /* Send current bank/program (-FIX- another race...) */
+ if (instance->pendingProgramChange < 0) {
+ unsigned long bank = instance->currentBank;
+ unsigned long program = instance->currentProgram;
+ instance->uiNeedsProgramUpdate = 0;
+ if (instance->uiTarget) {
+ lo_send(instance->uiTarget, instance->ui_osc_program_path, "ii", bank, program);
+ }
+ }
+
+ /* Send control ports */
+ for (i = 0; i < instance->plugin->controlIns; i++) {
+ int in = i + instance->firstControlIn;
+ int port = pluginControlInPortNumbers[in];
+ lo_send(instance->uiTarget, instance->ui_osc_control_path, "if", port,
+ pluginControlIns[in]);
+ /* Avoid overloading the GUI if there are lots and lots of ports */
+ if ((i+1) % 50 == 0)
+ usleep(300000);
+ }
+#endif
+ return 0;
}
//---------------------------------------------------------
// oscProgram
//---------------------------------------------------------
-int DssiSynthIF::oscProgram(lo_arg** argv)
+int DssiSynthIF::oscProgram(unsigned long program, unsigned long bank)
{
//int bank = argv[0]->i;
//int program = argv[1]->i;
- int bank = argv[0]->i & 0xff;
- int program = argv[1]->i & 0xff;
int ch = 0; // TODO: ??
int port = synti->midiPort();
+ //_curBank = bank;
+ //_curProgram = program;
+ synti->_curBankH = 0;
+ synti->_curBankL = bank;
+ synti->_curProgram = program;
+
+ bank &= 0xff;
+ program &= 0xff;
+
//MidiEvent event(0, ch, ME_CONTROLLER, CTRL_PROGRAM, (bank << 8) + program);
if(port != -1)
@@ -2110,31 +2534,32 @@ int DssiSynthIF::oscProgram(lo_arg** argv)
// oscControl
//---------------------------------------------------------
-int DssiSynthIF::oscControl(lo_arg** argv)
+int DssiSynthIF::oscControl(unsigned long port, float value)
{
- int port = argv[0]->i;
- LADSPA_Data value = argv[1]->f;
+ //int port = argv[0]->i;
+ //LADSPA_Data value = argv[1]->f;
#ifdef DSSI_DEBUG
- printf("DssiSynthIF::oscControl received oscControl port:%d val:%f\n", port, value);
+ printf("DssiSynthIF::oscControl received oscControl port:%ld val:%f\n", port, value);
#endif
- //int controlPorts = synth->_controller;
+ //int controlPorts = synth->_controlInPorts;
//if(port >= controlPorts)
- if(port < 0 || port >= synth->rpIdx.size())
+ //if(port < 0 || port >= synth->rpIdx.size())
+ if(port >= synth->rpIdx.size())
{
//fprintf(stderr, "DssiSynthIF::oscControl: port number:%d is out of range of number of ports:%d\n", port, controlPorts);
- fprintf(stderr, "DssiSynthIF::oscControl: port number:%d is out of range of index list size:%d\n", port, synth->rpIdx.size());
+ fprintf(stderr, "DssiSynthIF::oscControl: port number:%ld is out of range of index list size:%d\n", port, synth->rpIdx.size());
return 0;
}
// Convert from DSSI port number to control input port index.
- int cport = synth->rpIdx[port];
+ unsigned long cport = synth->rpIdx[port];
- if(cport == -1)
+ if((int)cport == -1)
{
- fprintf(stderr, "DssiSynthIF::oscControl: port number:%d is not a control input\n", port);
+ fprintf(stderr, "DssiSynthIF::oscControl: port number:%ld is not a control input\n", port);
return 0;
}
@@ -2144,16 +2569,38 @@ int DssiSynthIF::oscControl(lo_arg** argv)
// Hence in response to the call to this oscControl, sent by the native GUI, it is required to that here.
/// controls[cport].val = value;
// DSSI-VST synths however, unlike DSSI synths, DO change their OWN sound in response to their gui controls.
- // AND this function is called !
+ // AND this function is called.
// Despite the descrepency we are STILL required to update the DSSI control port values here
- // because dssi-vst is WAITING FOR A RESPONSE! (A CHANGE in the control port value).
+ // because dssi-vst is WAITING FOR A RESPONSE. (A CHANGE in the control port value).
// It will output something like "...4 events expected..." and count that number down as 4 actual control port value CHANGES
// are done here in response. Normally it says "...0 events expected..." when MusE is the one doing the DSSI control changes.
- // TODO: May need FIFOs on each control(!) so that the control changes get sent one per process cycle!
+ // TODO: (Done) May need FIFOs on each control(!) so that the control changes get sent one per process cycle.
// Observed countdown not actually going to zero upon string of changes.
+ //
+ // NOTE: NOTE: This line in RemoteVSTServer::setParameter(int p, float v) in dssi-vst-server.cpp :
+ //
+ // " if (tv.tv_sec > m_lastGuiComms.tv_sec + 10) "
+ //
+ // explains an observation that after ten seconds, the server automatically clears the expected number to 0.
+ // TODO: Now MusE should forget about all the VST fifo events past ten+ (?) seconds. Add event timestamps...
+ // You can't send any 'new' values until either you a): send all the expected events or b): wait ten seconds.
+ // (Because the server simply ignores the 'expected' messages.)
+ //
+ // Well, at least here are the fifos. Try this ...
+ OscControlFifo* cfifo = _oscif.oscFifo(cport);
+ if(cfifo)
+ {
+ OscControlValue cv;
+ //cv.idx = cport;
+ cv.value = value;
+ if(cfifo->put(cv))
+ {
+ fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%ld\n", cport);
+ }
+ }
- const DSSI_Descriptor* dssi = synth->dssi;
- const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
+ //const DSSI_Descriptor* dssi = synth->dssi;
+ //const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
ciMidiCtl2LadspaPort ip = synth->port2MidiCtlMap.find(cport);
if(ip != synth->port2MidiCtlMap.end())
@@ -2189,6 +2636,7 @@ int DssiSynthIF::oscControl(lo_arg** argv)
return 0;
}
+/*
//---------------------------------------------------------
// oscExiting
//---------------------------------------------------------
@@ -2228,20 +2676,19 @@ int DssiSynthIF::oscExiting(lo_arg**)
if (instance->plugin) {
- /*!!! No, this isn't safe -- plugins deactivated in this way
- would still be included in a run_multiple_synths call unless
- we re-jigged the instance array at the same time -- leave it
- for now
- if (instance->plugin->descriptor->LADSPA_Plugin->deactivate) {
- instance->plugin->descriptor->LADSPA_Plugin->deactivate
- (instanceHandles[instance->number]);
- }
- */
- /* Leave this flag though, as we need it to determine when to exit */
+ // !!! No, this isn't safe -- plugins deactivated in this way
+ // would still be included in a run_multiple_synths call unless
+ // we re-jigged the instance array at the same time -- leave it
+ // for now
+ //if (instance->plugin->descriptor->LADSPA_Plugin->deactivate) {
+ // instance->plugin->descriptor->LADSPA_Plugin->deactivate
+ // (instanceHandles[instance->number]);
+ // }
+ // Leave this flag though, as we need it to determine when to exit
instance->inactive = 1;
}
- /* Do we have any plugins left running? */
+ // Do we have any plugins left running?
for (i = 0; i < instance_count; ++i) {
if (!instances[i].inactive)
@@ -2255,16 +2702,18 @@ int DssiSynthIF::oscExiting(lo_arg**)
#endif
return 0;
}
+*/
//---------------------------------------------------------
// oscMidi
//---------------------------------------------------------
-int DssiSynthIF::oscMidi(lo_arg** argv)
+int DssiSynthIF::oscMidi(int a, int b, int c)
{
- int a = argv[0]->m[1];
- int b = argv[0]->m[2];
- int c = argv[0]->m[3];
+ //int a = argv[0]->m[1];
+ //int b = argv[0]->m[2];
+ //int c = argv[0]->m[3];
+
if (a == ME_NOTEOFF) {
a = ME_NOTEON;
c = 0;
@@ -2302,44 +2751,47 @@ int DssiSynthIF::oscMidi(lo_arg** argv)
// oscConfigure
//---------------------------------------------------------
-int DssiSynthIF::oscConfigure(lo_arg** argv)
+int DssiSynthIF::oscConfigure(const char *key, const char *value)
{
- if (!synth->dssi->configure)
- return 0;
-
- const char *key = (const char *)&argv[0]->s;
- const char *value = (const char *)&argv[1]->s;
+ //const char *key = (const char *)&argv[0]->s;
+ //const char *value = (const char *)&argv[1]->s;
- /* This is pretty much the simplest legal implementation of
- * configure in a DSSI host. */
+ // This is pretty much the simplest legal implementation of
+ // configure in a DSSI host.
- /* The host has the option to remember the set of (key,value)
- * pairs associated with a particular instance, so that if it
- * wants to restore the "same" instance on another occasion it can
- * just call configure() on it for each of those pairs and so
- * restore state without any input from a GUI. Any real-world GUI
- * host will probably want to do that. This host doesn't have any
- * concept of restoring an instance from one run to the next, so
- * we don't bother remembering these at all. */
+ // The host has the option to remember the set of (key,value)
+ // pairs associated with a particular instance, so that if it
+ // wants to restore the "same" instance on another occasion it can
+ // just call configure() on it for each of those pairs and so
+ // restore state without any input from a GUI. Any real-world GUI
+ // host will probably want to do that. This host doesn't have any
+ // concept of restoring an instance from one run to the next, so
+ // we don't bother remembering these at all.
#ifdef DSSI_DEBUG
- printf("DssiSynthIF::oscConfigure synth name:%s key:%s value:%s\n", synti->name().ascii(), key, value);
+ printf("DssiSynthIF::oscConfigure synth name:%s key:%s value:%s\n", synti->name().latin1(), key, value);
#endif
+ // Add or modify the configuration map item.
+ synti->_stringParamMap.set(key, value);
+
if (!strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX,
strlen(DSSI_RESERVED_CONFIGURE_PREFIX))) {
fprintf(stderr, "MusE: OSC: UI for plugin '%s' attempted to use reserved configure key \"%s\", ignoring\n",
//synti->name().toAscii().data(), key);
- synti->name().ascii(), key);
+ synti->name().latin1(), key);
return 0;
}
+ if (!synth->dssi->configure)
+ return 0;
+
char* message = synth->dssi->configure(handle, key, value);
if (message) {
printf("MusE: on configure '%s' '%s', plugin '%s' returned error '%s'\n",
//key, value, synti->name().toAscii().data(), message);
- key, value, synti->name().ascii(), message);
+ key, value, synti->name().latin1(), message);
free(message);
}
@@ -2351,11 +2803,12 @@ int DssiSynthIF::oscConfigure(lo_arg** argv)
// instances[n].ui_osc_configure_path, "ss", key, value);
// }
- /* configure invalidates bank and program information, so
- we should do this again now: */
+ // configure invalidates bank and program information, so
+ // we should do this again now:
queryPrograms();
return 0;
}
+#endif // OSC_SUPPORT
//---------------------------------------------------------
// queryPrograms
@@ -2369,7 +2822,8 @@ void DssiSynthIF::queryPrograms()
}
programs.clear();
- if (!(synth->dssi->get_program && synth->dssi->select_program))
+ //if (!(synth->dssi->get_program && synth->dssi->select_program))
+ if (!synth->dssi->get_program)
return;
for (int i = 0;; ++i) {
@@ -2416,6 +2870,10 @@ const char* DssiSynthIF::getPatchName(int /*chan*/, int prog, MType /*type*/, bo
//void DssiSynthIF::populatePatchPopup(QMenu* menu, int)
void DssiSynthIF::populatePatchPopup(QPopupMenu* menu, int /*ch*/, MType /*type*/, bool /*drum*/)
{
+ // The plugin can change the programs, patches etc.
+ // So make sure we're up to date by calling queryPrograms.
+ queryPrograms();
+
menu->clear();
for (std::vector<DSSI_Program_Descriptor>::const_iterator i = programs.begin();
@@ -2432,7 +2890,7 @@ void DssiSynthIF::populatePatchPopup(QPopupMenu* menu, int /*ch*/, MType /*type*
int DssiSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval)
{
- int controlPorts = synth->_controller;
+ int controlPorts = synth->_controlInPorts;
if(id >= controlPorts)
//if(id >= midiCtl2PortMap.size())
return 0;
diff --git a/muse/muse/dssihost.h b/muse/muse/dssihost.h
index 526d793f..deaa87b9 100644
--- a/muse/muse/dssihost.h
+++ b/muse/muse/dssihost.h
@@ -21,16 +21,29 @@
#ifndef __DSSIHOST_H__
#define __DSSIHOST_H__
+#include "config.h"
+
#include <vector>
+#include <map>
+#include <string>
+#ifdef OSC_SUPPORT
#include <lo/lo.h>
+#include "osc.h"
+#endif
+
#include <dssi.h>
#include <alsa/asoundlib.h>
#include "midictrl.h"
#include "synth.h"
-#include "plugin.h"
+#include "stringparam.h"
+//#include "plugin.h"
+
+#define DSSI_PARAMSAVE_VERSION_MAJOR 0
+#define DSSI_PARAMSAVE_VERSION_MINOR 1
+
struct _DSSI;
class DssiPluginIF;
@@ -48,31 +61,34 @@ class DssiSynth : public Synth {
void* handle;
const DSSI_Descriptor* dssi;
DSSI_Descriptor_Function df;
- std::vector<int> pIdx; // Control input index to port number.
- std::vector<int> opIdx; // Control output index to port number. This is sometimes a latency port and...?
- std::vector<int> iIdx; // Audio input index to port number.
- std::vector<int> oIdx; // Audio output index to port number.
- std::vector<bool> iUsedIdx; // This is for audio input ports during process to tell whether an audio input port was used by any input routes.
- int _inports, _outports, _controller, _controllerOut;
- std::vector<int> rpIdx; // Port number to control input index. Item is -1 if it's not a control input.
+ unsigned long _portCount, _inports, _outports, _controlInPorts, _controlOutPorts;
+ std::vector<unsigned long> pIdx; // Control input index to port number.
+ std::vector<unsigned long> opIdx; // Control output index to port number. This is sometimes a latency port and...?
+ std::vector<unsigned long> iIdx; // Audio input index to port number.
+ std::vector<unsigned long> oIdx; // Audio output index to port number.
+ std::vector<bool> iUsedIdx; // During process, tells whether an audio input port was used by any input routes.
+ std::vector<unsigned long> rpIdx; // Port number to control input index. Item is -1 if it's not a control input.
+ //unsigned long* rpIdx;
MidiCtl2LadspaPortMap midiCtl2PortMap; // Maps midi controller numbers to DSSI port numbers.
MidiCtl2LadspaPortMap port2MidiCtlMap; // Maps DSSI port numbers to midi controller numbers.
bool _hasGui;
+ bool _inPlaceCapable;
public:
//DssiSynth(const QFileInfo* fi, QString l) : Synth(fi, l) {
//DssiSynth(const QFileInfo& fi, QString l) : Synth(fi, l) {
- DssiSynth(const QFileInfo& fi, QString label, QString descr, QString maker, QString ver) :
- Synth(fi, label, descr, maker, ver) {
- df = 0;
- handle = 0;
- dssi = 0;
- _hasGui = false;
- }
- virtual ~DssiSynth() {
- //delete label;
- }
- virtual void incInstances(int val);
+ //DssiSynth(const QFileInfo& fi, QString label, QString descr, QString maker, QString ver) :
+ // Synth(fi, label, descr, maker, ver) {
+ // rpIdx = 0;
+ // df = 0;
+ // handle = 0;
+ // dssi = 0;
+ // _hasGui = false;
+ // }
+ //DssiSynth(const QFileInfo& fi, QString label, QString descr, QString maker, QString ver);
+ DssiSynth(const QFileInfo&, const DSSI_Descriptor*);
+ virtual ~DssiSynth();
+ virtual void incInstances(int);
//virtual void* instantiate();
@@ -80,7 +96,13 @@ class DssiSynth : public Synth {
//virtual SynthIF* createSIF();
friend class DssiSynthIF;
- float defaultValue(int);
+ //float defaultValue(int); // Not required
+ unsigned long inPorts() const { return _inports; }
+ unsigned long outPorts() const { return _outports; }
+ unsigned long inControls() const { return _controlInPorts; }
+ unsigned long outControls() const { return _controlOutPorts; }
+
+ unsigned long inControlPortIdx(unsigned long i) { return pIdx[i]; }
};
//---------------------------------------------------------
@@ -90,7 +112,7 @@ class DssiSynth : public Synth {
class DssiSynthIF : public SynthIF
{
- bool _guiVisible;
+ //bool _guiVisible;
DssiSynth* synth;
LADSPA_Handle handle;
@@ -98,12 +120,19 @@ class DssiSynthIF : public SynthIF
Port* controls;
Port* controlsOut;
- void* uiTarget;
- char* uiOscShowPath;
- char* uiOscControlPath;
- char* uiOscConfigurePath;
- char* uiOscProgramPath;
- char* uiOscPath;
+ //unsigned long _curBank;
+ //unsigned long _curProgram;
+
+ #ifdef OSC_SUPPORT
+ OscDssiIF _oscif;
+ #endif
+
+ //void* uiTarget;
+ //char* uiOscShowPath;
+ //char* uiOscControlPath;
+ //char* uiOscConfigurePath;
+ //char* uiOscProgramPath;
+ //char* uiOscPath;
std::vector<DSSI_Program_Descriptor> programs;
void queryPrograms();
@@ -114,7 +143,7 @@ class DssiSynthIF : public SynthIF
protected:
//int guiPid;
- QProcess* guiQProc;
+ //QProcess* guiQProc;
public:
DssiSynthIF(SynthI* s);
@@ -122,7 +151,11 @@ class DssiSynthIF : public SynthIF
virtual ~DssiSynthIF();
- virtual bool startGui();
+ virtual DssiSynth* dssiSynth() { return synth; }
+ virtual SynthI* dssiSynthI() { return synti; }
+
+ virtual bool initGui();
+ virtual void guiHeartBeat();
virtual bool guiVisible() const;
virtual void showGui(bool v);
virtual bool hasGui() const { return synth->_hasGui; }
@@ -159,19 +192,34 @@ class DssiSynthIF : public SynthIF
//virtual void write(Xml& xml) const;
virtual void write(int level, Xml& xml) const;
- virtual void setParameter(int idx, float value);
+ virtual float getParameter(unsigned long /*idx*/);
+ virtual void setParameter(unsigned long /*idx*/, float /*value*/);
//virtual int getControllerInfo(int, const char**, int*, int*, int*) { return 0; }
virtual int getControllerInfo(int, const char**, int*, int*, int*, int*);
bool init(DssiSynth* s);
- int oscUpdate(lo_arg**);
+ //StringParamMap& stringParameters() { return synti->stringParameters(); }
+
+ #ifdef OSC_SUPPORT
+ OscDssiIF& oscIF() { return _oscif; }
+ /*
int oscProgram(lo_arg**);
int oscControl(lo_arg**);
- int oscExiting(lo_arg**);
int oscMidi(lo_arg**);
int oscConfigure(lo_arg**);
+ int oscUpdate(lo_arg**);
+ //int oscExiting(lo_arg**);
+ */
+
+ int oscProgram(unsigned long /*prog*/, unsigned long /*bank*/);
+ int oscControl(unsigned long /*dssiPort*/, float /*val*/);
+ int oscMidi(int /*a*/, int /*b*/, int /*c*/);
+ int oscConfigure(const char */*key*/, const char */*val*/);
+ int oscUpdate();
+ //int oscExiting();
+ #endif
friend class DssiSynth;
};
diff --git a/muse/muse/mixer/rack.cpp b/muse/muse/mixer/rack.cpp
index e94acb97..30b3ff0d 100644
--- a/muse/muse/mixer/rack.cpp
+++ b/muse/muse/mixer/rack.cpp
@@ -24,6 +24,7 @@
#include "gconfig.h"
#include "plugin.h"
#include "filedialog.h"
+#include "config.h"
//---------------------------------------------------------
// class RackSlot
@@ -149,16 +150,19 @@ void EffectRack::menuRequested(QListBoxItem* it, const QPoint& pt)
mute = pipe->isOn(idx);
}
- enum { NEW, CHANGE, UP, DOWN, REMOVE, BYPASS, SHOW, SAVE };
+ //enum { NEW, CHANGE, UP, DOWN, REMOVE, BYPASS, SHOW, SAVE };
+ enum { NEW, CHANGE, UP, DOWN, REMOVE, BYPASS, SHOW, SHOW_NATIVE, SAVE };
QPopupMenu* menu = new QPopupMenu;
menu->insertItem(QIconSet(*upIcon), tr("move up"), UP, UP);
menu->insertItem(QIconSet(*downIcon), tr("move down"), DOWN, DOWN);
menu->insertItem(tr("remove"), REMOVE, REMOVE);
menu->insertItem(tr("bypass"), BYPASS, BYPASS);
menu->insertItem(tr("show gui"), SHOW, SHOW);
+ menu->insertItem(tr("show native gui"), SHOW_NATIVE, SHOW_NATIVE);
menu->setItemChecked(BYPASS, !pipe->isOn(idx));
menu->setItemChecked(SHOW, pipe->guiVisible(idx));
+ menu->setItemChecked(SHOW_NATIVE, pipe->nativeGuiVisible(idx));
if (pipe->empty(idx)) {
menu->insertItem(tr("new"), NEW, NEW);
@@ -167,6 +171,7 @@ void EffectRack::menuRequested(QListBoxItem* it, const QPoint& pt)
menu->setItemEnabled(REMOVE, false);
menu->setItemEnabled(BYPASS, false);
menu->setItemEnabled(SHOW, false);
+ menu->setItemEnabled(SHOW_NATIVE, false);
menu->setItemEnabled(SAVE, false);
}
else {
@@ -176,8 +181,14 @@ void EffectRack::menuRequested(QListBoxItem* it, const QPoint& pt)
menu->setItemEnabled(UP, false);
if (idx == (PipelineDepth-1))
menu->setItemEnabled(DOWN, false);
+ if(!pipe->isDssiPlugin(idx))
+ menu->setItemEnabled(SHOW_NATIVE, false);
}
+ #ifndef OSC_SUPPORT
+ menu->setItemEnabled(SHOW_NATIVE, false);
+ #endif
+
int sel = menu->exec(pt, 1);
delete menu;
if (sel == -1)
@@ -230,6 +241,12 @@ void EffectRack::menuRequested(QListBoxItem* it, const QPoint& pt)
pipe->showGui(idx, flag);
break;
}
+ case SHOW_NATIVE:
+ {
+ bool flag = !pipe->nativeGuiVisible(idx);
+ pipe->showNativeGui(idx, flag);
+ break;
+ }
case UP:
if (idx > 0) {
setCurrentItem(idx-1);
diff --git a/muse/muse/plugin.cpp b/muse/muse/plugin.cpp
index ac06c5ab..4d6113ff 100644
--- a/muse/muse/plugin.cpp
+++ b/muse/muse/plugin.cpp
@@ -49,7 +49,10 @@
#include "audio.h"
#include "al/dsp.h"
-#define PLUGIN_DEBUGIN 0
+#include "config.h"
+
+// Turn on debugging messages.
+//#define PLUGIN_DEBUGIN
PluginList plugins;
@@ -92,13 +95,15 @@ bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctl
//bool isint = desc & LADSPA_HINT_INTEGER;
MidiController::ControllerType t = midiControllerType(ctlnum);
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: ctlnum:%d ladspa port:%d has default?:%d default:%f\n", ctlnum, port, hasdef, fdef);
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: ctlnum:%d ladspa port:%d has default?:%d default:%f\n", ctlnum, port, hasdef, fdef);
+ #endif
if(desc & LADSPA_HINT_TOGGLED)
{
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: has LADSPA_HINT_TOGGLED\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: has LADSPA_HINT_TOGGLED\n");
+ #endif
*min = 0;
*max = 1;
@@ -109,16 +114,18 @@ bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctl
float m = 1.0;
if(desc & LADSPA_HINT_SAMPLE_RATE)
{
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: has LADSPA_HINT_SAMPLE_RATE\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: has LADSPA_HINT_SAMPLE_RATE\n");
+ #endif
m = float(sampleRate);
}
if(desc & LADSPA_HINT_BOUNDED_BELOW)
{
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: has LADSPA_HINT_BOUNDED_BELOW\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: has LADSPA_HINT_BOUNDED_BELOW\n");
+ #endif
fmin = range.LowerBound * m;
}
@@ -127,8 +134,9 @@ bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctl
if(desc & LADSPA_HINT_BOUNDED_ABOVE)
{
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: has LADSPA_HINT_BOUNDED_ABOVE\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: has LADSPA_HINT_BOUNDED_ABOVE\n");
+ #endif
fmax = range.UpperBound * m;
}
@@ -143,8 +151,9 @@ bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctl
int ctlmn = 0;
int ctlmx = 127;
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: port min:%f max:%f \n", fmin, fmax);
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: port min:%f max:%f \n", fmin, fmax);
+ #endif
//bool isneg = (fmin < 0.0);
bool isneg = (imin < 0);
@@ -200,8 +209,9 @@ bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctl
// Is it an integer control?
if(desc & LADSPA_HINT_INTEGER)
{
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: has LADSPA_HINT_INTEGER\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: has LADSPA_HINT_INTEGER\n");
+ #endif
// If the upper or lower limit is beyond the controller limits, just scale the whole range to fit.
// We could get fancy by scaling only the negative or positive domain, or each one separately, but no...
@@ -247,8 +257,9 @@ bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctl
*def = (int)lrint(fdef) + bias;
- if(PLUGIN_DEBUGIN)
- printf("ladspa2MidiControlValues: setting default:%d\n", *def);
+ #ifdef PLUGIN_DEBUGIN
+ printf("ladspa2MidiControlValues: setting default:%d\n", *def);
+ #endif
return hasdef;
}
@@ -274,22 +285,25 @@ float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, in
//bool isint = desc & LADSPA_HINT_INTEGER;
MidiController::ControllerType t = midiControllerType(ctlnum);
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: ctlnum:%d ladspa port:%d val:%d\n", ctlnum, port, val);
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: ctlnum:%d ladspa port:%d val:%d\n", ctlnum, port, val);
+ #endif
float m = 1.0;
if(desc & LADSPA_HINT_SAMPLE_RATE)
{
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: has LADSPA_HINT_SAMPLE_RATE\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: has LADSPA_HINT_SAMPLE_RATE\n");
+ #endif
m = float(sampleRate);
}
if(desc & LADSPA_HINT_BOUNDED_BELOW)
{
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: has LADSPA_HINT_BOUNDED_BELOW\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: has LADSPA_HINT_BOUNDED_BELOW\n");
+ #endif
fmin = range.LowerBound * m;
}
@@ -298,8 +312,9 @@ float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, in
if(desc & LADSPA_HINT_BOUNDED_ABOVE)
{
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: has LADSPA_HINT_BOUNDED_ABOVE\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: has LADSPA_HINT_BOUNDED_ABOVE\n");
+ #endif
fmax = range.UpperBound * m;
}
@@ -313,8 +328,9 @@ float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, in
if(desc & LADSPA_HINT_TOGGLED)
{
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: has LADSPA_HINT_TOGGLED\n");
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: has LADSPA_HINT_TOGGLED\n");
+ #endif
if(val > 0)
return fmax;
@@ -325,8 +341,9 @@ float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, in
int ctlmn = 0;
int ctlmx = 127;
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: port min:%f max:%f \n", fmin, fmax);
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: port min:%f max:%f \n", fmin, fmax);
+ #endif
//bool isneg = (fmin < 0.0);
bool isneg = (imin < 0);
@@ -391,9 +408,10 @@ float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, in
ret = fmin;
if(ret > fmax)
ret = fmax;
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: has LADSPA_HINT_INTEGER returning:%f\n", ret);
-
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: has LADSPA_HINT_INTEGER returning:%f\n", ret);
+ #endif
+
return ret;
}
@@ -410,8 +428,9 @@ float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, in
float ret = normval * frng + fmin;
- if(PLUGIN_DEBUGIN)
- printf("midi2LadspaValue: float returning:%f\n", ret);
+ #ifdef PLUGIN_DEBUGIN
+ printf("midi2LadspaValue: float returning:%f\n", ret);
+ #endif
return ret;
}
@@ -558,55 +577,278 @@ void ladspaControlRange(const LADSPA_Descriptor* plugin, int i, float* min, floa
// Plugin
//---------------------------------------------------------
-Plugin::Plugin(QFileInfo* f,
- LADSPA_Descriptor_Function df, const LADSPA_Descriptor* d, bool ip)
- : fi(*f), ladspa(df), plugin(d)
+Plugin::Plugin(QFileInfo* f, const LADSPA_Descriptor* d, bool isDssi)
+{
+ _isDssi = isDssi;
+ #ifdef DSSI_SUPPORT
+ dssi_descr = NULL;
+ #endif
+
+ fi = *f;
+ plugin = NULL;
+ ladspa = NULL;
+ _handle = 0;
+ _references = 0;
+ _instNo = 0;
+ _label = QString(d->Label);
+ _name = QString(d->Name);
+ _uniqueID = d->UniqueID;
+ _maker = QString(d->Maker);
+ _copyright = QString(d->Copyright);
+
+ _portCount = d->PortCount;
+ //_portDescriptors = 0;
+ //if(_portCount)
+ // _portDescriptors = new LADSPA_PortDescriptor[_portCount];
+
+
+ _inports = 0;
+ _outports = 0;
+ _controlInPorts = 0;
+ _controlOutPorts = 0;
+ for(unsigned long k = 0; k < _portCount; ++k)
+ {
+ LADSPA_PortDescriptor pd = d->PortDescriptors[k];
+ //_portDescriptors[k] = pd;
+ if(pd & LADSPA_PORT_AUDIO)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++_inports;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++_outports;
+ }
+ else
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++_controlInPorts;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++_controlOutPorts;
+ }
+ }
+
+ _inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(d->Properties);
+
+ // By T356. Blacklist vst plugins in-place configurable for now. At one point they
+ // were working with in-place here, but not now, and RJ also reported they weren't working.
+ // Fixes problem with vst plugins not working or feeding back loudly.
+ // I can only think of two things that made them stop working:
+ // 1): I switched back from Jack-2 to Jack-1
+ // 2): I changed winecfg audio to use Jack instead of ALSA.
+ // Will test later...
+ // Possibly the first one because under Mandriva2007.1 (Jack-1), no matter how hard I tried,
+ // the same problem existed. It may have been when using Jack-2 with Mandriva2009 that they worked.
+ // Apparently the plugins are lying about their in-place capability.
+ // Quote:
+ /* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin
+ may cease to work correctly if the host elects to use the same data
+ location for both input and output (see connect_port()). This
+ should be avoided as enabling this flag makes it impossible for
+ hosts to use the plugin to process audio `in-place.' */
+ // Examination of all my ladspa and vst synths and effects plugins showed only one -
+ // EnsembleLite (EnsLite VST) has the flag set, but it is a vst synth and is not involved here!
+ // Yet many (all?) ladspa vst effect plugins exhibit this problem.
+ // Changed by Tim. p3.3.14
+ if ((_inports != _outports) || (fi.baseName(true) == QString("dssi-vst") && !config.vstInPlace))
+ _inPlaceCapable = false;
+}
+
+Plugin::~Plugin()
+{
+ //if(_portDescriptors)
+ // delete[] _portDescriptors;
+}
+
+//---------------------------------------------------------
+// incReferences
+//---------------------------------------------------------
+
+int Plugin::incReferences(int val)
+{
+ int newref = _references + val;
+
+ if(newref == 0)
+ {
+ _references = 0;
+ if(_handle)
+ {
+ #ifdef PLUGIN_DEBUGIN
+ fprintf(stderr, "Plugin::incReferences no more instances, closing library\n");
+ #endif
+
+ dlclose(_handle);
+ }
+
+ _handle = 0;
+ ladspa = NULL;
+ plugin = NULL;
+ rpIdx.clear();
+
+ #ifdef DSSI_SUPPORT
+ dssi_descr = NULL;
+ #endif
+
+ return 0;
+ }
+
+ //if(_references == 0)
+ if(_handle == 0)
+ {
+ //_references = 0;
+ _handle = dlopen(fi.filePath().latin1(), RTLD_NOW);
+ //handle = dlopen(fi.absFilePath().latin1(), RTLD_NOW);
+
+ if(_handle == 0)
+ {
+ fprintf(stderr, "Plugin::incReferences dlopen(%s) failed: %s\n",
+ fi.filePath().latin1(), dlerror());
+ //fi.absFilePath().latin1(), dlerror());
+ return 0;
+ }
+
+ #ifdef DSSI_SUPPORT
+ DSSI_Descriptor_Function dssi = (DSSI_Descriptor_Function)dlsym(_handle, "dssi_descriptor");
+ if(dssi)
+ {
+ const DSSI_Descriptor* descr;
+ for(int i = 0;; ++i)
+ {
+ descr = dssi(i);
+ if(descr == NULL)
+ break;
+
+ QString label(descr->LADSPA_Plugin->Label);
+ // Listing effect plugins only while excluding synths:
+ // Do exactly what dssi-vst.cpp does for listing ladspa plugins.
+ //if(label == _name &&
+ if(label == _label &&
+ !descr->run_synth &&
+ !descr->run_synth_adding &&
+ !descr->run_multiple_synths &&
+ !descr->run_multiple_synths_adding)
+ {
+ _isDssi = true;
+ ladspa = NULL;
+ dssi_descr = descr;
+ plugin = descr->LADSPA_Plugin;
+ break;
+ }
+ }
+ }
+ else
+ #endif // DSSI_SUPPORT
+ {
+ LADSPA_Descriptor_Function ladspadf = (LADSPA_Descriptor_Function)dlsym(_handle, "ladspa_descriptor");
+ if(ladspadf)
{
- _inPlaceCapable = ip;
+ const LADSPA_Descriptor* descr;
+ for(int i = 0;; ++i)
+ {
+ descr = ladspadf(i);
+ if(descr == NULL)
+ break;
+
+ QString label(descr->Label);
+ //if(label == _name)
+ if(label == _label)
+ {
+ _isDssi = false;
+ ladspa = ladspadf;
+ plugin = descr;
+
+ #ifdef DSSI_SUPPORT
+ dssi_descr = NULL;
+ #endif
+
+ break;
+ }
+ }
+ }
+ }
+
+ if(plugin != NULL)
+ {
+ //_instNo = 0;
+ _name = QString(plugin->Name);
+ _uniqueID = plugin->UniqueID;
+ _maker = QString(plugin->Maker);
+ _copyright = QString(plugin->Copyright);
+
+ //if(_portDescriptors)
+ // delete[] _portDescriptors;
+ //_portDescriptors = 0;
+ _portCount = plugin->PortCount;
+ //if(_portCount)
+ // _portDescriptors = new LADSPA_PortDescriptor[_portCount];
+
_inports = 0;
_outports = 0;
- for (unsigned k = 0; k < d->PortCount; ++k) {
- LADSPA_PortDescriptor pd = d->PortDescriptors[k];
- if (pd & LADSPA_PORT_CONTROL)
- continue;
- if (pd & LADSPA_PORT_INPUT)
- ++_inports;
- else
- ++_outports;
- }
+ _controlInPorts = 0;
+ _controlOutPorts = 0;
+ for(unsigned long k = 0; k < _portCount; ++k)
+ {
+ LADSPA_PortDescriptor pd = plugin->PortDescriptors[k];
+ //_portDescriptors[k] = pd;
+ if(pd & LADSPA_PORT_AUDIO)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++_inports;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++_outports;
+
+ rpIdx.push_back((unsigned long)-1);
+ }
+ else
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ {
+ rpIdx.push_back(_controlInPorts);
+ ++_controlInPorts;
+ }
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ {
+ rpIdx.push_back((unsigned long)-1);
+ ++_controlOutPorts;
+ }
+ }
+ }
- // By T356. Blacklist vst plugins in-place configurable for now. At one point they
- // were working with in-place here, but not now, and RJ also reported they weren't working.
- // Fixes problem with vst plugins not working or feeding back loudly.
- // I can only think of two things that made them stop working:
- // 1): I switched back from Jack-2 to Jack-1
- // 2): I changed winecfg audio to use Jack instead of ALSA.
- // Will test later...
- // Possibly the first one because under Mandriva2007.1 (Jack-1), no matter how hard I tried,
- // the same problem existed. It may have been when using Jack-2 with Mandriva2009 that they worked.
- // Apparently the plugins are lying about their in-place capability.
- // Quote:
- /* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin
- may cease to work correctly if the host elects to use the same data
- location for both input and output (see connect_port()). This
- should be avoided as enabling this flag makes it impossible for
- hosts to use the plugin to process audio `in-place.' */
- // Examination of all my ladspa and vst synths and effects plugins showed only one -
- // EnsembleLite (EnsLite VST) has the flag set, but it is a vst synth and is not involved here!
- // Yet many (all?) ladspa vst effect plugins exhibit this problem.
- // Changed by Tim. p3.3.14
- if ((_inports != _outports) || (f->baseName(true) == QString("dssi-vst") && !config.vstInPlace))
- _inPlaceCapable = false;
+ _inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(plugin->Properties);
- _references = 0;
- _instNo = 0;
- }
+ // Blacklist vst plugins in-place configurable for now.
+ if ((_inports != _outports) || (fi.baseName(true) == QString("dssi-vst") && !config.vstInPlace))
+ _inPlaceCapable = false;
+ }
+ }
+
+ if(plugin == NULL)
+ {
+ dlclose(_handle);
+ _handle = 0;
+ _references = 0;
+ fprintf(stderr, "Plugin::incReferences Error: %s no plugin!\n", fi.filePath().latin1());
+ return 0;
+ }
+
+ _references = newref;
+
+ //QString guiPath(info.dirPath() + "/" + info.baseName());
+ //QDir guiDir(guiPath, "*", QDir::Unsorted, QDir::Files);
+ //_hasGui = guiDir.exists();
+
+ return _references;
+}
//---------------------------------------------------------
// range
//---------------------------------------------------------
-void Plugin::range(int i, float* min, float* max) const
+void Plugin::range(unsigned long i, float* min, float* max) const
{
LADSPA_PortRangeHint range = plugin->PortRangeHints[i];
LADSPA_PortRangeHintDescriptor desc = range.HintDescriptor;
@@ -633,7 +875,7 @@ void Plugin::range(int i, float* min, float* max) const
// defaultValue
//---------------------------------------------------------
-double Plugin::defaultValue(unsigned int port) const
+double Plugin::defaultValue(unsigned long port) const
{
if(port >= plugin->PortCount)
return 0.0;
@@ -680,59 +922,91 @@ double Plugin::defaultValue(unsigned int port) const
//---------------------------------------------------------
static void loadPluginLib(QFileInfo* fi)
- {
- void* handle = dlopen(fi->filePath().ascii(), RTLD_NOW);
- if (handle == 0) {
- fprintf(stderr, "dlopen(%s) failed: %s\n",
- fi->filePath().ascii(), dlerror());
- return;
- }
- LADSPA_Descriptor_Function ladspa = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor");
-
- if (!ladspa) {
- const char *txt = dlerror();
- if (txt) {
- fprintf(stderr,
- "Unable to find ladspa_descriptor() function in plugin "
- "library file \"%s\": %s.\n"
- "Are you sure this is a LADSPA plugin file?\n",
- fi->filePath().ascii(),
- txt);
- }
- dlclose(handle);
- return;
- }
- const LADSPA_Descriptor* descr;
- for (int i = 0;; ++i) {
- descr = ladspa(i);
- if (descr == NULL)
- break;
-
- // Make sure it doesn't already exist.
- if(plugins.find(fi->baseName(true), QString(descr->Label)) != 0)
- continue;
-
- LADSPA_Properties properties = descr->Properties;
-
- /*
- int ai = 0;
- int ao = 0;
- for (unsigned k = 0; k < descr->PortCount; ++k) {
- LADSPA_PortDescriptor pd = descr->PortDescriptors[k];
- if (pd & LADSPA_PORT_CONTROL)
- continue;
- if (pd & LADSPA_PORT_INPUT)
- ++ai;
- else
- ++ao;
- }
- */
-
- bool inPlaceBroken = LADSPA_IS_INPLACE_BROKEN(properties);
-
- plugins.add(fi, ladspa, descr, !inPlaceBroken);
- }
+{
+ void* handle = dlopen(fi->filePath().ascii(), RTLD_NOW);
+ if (handle == 0) {
+ fprintf(stderr, "dlopen(%s) failed: %s\n",
+ fi->filePath().ascii(), dlerror());
+ return;
+ }
+
+ #ifdef DSSI_SUPPORT
+ DSSI_Descriptor_Function dssi = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor");
+ if(dssi)
+ {
+ const DSSI_Descriptor* descr;
+ for (int i = 0;; ++i)
+ {
+ descr = dssi(i);
+ if (descr == 0)
+ break;
+
+ // Listing effect plugins only while excluding synths:
+ // Do exactly what dssi-vst.cpp does for listing ladspa plugins.
+ if(!descr->run_synth &&
+ !descr->run_synth_adding &&
+ !descr->run_multiple_synths &&
+ !descr->run_multiple_synths_adding)
+ {
+ // Make sure it doesn't already exist.
+ if(plugins.find(fi->baseName(true), QString(descr->LADSPA_Plugin->Label)) != 0)
+ continue;
+
+ #ifdef PLUGIN_DEBUGIN
+ fprintf(stderr, "loadPluginLib: dssi effect name:%s inPlaceBroken:%d\n", descr->LADSPA_Plugin->Name, LADSPA_IS_INPLACE_BROKEN(descr->LADSPA_Plugin->Properties));
+ #endif
+
+ //LADSPA_Properties properties = descr->LADSPA_Plugin->Properties;
+ //bool inPlaceBroken = LADSPA_IS_INPLACE_BROKEN(properties);
+ //plugins.add(fi, descr, !inPlaceBroken);
+ plugins.add(fi, descr->LADSPA_Plugin, true);
}
+ }
+ }
+ else
+ #endif
+ {
+ LADSPA_Descriptor_Function ladspa = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor");
+ if(!ladspa)
+ {
+ const char *txt = dlerror();
+ if(txt)
+ {
+ fprintf(stderr,
+ "Unable to find ladspa_descriptor() function in plugin "
+ "library file \"%s\": %s.\n"
+ "Are you sure this is a LADSPA plugin file?\n",
+ fi->filePath().ascii(),
+ txt);
+ }
+ dlclose(handle);
+ return;
+ }
+
+ const LADSPA_Descriptor* descr;
+ for (int i = 0;; ++i)
+ {
+ descr = ladspa(i);
+ if (descr == NULL)
+ break;
+
+ // Make sure it doesn't already exist.
+ if(plugins.find(fi->baseName(true), QString(descr->Label)) != 0)
+ continue;
+
+ #ifdef PLUGIN_DEBUGIN
+ fprintf(stderr, "loadPluginLib: ladspa effect name:%s inPlaceBroken:%d\n", descr->Name, LADSPA_IS_INPLACE_BROKEN(descr->Properties));
+ #endif
+
+ //LADSPA_Properties properties = descr->Properties;
+ //bool inPlaceBroken = LADSPA_IS_INPLACE_BROKEN(properties);
+ //plugins.add(fi, ladspa, descr, !inPlaceBroken);
+ plugins.add(fi, descr);
+ }
+ }
+
+ dlclose(handle);
+}
//---------------------------------------------------------
// loadPluginDir
@@ -762,11 +1036,38 @@ void initPlugins()
{
loadPluginDir(museGlobalLib + QString("/plugins"));
+ const char* p = 0;
+
+ // Take care of DSSI plugins first...
+ #ifdef DSSI_SUPPORT
+ const char* dssiPath = getenv("DSSI_PATH");
+ if (dssiPath == 0)
+ dssiPath = "/usr/local/lib64/dssi:/usr/lib64/dssi:/usr/local/lib/dssi:/usr/lib/dssi";
+ p = dssiPath;
+ while (*p != '\0') {
+ const char* pe = p;
+ while (*pe != ':' && *pe != '\0')
+ pe++;
+
+ int n = pe - p;
+ if (n) {
+ char* buffer = new char[n + 1];
+ strncpy(buffer, p, n);
+ buffer[n] = '\0';
+ loadPluginDir(QString(buffer));
+ delete[] buffer;
+ }
+ p = pe;
+ if (*p == ':')
+ p++;
+ }
+ #endif
+
+ // Now do LADSPA plugins...
const char* ladspaPath = getenv("LADSPA_PATH");
if (ladspaPath == 0)
ladspaPath = "/usr/local/lib64/ladspa:/usr/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib/ladspa";
-
- const char* p = ladspaPath;
+ p = ladspaPath;
while (*p != '\0') {
const char* pe = p;
while (*pe != ':' && *pe != '\0')
@@ -972,6 +1273,19 @@ void Pipeline::move(int idx, bool up)
}
//---------------------------------------------------------
+// isDssiPlugin
+//---------------------------------------------------------
+
+bool Pipeline::isDssiPlugin(int idx) const
+{
+ PluginI* p = (*this)[idx];
+ if(p)
+ return p->isDssiPlugin();
+
+ return false;
+}
+
+//---------------------------------------------------------
// showGui
//---------------------------------------------------------
@@ -983,6 +1297,19 @@ void Pipeline::showGui(int idx, bool flag)
}
//---------------------------------------------------------
+// showNativeGui
+//---------------------------------------------------------
+
+void Pipeline::showNativeGui(int idx, bool flag)
+ {
+ #ifdef OSC_SUPPORT
+ PluginI* p = (*this)[idx];
+ if (p)
+ p->oscIF().oscShowGui(flag);
+ #endif
+ }
+
+//---------------------------------------------------------
// deleteGui
//---------------------------------------------------------
@@ -1018,6 +1345,18 @@ bool Pipeline::guiVisible(int idx)
}
//---------------------------------------------------------
+// nativeGuiVisible
+//---------------------------------------------------------
+
+bool Pipeline::nativeGuiVisible(int idx)
+ {
+ PluginI* p = (*this)[idx];
+ if (p)
+ return p->nativeGuiVisible();
+ return false;
+ }
+
+//---------------------------------------------------------
// apply
//---------------------------------------------------------
@@ -1078,16 +1417,19 @@ void PluginI::init()
handle = 0;
controls = 0;
controlsOut = 0;
+ controlPorts = 0;
controlOutPorts = 0;
_gui = 0;
_on = true;
initControlValues = false;
+ _showNativeGuiPending = false;
}
PluginI::PluginI()
{
_id = -1;
_track = 0;
+
init();
}
@@ -1104,11 +1446,11 @@ PluginI::~PluginI()
if (_gui)
delete _gui;
if (controlsOut)
- delete controlsOut;
+ delete[] controlsOut;
if (controls)
- delete controls;
+ delete[] controls;
if (handle)
- delete handle;
+ delete[] handle;
}
//---------------------------------------------------------
@@ -1144,7 +1486,7 @@ CtrlValueType PluginI::valueType() const
//---------------------------------------------------------
void PluginI::setChannels(int c)
- {
+{
if (channel == c)
return;
int ni = c / _plugin->outports();
@@ -1156,20 +1498,21 @@ void PluginI::setChannels(int c)
// remove old instances:
deactivate();
- delete handle;
+ delete[] handle;
instances = ni;
handle = new LADSPA_Handle[instances];
for (int i = 0; i < instances; ++i) {
handle[i] = _plugin->instantiate();
- if (handle[i] == 0) {
+ if (handle[i] == NULL) {
printf("cannot instantiate instance %d\n", i);
return;
}
}
+
int curPort = 0;
int curOutPort = 0;
- int ports = _plugin->ports();
- for (int k = 0; k < ports; ++k)
+ unsigned long ports = _plugin->ports();
+ for (unsigned long k = 0; k < ports; ++k)
{
LADSPA_PortDescriptor pd = _plugin->portd(k);
if (pd & LADSPA_PORT_CONTROL)
@@ -1191,8 +1534,9 @@ void PluginI::setChannels(int c)
}
}
}
+
activate();
- }
+}
//---------------------------------------------------------
// defaultValue
@@ -1207,6 +1551,22 @@ double PluginI::defaultValue(unsigned int param) const
return _plugin->defaultValue(controls[param].idx);
}
+LADSPA_Handle Plugin::instantiate()
+{
+ LADSPA_Handle h = plugin->instantiate(plugin, sampleRate);
+ if(h == NULL)
+ {
+ fprintf(stderr, "Plugin::instantiate() Error: plugin:%s instantiate failed!\n", plugin->Label);
+ return NULL;
+ }
+
+ //QString guiPath(info.dirPath() + "/" + info.baseName());
+ //QDir guiDir(guiPath, "*", QDir::Unsorted, QDir::Files);
+ //_hasGui = guiDir.exists();
+
+ return h;
+}
+
//---------------------------------------------------------
// initPluginInstance
// return true on error
@@ -1215,96 +1575,107 @@ double PluginI::defaultValue(unsigned int param) const
bool PluginI::initPluginInstance(Plugin* plug, int c)
{
channel = c;
- if (plug == 0) {
- printf("initPluginInstance: zero plugin\n");
- return true;
- }
+ if(plug == 0)
+ {
+ printf("initPluginInstance: zero plugin\n");
+ return true;
+ }
_plugin = plug;
+
_plugin->incReferences(1);
+ #ifdef OSC_SUPPORT
+ _oscif.oscSetPluginI(this);
+ #endif
+
QString inst("-" + QString::number(_plugin->instNo()));
_name = _plugin->name() + inst;
_label = _plugin->label() + inst;
instances = channel/plug->outports();
- if (instances < 1)
- instances = 1;
+ if(instances < 1)
+ instances = 1;
handle = new LADSPA_Handle[instances];
- for (int i = 0; i < instances; ++i) {
- handle[i] = _plugin->instantiate();
- if (handle[i] == 0)
- return true;
- }
+ for(int i = 0; i < instances; ++i)
+ {
+ handle[i] = _plugin->instantiate();
+ //if (handle[i] == 0)
+ if(handle[i] == NULL)
+ return true;
+ }
+ unsigned long ports = _plugin->ports();
+
controlPorts = 0;
controlOutPorts = 0;
- int ports = _plugin->ports();
-
- for (int k = 0; k < ports; ++k)
+
+ for(unsigned long k = 0; k < ports; ++k)
{
- LADSPA_PortDescriptor pd = _plugin->portd(k);
- if (pd & LADSPA_PORT_CONTROL)
- {
- if (pd & LADSPA_PORT_INPUT)
- ++controlPorts;
- else
- if (pd & LADSPA_PORT_OUTPUT)
- ++controlOutPorts;
- }
+ LADSPA_PortDescriptor pd = _plugin->portd(k);
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++controlPorts;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++controlOutPorts;
+ }
}
+
controls = new Port[controlPorts];
controlsOut = new Port[controlOutPorts];
+
int i = 0;
int ii = 0;
- for (int k = 0; k < ports; ++k)
+ for(unsigned long k = 0; k < ports; ++k)
{
- LADSPA_PortDescriptor pd = _plugin->portd(k);
- if (pd & LADSPA_PORT_CONTROL)
- {
- if (pd & LADSPA_PORT_INPUT)
- {
- double val = _plugin->defaultValue(k);
- controls[i].val = val;
- controls[i].tmpVal = val;
- controls[i].enCtrl = true;
- controls[i].en2Ctrl = true;
- ++i;
- }
- else
- if (pd & LADSPA_PORT_OUTPUT)
- {
- //double val = _plugin->defaultValue(k);
- controls[ii].val = 0.0;
- controls[ii].tmpVal = 0.0;
- controls[ii].enCtrl = false;
- controls[ii].en2Ctrl = false;
- ++ii;
- }
- }
+ LADSPA_PortDescriptor pd = _plugin->portd(k);
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ {
+ double val = _plugin->defaultValue(k);
+ controls[i].val = val;
+ controls[i].tmpVal = val;
+ controls[i].enCtrl = true;
+ controls[i].en2Ctrl = true;
+ ++i;
+ }
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ {
+ //double val = _plugin->defaultValue(k);
+ controlsOut[ii].val = 0.0;
+ controlsOut[ii].tmpVal = 0.0;
+ controlsOut[ii].enCtrl = false;
+ controlsOut[ii].en2Ctrl = false;
+ ++ii;
+ }
+ }
}
- int curPort = 0;
- int curOutPort = 0;
- for (int k = 0; k < ports; ++k)
+ unsigned long curPort = 0;
+ unsigned long curOutPort = 0;
+ for(unsigned long k = 0; k < ports; ++k)
{
- LADSPA_PortDescriptor pd = _plugin->portd(k);
- if (pd & LADSPA_PORT_CONTROL)
- {
- if (pd & LADSPA_PORT_INPUT)
- {
- for (int i = 0; i < instances; ++i)
- _plugin->connectPort(handle[i], k, &controls[curPort].val);
- controls[curPort].idx = k;
- ++curPort;
- }
- else
- if (pd & LADSPA_PORT_OUTPUT)
- {
- for (int i = 0; i < instances; ++i)
- _plugin->connectPort(handle[i], k, &controlsOut[curOutPort].val);
- controlsOut[curOutPort].idx = k;
- ++curOutPort;
- }
- }
+ LADSPA_PortDescriptor pd = _plugin->portd(k);
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ {
+ for(int i = 0; i < instances; ++i)
+ _plugin->connectPort(handle[i], k, &controls[curPort].val);
+ controls[curPort].idx = k;
+ ++curPort;
+ }
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ {
+ for(int i = 0; i < instances; ++i)
+ _plugin->connectPort(handle[i], k, &controlsOut[curOutPort].val);
+ controlsOut[curOutPort].idx = k;
+ ++curOutPort;
+ }
+ }
}
activate();
return false;
@@ -1318,7 +1689,7 @@ void PluginI::connect(int ports, float** src, float** dst)
{
int port = 0;
for (int i = 0; i < instances; ++i) {
- for (int k = 0; k < _plugin->ports(); ++k) {
+ for (unsigned long k = 0; k < _plugin->ports(); ++k) {
if (isAudioIn(k)) {
_plugin->connectPort(handle[i], k, src[port]);
port = (port + 1) % ports;
@@ -1327,7 +1698,7 @@ void PluginI::connect(int ports, float** src, float** dst)
}
port = 0;
for (int i = 0; i < instances; ++i) {
- for (int k = 0; k < _plugin->ports(); ++k) {
+ for (unsigned long k = 0; k < _plugin->ports(); ++k) {
if (isAudioOut(k)) {
_plugin->connectPort(handle[i], k, dst[port]);
port = (port + 1) % ports; // overwrite output?
@@ -1377,6 +1748,11 @@ void PluginI::writeConfiguration(int level, Xml& xml)
xml.intTag(level, "gui", 1);
xml.geometryTag(level, "geometry", _gui);
}
+ if (nativeGuiVisible()) {
+ xml.intTag(level, "nativegui", 1);
+ // TODO:
+ //xml.geometryTag(level, "nativegeometry", ?);
+ }
xml.tag(level--, "/plugin");
}
@@ -1462,6 +1838,13 @@ bool PluginI::readConfiguration(Xml& xml, bool readPreset)
bool flag = xml.parseInt();
showGui(flag);
}
+ else if (tag == "nativegui") {
+ // We can't tell OSC to show the native plugin gui
+ // until the parent track is added to the lists.
+ // OSC needs to find the plugin in the track lists.
+ // Use this 'pending' flag so it gets done later.
+ _showNativeGuiPending = xml.parseInt();
+ }
else if (tag == "geometry") {
QRect r(readGeometry(xml, tag));
if (_gui) {
@@ -1557,6 +1940,48 @@ bool PluginI::guiVisible()
}
//---------------------------------------------------------
+// showNativeGui
+//---------------------------------------------------------
+
+void PluginI::showNativeGui()
+{
+ #ifdef OSC_SUPPORT
+ if (_plugin)
+ {
+ if (_oscif.oscGuiVisible())
+ _oscif.oscShowGui(false);
+ else
+ _oscif.oscShowGui(true);
+ }
+ #endif
+ _showNativeGuiPending = false;
+}
+
+void PluginI::showNativeGui(bool flag)
+{
+ #ifdef OSC_SUPPORT
+ if(_plugin)
+ {
+ _oscif.oscShowGui(flag);
+ }
+ #endif
+ _showNativeGuiPending = false;
+}
+
+//---------------------------------------------------------
+// nativeGuiVisible
+//---------------------------------------------------------
+
+bool PluginI::nativeGuiVisible()
+{
+ #ifdef OSC_SUPPORT
+ return _oscif.oscGuiVisible();
+ #endif
+
+ return false;
+}
+
+//---------------------------------------------------------
// makeGui
//---------------------------------------------------------
@@ -1602,23 +2027,351 @@ void PluginI::enable2AllControllers(bool v)
//---------------------------------------------------------
void PluginI::apply(int n)
+{
+ // Process control value changes.
+ //if(automation && _track && _track->automationType() != AUTO_OFF && _id != -1)
+ //{
+ // for(int i = 0; i < controlPorts; ++i)
+ // {
+ // if( controls[i].enCtrl && controls[i].en2Ctrl )
+ // controls[i].tmpVal = _track->pluginCtrlVal(genACnum(_id, i));
+ // }
+ //}
+
+ unsigned long ctls = controlPorts;
+ for(unsigned long k = 0; k < ctls; ++k)
{
- if(automation && _track && _track->automationType() != AUTO_OFF && _id != -1)
- {
- for(int i = 0; i < controlPorts; ++i)
+ // First, update the temporary value if needed...
+
+ #ifdef OSC_SUPPORT
+ // Process OSC gui input control fifo events.
+ // It is probably more important that these are processed so that they take precedence over all other
+ // events because OSC + DSSI/DSSI-VST are fussy about receiving feedback via these control ports, from GUI changes.
+
+ OscControlFifo* cfifo = _oscif.oscFifo(k);
+ //if(!cfifo)
+ // continue;
+
+ // If there are 'events' in the fifo, get exactly one 'event' per control per process cycle...
+ //if(!cfifo->isEmpty())
+ if(cfifo && !cfifo->isEmpty())
{
- if( controls[i].enCtrl && controls[i].en2Ctrl )
- controls[i].tmpVal = _track->pluginCtrlVal(genACnum(_id, i));
- }
- }
+ OscControlValue v = cfifo->get();
+
+ #ifdef PLUGIN_DEBUGIN
+ fprintf(stderr, "PluginI::apply OscControlFifo event input control number:%ld value:%f\n", k, v.value);
+ #endif
+
+ // Set the ladspa control port value.
+ controls[k].tmpVal = v.value;
+
+ // Need to update the automation value, otherwise it overwrites later with the last automation value.
+ if(_track && _id != -1)
+ {
+ // Since we are now in the audio thread context, there's no need to send a message,
+ // just modify directly.
+ //audio->msgSetPluginCtrlVal(this, genACnum(_id, k), controls[k].val);
+ _track->setPluginCtrlVal(genACnum(_id, k), v.value);
+
+ // Record automation.
+ // NO! Take care of this immediately in the OSC control handler, because we don't want
+ // the silly delay associated with processing the fifo one-at-a-time here.
+
+ //AutomationType at = _track->automationType();
+ // TODO: Taken from our native gui control handlers.
+ // This may need modification or may cause problems -
+ // we don't have the luxury of access to the dssi gui controls !
+ //if(at == AUTO_WRITE || (audio->isPlaying() && at == AUTO_TOUCH))
+ // enableController(k, false);
+ //_track->recordAutomation(id, v.value);
+ }
+ }
+ else
+ #endif // OSC_SUPPORT
+ {
+ // Process automation control value.
+ if(automation && _track && _track->automationType() != AUTO_OFF && _id != -1)
+ {
+ if(controls[k].enCtrl && controls[k].en2Ctrl )
+ controls[k].tmpVal = _track->pluginCtrlVal(genACnum(_id, k));
+ }
+ }
+
+ // Now update the actual value from the temporary value...
+ controls[k].val = controls[k].tmpVal;
+ }
+
+ //for (int i = 0; i < controlPorts; ++i)
+ // controls[i].val = controls[i].tmpVal;
- for (int i = 0; i < controlPorts; ++i)
- controls[i].val = controls[i].tmpVal;
for (int i = 0; i < instances; ++i)
_plugin->apply(handle[i], n);
}
//---------------------------------------------------------
+// oscConfigure
+//---------------------------------------------------------
+
+#ifdef OSC_SUPPORT
+int Plugin::oscConfigure(LADSPA_Handle handle, const char* key, const char* value)
+ {
+ #ifdef PLUGIN_DEBUGIN
+ printf("Plugin::oscConfigure effect plugin label:%s key:%s value:%s\n", plugin->Label, key, value);
+ #endif
+
+ #ifdef DSSI_SUPPORT
+ if(!dssi_descr || !dssi_descr->configure)
+ return 0;
+
+ if (!strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX,
+ strlen(DSSI_RESERVED_CONFIGURE_PREFIX))) {
+ fprintf(stderr, "Plugin::oscConfigure OSC: UI for plugin '%s' attempted to use reserved configure key \"%s\", ignoring\n",
+ plugin->Label, key);
+
+ return 0;
+ }
+
+ char* message = dssi_descr->configure(handle, key, value);
+ if (message) {
+ printf("Plugin::oscConfigure on configure '%s' '%s', plugin '%s' returned error '%s'\n",
+ //key, value, synti->name().toAscii().data(), message);
+ key, value, plugin->Label, message);
+
+ free(message);
+ }
+
+ // also call back on UIs for plugins other than the one
+ // that requested this:
+ // if (n != instance->number && instances[n].uiTarget) {
+ // lo_send(instances[n].uiTarget,
+ // instances[n].ui_osc_configure_path, "ss", key, value);
+ // }
+
+ // configure invalidates bank and program information, so
+ // we should do this again now:
+ //queryPrograms();
+
+ #endif // DSSI_SUPPORT
+
+ return 0;
+}
+
+//---------------------------------------------------------
+// oscConfigure
+//---------------------------------------------------------
+
+int PluginI::oscConfigure(const char *key, const char *value)
+ {
+ if(!_plugin)
+ return 0;
+
+ // This is pretty much the simplest legal implementation of
+ // configure in a DSSI host.
+
+ // The host has the option to remember the set of (key,value)
+ // pairs associated with a particular instance, so that if it
+ // wants to restore the "same" instance on another occasion it can
+ // just call configure() on it for each of those pairs and so
+ // restore state without any input from a GUI. Any real-world GUI
+ // host will probably want to do that. This host doesn't have any
+ // concept of restoring an instance from one run to the next, so
+ // we don't bother remembering these at all.
+
+ //const char *key = (const char *)&argv[0]->s;
+ //const char *value = (const char *)&argv[1]->s;
+
+ #ifdef PLUGIN_DEBUGIN
+ printf("PluginI::oscConfigure effect plugin name:%s label:%s key:%s value:%s\n", _name.latin1(), _label.latin1(), key, value);
+ #endif
+
+ #ifdef DSSI_SUPPORT
+ // FIXME: Don't think this is right, should probably do as example shows below.
+ for(int i = 0; i < instances; ++i)
+ _plugin->oscConfigure(handle[i], key, value);
+
+ // also call back on UIs for plugins other than the one
+ // that requested this:
+ // if (n != instance->number && instances[n].uiTarget) {
+ // lo_send(instances[n].uiTarget,
+ // instances[n].ui_osc_configure_path, "ss", key, value);
+ // }
+
+ // configure invalidates bank and program information, so
+ // we should do this again now:
+ //queryPrograms();
+ #endif // DSSI_SUPPORT
+
+ return 0;
+}
+
+//---------------------------------------------------------
+// oscUpdate
+//---------------------------------------------------------
+
+int PluginI::oscUpdate()
+{
+ #ifdef DSSI_SUPPORT
+ // Send project directory.
+ _oscif.oscSendConfigure(DSSI_PROJECT_DIRECTORY_KEY, museProject.latin1()); // song->projectPath()
+ #endif
+
+ /*
+ // Send current string configuration parameters.
+ StringParamMap& map = synti->stringParameters();
+ int i = 0;
+ for(ciStringParamMap r = map.begin(); r != map.end(); ++r)
+ {
+ _oscIF.oscSendConfigure(r->first.c_str(), r->second.c_str());
+ // Avoid overloading the GUI if there are lots and lots of params.
+ if((i+1) % 50 == 0)
+ usleep(300000);
+ ++i;
+ }
+
+ // Send current bank and program.
+ unsigned long bank, prog;
+ synti->currentProg(&prog, &bank, 0);
+ _oscIF.oscSendProgram(prog, bank);
+
+ // Send current control values.
+ unsigned long ports = synth->_controlInPorts;
+ for(unsigned long i = 0; i < ports; ++i)
+ {
+ unsigned long k = synth->pIdx(i);
+ _oscIF.oscSendControl(k, controls[i]);
+ // Avoid overloading the GUI if there are lots and lots of ports.
+ if((i+1) % 50 == 0)
+ usleep(300000);
+ }
+
+ */
+
+ return 0;
+}
+
+//---------------------------------------------------------
+// oscControl
+//---------------------------------------------------------
+
+int PluginI::oscControl(unsigned long port, float value)
+{
+ //int port = argv[0]->i;
+ //LADSPA_Data value = argv[1]->f;
+
+ #ifdef PLUGIN_DEBUGIN
+ printf("PluginI::oscControl received oscControl port:%ld val:%f\n", port, value);
+ #endif
+
+ //int controlPorts = synth->_controller;
+
+ //if(port >= controlPorts)
+ //if(port < 0 || port >= _plugin->rpIdx.size())
+ //{
+ //fprintf(stderr, "DssiSynthIF::oscControl: port number:%d is out of range of number of ports:%d\n", port, controlPorts);
+ // fprintf(stderr, "PluginI::oscControl: port number:%d is out of range of index list size:%d\n", port, _plugin->rpIdx.size());
+ // return 0;
+ //}
+
+ // Convert from DSSI port number to control input port index.
+ //unsigned long cport = _plugin->rpIdx[port];
+ unsigned long cport = _plugin->port2InCtrl(port);
+
+ if((int)cport == -1)
+ {
+ fprintf(stderr, "PluginI::oscControl: port number:%ld is not a control input\n", port);
+ return 0;
+ }
+
+ // (From DSSI module).
+ // p3.3.39 Set the DSSI control input port's value.
+ // Observations: With a native DSSI synth like LessTrivialSynth, the native GUI's controls do not change the sound at all
+ // ie. they don't update the DSSI control port values themselves.
+ // Hence in response to the call to this oscControl, sent by the native GUI, it is required to that here.
+/// controls[cport].val = value;
+ // DSSI-VST synths however, unlike DSSI synths, DO change their OWN sound in response to their gui controls.
+ // AND this function is called !
+ // Despite the descrepency we are STILL required to update the DSSI control port values here
+ // because dssi-vst is WAITING FOR A RESPONSE! (A CHANGE in the control port value).
+ // It will output something like "...4 events expected..." and count that number down as 4 actual control port value CHANGES
+ // are done here in response. Normally it says "...0 events expected..." when MusE is the one doing the DSSI control changes.
+ // TODO: May need FIFOs on each control(!) so that the control changes get sent one per process cycle!
+ // Observed countdown not actually going to zero upon string of changes.
+ // Try this ...
+ OscControlFifo* cfifo = _oscif.oscFifo(cport);
+ if(cfifo)
+ {
+ OscControlValue cv;
+ //cv.idx = cport;
+ cv.value = value;
+ if(cfifo->put(cv))
+ {
+ fprintf(stderr, "PluginI::oscControl: fifo overflow: in control number:%ld\n", cport);
+ }
+ }
+
+ // Record automation:
+ // Take care of this immediately, because we don't want the silly delay associated with
+ // processing the fifo one-at-a-time in the apply().
+ // NOTE: Ahh crap! We don't receive control events until the user RELEASES a control !
+ // So the events all arrive at once when the user releases a control.
+ // That makes this pretty useless... But what the heck...
+ if(_track && _id != -1)
+ {
+ int id = genACnum(_id, cport);
+ AutomationType at = _track->automationType();
+
+ // TODO: Taken from our native gui control handlers.
+ // This may need modification or may cause problems -
+ // we don't have the luxury of access to the dssi gui controls !
+ if(at == AUTO_WRITE || (audio->isPlaying() && at == AUTO_TOUCH))
+ enableController(cport, false);
+
+ _track->recordAutomation(id, value);
+ }
+
+ /*
+ const DSSI_Descriptor* dssi = synth->dssi;
+ const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
+
+ ciMidiCtl2LadspaPort ip = synth->port2MidiCtlMap.find(cport);
+ if(ip != synth->port2MidiCtlMap.end())
+ {
+ // TODO: TODO: Update midi MusE's midi controller knobs, sliders, boxes etc with a call to the midi port's setHwCtrlState() etc.
+ // But first we need a ladspa2MidiValue() function! ...
+ //
+ //
+ //float val = ladspa2MidiValue(ld, i, ?, ?);
+
+ }
+ */
+
+#if 0
+ int port = argv[0]->i;
+ LADSPA_Data value = argv[1]->f;
+
+ if (port < 0 || port > instance->plugin->descriptor->LADSPA_Plugin->PortCount) {
+ fprintf(stderr, "MusE: OSC: %s port number (%d) is out of range\n",
+ instance->friendly_name, port);
+ return 0;
+ }
+ if (instance->pluginPortControlInNumbers[port] == -1) {
+ fprintf(stderr, "MusE: OSC: %s port %d is not a control in\n",
+ instance->friendly_name, port);
+ return 0;
+ }
+ pluginControlIns[instance->pluginPortControlInNumbers[port]] = value;
+ if (verbose) {
+ printf("MusE: OSC: %s port %d = %f\n",
+ instance->friendly_name, port, value);
+ }
+#endif
+ return 0;
+ }
+
+#endif // OSC_SUPPORT
+
+
+//---------------------------------------------------------
// PluginDialog
// select Plugin dialog
//---------------------------------------------------------
@@ -1746,122 +2499,149 @@ void PluginDialog::accept()
//---------------------------------------------------------
void PluginDialog::fillPlugs(int nbr)
- {
- pList->clear();
- for (iPlugin i = plugins.begin(); i != plugins.end(); ++i) {
- int ai = 0;
- int ao = 0;
- int ci = 0;
- int co = 0;
- for (int k = 0; k < i->ports(); ++k) {
- LADSPA_PortDescriptor pd = i->portd(k);
- if (pd & LADSPA_PORT_CONTROL) {
- if (pd & LADSPA_PORT_INPUT)
- ++ci;
- else
- ++co;
- }
- else {
- if (pd & LADSPA_PORT_INPUT)
- ++ai;
- else
- ++ao;
- }
- }
+{
+ pList->clear();
+ for(iPlugin i = plugins.begin(); i != plugins.end(); ++i)
+ {
+ /*
+ int ai = 0;
+ int ao = 0;
+ int ci = 0;
+ int co = 0;
+ for(unsigned long k = 0; k < i->ports(); ++k)
+ {
+ LADSPA_PortDescriptor pd = i->portd(k);
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++ci;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++co;
+ }
+ else
+ if(pd & LADSPA_PORT_AUDIO)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++ai;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++ao;
+ }
+ }
+ */
+ int ai = i->inports();
+ int ao = i->outports();
+ int ci = i->controlInPorts();
+ int co = i->controlOutPorts();
- bool addFlag = false;
- switch(nbr)
- {
- case 0: // stereo & mono
- if ((ai == 1 || ai == 2) && (ao == 1 || ao ==2))
- {
- addFlag = true;
- }
- break;
- case 1: // stereo
- if ((ai == 1 || ai == 2) && ao ==2)
- {
- addFlag = true;
- }
- break;
- case 2: // mono
- if (ai == 1 && ao == 1)
- {
- addFlag = true;
- }
- break;
- case 3: // all
- addFlag = true;
- break;
- }
- if (addFlag)
- {
- QListViewItem* item = new QListViewItem(pList,
- i->lib(),
- i->label(),
- i->name(),
- QString().setNum(ai),
- QString().setNum(ao),
- QString().setNum(ci),
- QString().setNum(co),
- QString().setNum(i->inPlaceCapable())
- );
- item->setText(8, QString().setNum(i->id()));
- item->setText(9, i->maker());
- item->setText(10, i->copyright());
+ bool addFlag = false;
+ switch(nbr)
+ {
+ case 0: // stereo & mono
+ if ((ai == 1 || ai == 2) && (ao == 1 || ao ==2))
+ {
+ addFlag = true;
}
- }
- selectedPlugType = nbr;
- }
+ break;
+ case 1: // stereo
+ if ((ai == 1 || ai == 2) && ao ==2)
+ {
+ addFlag = true;
+ }
+ break;
+ case 2: // mono
+ if (ai == 1 && ao == 1)
+ {
+ addFlag = true;
+ }
+ break;
+ case 3: // all
+ addFlag = true;
+ break;
+ }
+ if(addFlag)
+ {
+ QListViewItem* item = new QListViewItem(pList,
+ i->lib(),
+ i->label(),
+ i->name(),
+ QString().setNum(ai),
+ QString().setNum(ao),
+ QString().setNum(ci),
+ QString().setNum(co),
+ QString().setNum(i->inPlaceCapable())
+ );
+ item->setText(8, QString().setNum(i->id()));
+ item->setText(9, i->maker());
+ item->setText(10, i->copyright());
+ }
+ }
+ selectedPlugType = nbr;
+}
void PluginDialog::fillPlugs(const QString &sortValue)
- {
- pList->clear();
- for (iPlugin i = plugins.begin(); i != plugins.end(); ++i) {
- int ai = 0;
- int ao = 0;
- int ci = 0;
- int co = 0;
- for (int k = 0; k < i->ports(); ++k) {
- LADSPA_PortDescriptor pd = i->portd(k);
- if (pd & LADSPA_PORT_CONTROL) {
- if (pd & LADSPA_PORT_INPUT)
- ++ci;
- else
- ++co;
- }
- else {
- if (pd & LADSPA_PORT_INPUT)
- ++ai;
- else
- ++ao;
- }
- }
-
- bool addFlag = false;
-
- if (i->label().lower().contains(sortValue.lower()))
- addFlag = true;
- else if (i->name().lower().contains(sortValue.lower()))
- addFlag = true;
- if (addFlag)
- {
- QListViewItem* item = new QListViewItem(pList,
- i->lib(),
- i->label(),
- i->name(),
- QString().setNum(ai),
- QString().setNum(ao),
- QString().setNum(ci),
- QString().setNum(co),
- QString().setNum(i->inPlaceCapable())
- );
- item->setText(8, QString().setNum(i->id()));
- item->setText(9, i->maker());
- item->setText(10, i->copyright());
- }
- }
+{
+ pList->clear();
+ for(iPlugin i = plugins.begin(); i != plugins.end(); ++i)
+ {
+ /*
+ int ai = 0;
+ int ao = 0;
+ int ci = 0;
+ int co = 0;
+ for(unsigned long k = 0; k < i->ports(); ++k)
+ {
+ LADSPA_PortDescriptor pd = i->portd(k);
+ if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++ci;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++co;
}
+ else
+ if(pd & LADSPA_PORT_AUDIO)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ ++ai;
+ else
+ if(pd & LADSPA_PORT_OUTPUT)
+ ++ao;
+ }
+ }
+ */
+ int ai = i->inports();
+ int ao = i->outports();
+ int ci = i->controlInPorts();
+ int co = i->controlOutPorts();
+
+ bool addFlag = false;
+
+ if(i->label().lower().contains(sortValue.lower()))
+ addFlag = true;
+ else
+ if(i->name().lower().contains(sortValue.lower()))
+ addFlag = true;
+ if(addFlag)
+ {
+ QListViewItem* item = new QListViewItem(pList,
+ i->lib(),
+ i->label(),
+ i->name(),
+ QString().setNum(ai),
+ QString().setNum(ao),
+ QString().setNum(ci),
+ QString().setNum(co),
+ QString().setNum(i->inPlaceCapable())
+ );
+ item->setText(8, QString().setNum(i->id()));
+ item->setText(9, i->maker());
+ item->setText(10, i->copyright());
+ }
+ }
+}
//---------------------------------------------------------
// getPlugin
@@ -2559,7 +3339,6 @@ void PluginGui::updateControls()
}
if(((Slider*)(gp->actuator))->value() != sv)
{
- // Added by Tim. p3.3.6
//printf("PluginGui::updateControls slider\n");
gp->label->blockSignals(true);
@@ -2578,7 +3357,6 @@ void PluginGui::updateControls()
bool v = (int)plugin->track()->pluginCtrlVal(genACnum(plugin->id(), i));
if(((CheckBox*)(gp->actuator))->isChecked() != v)
{
- // Added by Tim. p3.3.6
//printf("PluginGui::updateControls switch\n");
((CheckBox*)(gp->actuator))->blockSignals(true);
@@ -2601,7 +3379,6 @@ void PluginGui::updateControls()
double v = plugin->track()->pluginCtrlVal(genACnum(plugin->id(), param));
if(((Slider*)widget)->value() != v)
{
- // Added by Tim. p3.3.6
//printf("PluginGui::updateControls slider\n");
((Slider*)widget)->blockSignals(true);
@@ -2616,7 +3393,6 @@ void PluginGui::updateControls()
double v = plugin->track()->pluginCtrlVal(genACnum(plugin->id(), param));
if(((DoubleLabel*)widget)->value() != v)
{
- // Added by Tim. p3.3.6
//printf("PluginGui::updateControls label\n");
((DoubleLabel*)widget)->blockSignals(true);
@@ -2631,7 +3407,6 @@ void PluginGui::updateControls()
bool b = (bool) plugin->track()->pluginCtrlVal(genACnum(plugin->id(), param));
if(((QCheckBox*)widget)->isChecked() != b)
{
- // Added by Tim. p3.3.6
//printf("PluginGui::updateControls checkbox\n");
((QCheckBox*)widget)->blockSignals(true);
@@ -2646,7 +3421,6 @@ void PluginGui::updateControls()
int n = (int) plugin->track()->pluginCtrlVal(genACnum(plugin->id(), param));
if(((QComboBox*)widget)->currentItem() != n)
{
- // Added by Tim. p3.3.6
//printf("PluginGui::updateControls combobox\n");
((QComboBox*)widget)->blockSignals(true);
diff --git a/muse/muse/plugin.h b/muse/muse/plugin.h
index 2ec13e29..8461b7f8 100644
--- a/muse/muse/plugin.h
+++ b/muse/muse/plugin.h
@@ -25,6 +25,19 @@
#include "globaldefs.h"
#include "ctrl.h"
+//#include "stringparam.h"
+
+#include "config.h"
+
+#ifdef OSC_SUPPORT
+//class OscIF;
+#include "osc.h"
+#endif
+
+#ifdef DSSI_SUPPORT
+#include <dssi.h>
+#endif
+
class Xml;
class QWidget;
// class QLabel;
@@ -50,67 +63,107 @@ class PluginWidgetFactory : public QWidgetFactory
//---------------------------------------------------------
class Plugin {
+ protected:
+ void* _handle;
int _references;
int _instNo;
QFileInfo fi;
LADSPA_Descriptor_Function ladspa;
const LADSPA_Descriptor *plugin;
- int _inports;
- int _outports;
+ unsigned long _uniqueID;
+ QString _label;
+ QString _name;
+ QString _maker;
+ QString _copyright;
+
+ bool _isDssi;
+ #ifdef DSSI_SUPPORT
+ const DSSI_Descriptor* dssi_descr;
+ #endif
+
+ //LADSPA_PortDescriptor* _portDescriptors;
+ unsigned long _portCount;
+ unsigned long _inports;
+ unsigned long _outports;
+ unsigned long _controlInPorts;
+ unsigned long _controlOutPorts;
+ std::vector<unsigned long> rpIdx; // Port number to control input index. Item is -1 if it's not a control input.
+
bool _inPlaceCapable;
public:
- Plugin(QFileInfo* f,
- LADSPA_Descriptor_Function df, const LADSPA_Descriptor* d, bool inPlace);
-
- QString label() const { return QString(plugin->Label); }
- QString name() const { return QString(plugin->Name); }
- unsigned long id() const { return plugin->UniqueID; }
- QString maker() const { return QString(plugin->Maker); }
- QString copyright() const { return QString(plugin->Copyright); }
- QString lib() const { return fi.baseName(true); }
- QString path() const { return fi.dirPath(); }
- int references() const { return _references; }
- int incReferences(int n) { return _references += n; }
- int instNo() { return _instNo++; }
-
- LADSPA_Handle instantiate() {
- return plugin->instantiate(plugin, sampleRate);
- }
+ Plugin(QFileInfo* f, const LADSPA_Descriptor* d, bool isDssi = false);
+ ~Plugin();
+
+ QString label() const { return _label; }
+ QString name() const { return _name; }
+ unsigned long id() const { return _uniqueID; }
+ QString maker() const { return _maker; }
+ QString copyright() const { return _copyright; }
+ QString lib(bool complete = true) const { return fi.baseName(complete); }
+ QString dirPath(bool complete = true) const { return fi.dirPath(complete); }
+ QString filePath() const { return fi.filePath(); }
+ int references() const { return _references; }
+ int incReferences(int);
+ int instNo() { return _instNo++; }
+
+ bool isDssiPlugin() const { return _isDssi; }
+
+ LADSPA_Handle instantiate();
void activate(LADSPA_Handle handle) {
- if (plugin->activate)
+ if (plugin && plugin->activate)
plugin->activate(handle);
}
void deactivate(LADSPA_Handle handle) {
- if (plugin->deactivate)
+ if (plugin && plugin->deactivate)
plugin->deactivate(handle);
}
void cleanup(LADSPA_Handle handle) {
- if (plugin->cleanup)
+ if (plugin && plugin->cleanup)
plugin->cleanup(handle);
}
void connectPort(LADSPA_Handle handle, int port, float* value) {
- plugin->connect_port(handle, port, value);
+ if(plugin)
+ plugin->connect_port(handle, port, value);
}
void apply(LADSPA_Handle handle, int n) {
- plugin->run(handle, n);
+ if(plugin)
+ plugin->run(handle, n);
}
- int ports() { return plugin->PortCount; }
- double defaultValue(unsigned int port) const;
- LADSPA_PortDescriptor portd(int k) const {
- return plugin->PortDescriptors[k];
+
+ #ifdef OSC_SUPPORT
+ int oscConfigure(LADSPA_Handle /*handle*/, const char* /*key*/, const char* /*value*/);
+ #endif
+
+ //int ports() { return plugin ? plugin->PortCount : 0; }
+ unsigned long ports() { return _portCount; }
+
+ LADSPA_PortDescriptor portd(unsigned long k) const {
+ return plugin ? plugin->PortDescriptors[k] : 0;
+ //return _portDescriptors[k];
}
- void range(int i, float*, float*) const;
- LADSPA_PortRangeHint range(int i) {
+
+ LADSPA_PortRangeHint range(unsigned long i) {
+ // FIXME:
+ //return plugin ? plugin->PortRangeHints[i] : 0;
return plugin->PortRangeHints[i];
}
- const char* portName(int i) {
- return plugin->PortNames[i];
+ double defaultValue(unsigned long port) const;
+ void range(unsigned long i, float*, float*) const;
+
+ const char* portName(unsigned long i) {
+ return plugin ? plugin->PortNames[i] : 0;
}
- int inports() const { return _inports; }
- int outports() const { return _outports; }
- bool inPlaceCapable() const { return _inPlaceCapable; }
+
+ // Returns (int)-1 if not an input control.
+ unsigned long port2InCtrl(unsigned long p) { return p >= rpIdx.size() ? (unsigned long)-1 : rpIdx[p]; }
+
+ unsigned long inports() const { return _inports; }
+ unsigned long outports() const { return _outports; }
+ unsigned long controlInPorts() const { return _controlInPorts; }
+ unsigned long controlOutPorts() const { return _controlOutPorts; }
+ bool inPlaceCapable() const { return _inPlaceCapable; }
};
typedef std::list<Plugin>::iterator iPlugin;
@@ -121,10 +174,11 @@ typedef std::list<Plugin>::iterator iPlugin;
class PluginList : public std::list<Plugin> {
public:
- void add(QFileInfo* fi, LADSPA_Descriptor_Function df,
- const LADSPA_Descriptor* d, bool inPlaceOk) {
- push_back(Plugin(fi, df, d, inPlaceOk));
- }
+ void add(QFileInfo* fi, const LADSPA_Descriptor* d, bool isDssi = false)
+ {
+ push_back(Plugin(fi, d, isDssi));
+ }
+
Plugin* find(const QString&, const QString&);
PluginList() {}
};
@@ -242,9 +296,18 @@ class PluginI {
QString _name;
QString _label;
+ //#ifdef DSSI_SUPPORT
+ //StringParamMap _stringParamMap;
+ //#endif
+
+ #ifdef OSC_SUPPORT
+ OscEffectIF _oscif;
+ #endif
+ bool _showNativeGuiPending;
+
void init();
void makeGui();
-
+
public:
PluginI();
~PluginI();
@@ -280,13 +343,33 @@ class PluginI {
CtrlValueType valueType() const;
QString lib() const { return _plugin->lib(); }
+ #ifdef OSC_SUPPORT
+ OscEffectIF& oscIF() { return _oscif; }
+ /*
+ int oscConfigure(lo_arg**);
+ int oscControl(lo_arg**);
+ //int oscUpdate(lo_arg**);
+ //int oscExiting(lo_arg**);
+ */
+
+ int oscControl(unsigned long /*dssiPort*/, float /*val*/);
+ int oscConfigure(const char */*key*/, const char */*val*/);
+ int oscUpdate();
+ //int oscExiting();
+ #endif
+
void writeConfiguration(int level, Xml& xml);
bool readConfiguration(Xml& xml, bool readPreset=false);
bool loadControl(Xml& xml);
bool setControl(const QString& s, double val);
void showGui();
void showGui(bool);
+ bool isDssiPlugin() const { return _plugin->isDssiPlugin(); }
+ void showNativeGui();
+ void showNativeGui(bool);
+ bool isShowNativeGuiPending() { return _showNativeGuiPending; }
bool guiVisible();
+ bool nativeGuiVisible();
int parameters() const { return controlPorts; }
void setParam(int i, double val) { controls[i].tmpVal = val; }
double param(int i) const { return controls[i].val; }
@@ -330,9 +413,12 @@ class Pipeline : public std::vector<PluginI*> {
QString label(int idx) const;
QString name(int idx) const;
void showGui(int, bool);
+ bool isDssiPlugin(int) const;
+ void showNativeGui(int, bool);
void deleteGui(int idx);
void deleteAllGuis();
bool guiVisible(int);
+ bool nativeGuiVisible(int);
void apply(int ports, unsigned long nframes, float** buffer);
void move(int idx, bool up);
bool empty(int idx) const;
diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp
index fa08f27f..bccb3f72 100644
--- a/muse/muse/song.cpp
+++ b/muse/muse/song.cpp
@@ -1559,9 +1559,15 @@ void Song::beat()
midiPorts[port].syncInfo().setTime();
}
+
int tick = audio->tickPos();
if (audio->isPlaying())
setPos(0, tick, true, false, true);
+
+ // p3.3.40 Update synth native guis at the heartbeat rate.
+ for(ciSynthI is = _synthIs.begin(); is != _synthIs.end(); ++is)
+ (*is)->guiHeartBeat();
+
while (noteFifoSize) {
int pv = recNoteFifo[noteFifoRindex];
noteFifoRindex = (noteFifoRindex + 1) % REC_NOTE_FIFO_SIZE;
@@ -3123,7 +3129,7 @@ void Song::insertTrack2(Track* track, int idx)
//---------------------------------------------------------
void Song::insertTrack3(Track* /*track*/, int /*idx*/)//prevent compiler warning: unused parameter
- {
+{
//printf("Song::insertTrack3\n");
/*
@@ -3134,7 +3140,7 @@ void Song::insertTrack3(Track* /*track*/, int /*idx*/)//prevent compiler warning
break;
}
*/
- }
+}
//---------------------------------------------------------
// removeTrack0
diff --git a/muse/muse/songfile.cpp b/muse/muse/songfile.cpp
index 07bf1e31..a1f51c69 100644
--- a/muse/muse/songfile.cpp
+++ b/muse/muse/songfile.cpp
@@ -1257,31 +1257,40 @@ void Song::read(Xml& xml)
WaveTrack* track = new WaveTrack();
track->read(xml);
insertTrack0(track,-1);
+ // Now that the track has been added to the lists in insertTrack2(),
+ // OSC can find the track and its plugins, and start their native guis if required...
+ track->showPendingPluginNativeGuis();
}
else if (tag == "AudioInput") {
AudioInput* track = new AudioInput();
track->read(xml);
insertTrack0(track,-1);
+ track->showPendingPluginNativeGuis();
}
else if (tag == "AudioOutput") {
AudioOutput* track = new AudioOutput();
track->read(xml);
insertTrack0(track,-1);
+ track->showPendingPluginNativeGuis();
}
else if (tag == "AudioGroup") {
AudioGroup* track = new AudioGroup();
track->read(xml);
insertTrack0(track,-1);
+ track->showPendingPluginNativeGuis();
}
else if (tag == "AudioAux") {
AudioAux* track = new AudioAux();
track->read(xml);
insertTrack0(track,-1);
+ track->showPendingPluginNativeGuis();
}
else if (tag == "SynthI") {
SynthI* track = new SynthI();
track->read(xml);
+ // Done in SynthI::read()
// insertTrack(track,-1);
+ //track->showPendingPluginNativeGuis();
}
else if (tag == "Route") {
readRoute(xml);
diff --git a/muse/muse/synth.cpp b/muse/muse/synth.cpp
index 24780a52..a08f9fcc 100644
--- a/muse/muse/synth.cpp
+++ b/muse/muse/synth.cpp
@@ -33,6 +33,7 @@
#include "audio.h"
#include "midiseq.h"
#include "midictrl.h"
+//#include "stringparam.h"
std::vector<Synth*> synthis; // array of available synthis
@@ -230,6 +231,11 @@ SynthI::SynthI()
_openFlags = 1;
_readEnable = false;
_writeEnable = false;
+
+ _curBankH = 0;
+ _curBankL = 0;
+ _curProgram = 0;
+
setVolume(1.0);
setPan(0.0);
}
@@ -283,6 +289,20 @@ void SynthI::setName(const QString& s)
}
//---------------------------------------------------------
+// currentProg
+//---------------------------------------------------------
+
+void SynthI::currentProg(unsigned long *prog, unsigned long *bankL, unsigned long *bankH)
+{
+ if(prog)
+ *prog = _curProgram;
+ if(bankL)
+ *bankL = _curBankL;
+ if(bankH)
+ *bankH = _curBankH;
+}
+
+//---------------------------------------------------------
// init
//---------------------------------------------------------
@@ -392,9 +412,14 @@ bool SynthI::initInstance(Synth* s, const QString& instanceName)
iel->clear();
}
- int idx = 0;
+ unsigned long idx = 0;
for (std::vector<float>::iterator i = initParams.begin(); i != initParams.end(); ++i, ++idx)
_sif->setParameter(idx, *i);
+
+ // p3.3.40 Since we are done with the (sometimes huge) initial parameters list, clear it.
+ // TODO: Decide: Maybe keep them around for a 'reset to previously loaded values' (revert) command? ...
+ initParams.clear();
+
return false;
}
@@ -576,6 +601,12 @@ SynthI* Song::createSynthI(const QString& sclass, const QString& label)
audio->msgUpdateSoloStates();
}
+ // Now that the track has been added to the lists in insertTrack2(),
+ // if it's a dssi synth, OSC can find the synth, and initialize (and show) its native gui.
+ // No, initializing OSC without actually showing the gui doesn't work, at least for
+ // dssi-vst plugins - without showing the gui they exit after ten seconds.
+ //si->initGui();
+
return si;
}
@@ -611,6 +642,10 @@ void SynthI::write(int level, Xml& xml) const
xml.qrectTag(level, "geometry", QRect(x, y, w, h));
}
+ _stringParamMap.write(level, xml, "stringParam");
+
+ xml.tag(level, "curProgram bankH=\"%ld\" bankL=\"%ld\" prog=\"%ld\"/", _curBankH, _curBankL, _curProgram);
+
_sif->write(level, xml);
xml.etag(level, "SynthI");
}
@@ -643,6 +678,45 @@ void MessSynthIF::write(int level, Xml& xml) const
}
//---------------------------------------------------------
+// SynthI::readProgram
+//---------------------------------------------------------
+
+void SynthI::readProgram(Xml& xml, const QString& name)
+{
+ for (;;)
+ {
+ Xml::Token token = xml.parse();
+ const QString tag = xml.s1();
+ switch (token)
+ {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::TagStart:
+ xml.unknown(name);
+ break;
+ case Xml::Attribut:
+ if(tag == "bankH")
+ _curBankH = xml.s2().toUInt();
+ else
+ if(tag == "bankL")
+ _curBankL = xml.s2().toUInt();
+ else
+ if(tag == "prog")
+ _curProgram = xml.s2().toUInt();
+ else
+ xml.unknown(name);
+ break;
+ case Xml::TagEnd:
+ if(tag == name)
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+//---------------------------------------------------------
// SynthI::read
//---------------------------------------------------------
@@ -652,7 +726,7 @@ void SynthI::read(Xml& xml)
QString label;
int port = -1;
- bool startGui = false;
+ bool startgui = false;
QRect r;
for (;;) {
@@ -670,13 +744,17 @@ void SynthI::read(Xml& xml)
else if (tag == "port")
port = xml.parseInt();
else if (tag == "guiVisible")
- startGui = xml.parseInt();
+ startgui = xml.parseInt();
else if (tag == "midistate")
readMidiState(xml);
else if (tag == "param") {
float val = xml.parseFloat();
initParams.push_back(val);
}
+ else if (tag == "stringParam")
+ _stringParamMap.read(xml, tag);
+ else if (tag == "curProgram")
+ readProgram(xml, tag);
else if (tag == "geometry")
r = readGeometry(xml, tag);
else if (AudioTrack::readProperties(xml, tag))
@@ -693,11 +771,21 @@ void SynthI::read(Xml& xml)
song->insertTrack0(this, -1);
if (port != -1 && port < MIDI_PORTS)
midiPorts[port].setMidiDevice(this);
- showGui(startGui);
+
+ // Now that the track has been added to the lists in insertTrack2(),
+ // if it's a dssi synth, OSC can find the synth, and initialize (and show) its native gui.
+ // No, initializing OSC without actually showing the gui doesn't work, at least for
+ // dssi-vst plugins - without showing the gui they exit after ten seconds.
+ //initGui();
+ showGui(startgui);
setGeometry(r.x(), r.y(), r.width(), r.height());
mapRackPluginsToControllers();
+ // Now that the track has been added to the lists in insertTrack2(), if it's a dssi synth
+ // OSC can find the track and its plugins, and start their native guis if required...
+ showPendingPluginNativeGuis();
+
return;
}
default:
diff --git a/muse/muse/synth.h b/muse/muse/synth.h
index 1841a50d..0bca9a75 100644
--- a/muse/muse/synth.h
+++ b/muse/muse/synth.h
@@ -9,7 +9,9 @@
#define __SYNTH_H__
#include <qfileinfo.h>
+#include <string>
#include <vector>
+#include <map>
#include "globals.h"
#include "node.h"
@@ -17,6 +19,7 @@
#include "mididev.h"
#include "midiport.h"
#include "track.h"
+#include "stringparam.h"
//class MidiEvent;
class MidiPlayEvent;
@@ -49,14 +52,16 @@ class Synth {
//virtual const char* description() const { return ""; }
//virtual const char* version() const { return ""; }
- int instances() const { return _instances; }
- virtual void incInstances(int val) { _instances += val; }
- QString baseName() const { return info.baseName(true); }
- QString name() const { return _name; }
- QString path() const { return info.dirPath(true); }
- QString description() const { return _description; }
- QString version() const { return _version; }
- QString maker() const { return _version; }
+ int instances() const { return _instances; }
+ virtual void incInstances(int val) { _instances += val; }
+ QString baseName(bool complete = true) const { return info.baseName(complete); }
+ QString name() const { return _name; }
+ QString dirPath(bool complete = true) const { return info.dirPath(complete); }
+ QString filePath() const { return info.filePath(); }
+ QString description() const { return _description; }
+ QString version() const { return _version; }
+ //QString maker() const { return _version; } ??
+ QString maker() const { return _maker; }
//virtual void* instantiate() = 0;
@@ -104,12 +109,14 @@ class SynthIF {
SynthIF(SynthI* s) { synti = s; }
virtual ~SynthIF() {}
+ virtual bool initGui() = 0;
+ virtual void guiHeartBeat() = 0;
virtual bool guiVisible() const = 0;
virtual void showGui(bool v) = 0;
virtual bool hasGui() const = 0;
virtual void getGeometry(int*, int*, int*, int*) const = 0;
virtual void setGeometry(int, int, int, int) = 0;
- virtual void preProcessAlways() { };
+ virtual void preProcessAlways() = 0;
virtual iMPEvent getData(MidiPort*, MPEventList*, iMPEvent, unsigned pos, int ports, unsigned n, float** buffer) = 0;
virtual bool putEvent(const MidiPlayEvent& ev) = 0;
virtual MidiPlayEvent receiveEvent() = 0;
@@ -125,7 +132,8 @@ class SynthIF {
virtual const char* getPatchName(int, int, MType, bool) = 0;
virtual void populatePatchPopup(QPopupMenu*, int, MType, bool) = 0;
virtual void write(int level, Xml& xml) const = 0;
- virtual void setParameter(int idx, float value) = 0;
+ virtual float getParameter(unsigned long idx) = 0;
+ virtual void setParameter(unsigned long idx, float value) = 0;
virtual int getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval) = 0;
};
@@ -144,14 +152,26 @@ class SynthI : public AudioTrack, public MidiDevice,
protected:
Synth* synthesizer;
- std::vector<float> initParams;
MidiFifo putFifo;
+
+ // List of initial floating point parameters, for synths which use them.
+ // Used once upon song reload, then discarded.
+ std::vector<float> initParams;
+ // List of gui controls to update upon heartbeat.
+ std::vector<bool> _guiUpdateControls;
+ // Update gui program upon heartbeat.
+ bool _guiUpdateProgram;
+ // Initial, and running, string parameters for synths which use them, like dssi.
+ StringParamMap _stringParamMap;
+ // Current bank and program for synths which use them, like dssi.
+ // In cases like dssi which have no 'hi' and 'lo' bank, just use _curBankL.
+ unsigned long _curBankH;
+ unsigned long _curBankL;
+ unsigned long _curProgram;
void preProcessAlways();
bool getData(unsigned a, int b, unsigned c, float** data);
- std::vector<bool> guiUpdateControls; // List of gui controls to update upon heartbeat.
-
//bool putEvent(const MidiPlayEvent& ev);
virtual QString open();
@@ -178,6 +198,7 @@ class SynthI : public AudioTrack, public MidiDevice,
SynthIF* sif() const { return _sif; }
bool initInstance(Synth* s, const QString& instanceName);
+ void readProgram(Xml&, const QString&);
void read(Xml&);
virtual void write(int, Xml&) const;
@@ -194,8 +215,13 @@ class SynthI : public AudioTrack, public MidiDevice,
virtual void populatePatchPopup(QPopupMenu* m, int i, MType t, bool d) {
_sif->populatePatchPopup(m, i, t, d);
}
- void setParameter(const char* name, const char* value) const;
+
+ // void setParameter(const char* name, const char* value) const; // Not required
+ //StringParamMap& stringParameters() { return _stringParamMap; } // Not required
+ void currentProg(unsigned long */*prog*/, unsigned long */*bankL*/, unsigned long */*bankH*/);
+ void guiHeartBeat() { return _sif->guiHeartBeat(); }
+ bool initGui() const { return _sif->initGui(); }
bool guiVisible() const { return _sif->guiVisible(); }
void showGui(bool v) { _sif->showGui(v); }
bool hasGui() const { return _sif->hasGui(); }
@@ -229,6 +255,8 @@ class MessSynthIF : public SynthIF {
MessSynthIF(SynthI* s) : SynthIF(s) { _mess = 0; }
virtual ~MessSynthIF() { }
+ virtual bool initGui() { return true; };
+ virtual void guiHeartBeat() { }
virtual bool guiVisible() const;
virtual void showGui(bool v);
virtual bool hasGui() const;
@@ -250,7 +278,8 @@ class MessSynthIF : public SynthIF {
virtual const char* getPatchName(int, int, MType, bool);
virtual void populatePatchPopup(QPopupMenu*, int, MType, bool);
virtual void write(int level, Xml& xml) const;
- virtual void setParameter(int, float) {}
+ virtual float getParameter(unsigned long) { return 0.0; }
+ virtual void setParameter(unsigned long, float) {}
virtual int getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval);
};
diff --git a/muse/muse/ticksynth.cpp b/muse/muse/ticksynth.cpp
index 2cd0ae82..eb360c17 100644
--- a/muse/muse/ticksynth.cpp
+++ b/muse/muse/ticksynth.cpp
@@ -61,11 +61,14 @@ class MetronomeSynthIF : public SynthIF
MetronomeSynthIF(SynthI* s) : SynthIF(s) {
data = 0;
}
+ virtual bool initGui() { return true; };
+ virtual void guiHeartBeat() { }
virtual bool guiVisible() const { return false; }
virtual void showGui(bool) {}
virtual bool hasGui() const { return false; }
virtual void getGeometry(int*, int*, int*, int*) const {}
virtual void setGeometry(int, int, int, int) {}
+ virtual void preProcessAlways() { };
virtual iMPEvent getData(MidiPort*, MPEventList*, iMPEvent, unsigned pos, int ports, unsigned n, float** buffer);
virtual bool putEvent(const MidiPlayEvent& ev);
virtual MidiPlayEvent receiveEvent() { return MidiPlayEvent(); }
@@ -81,7 +84,8 @@ class MetronomeSynthIF : public SynthIF
virtual const char* getPatchName(int, int, MType, bool) { return ""; }
virtual void populatePatchPopup(QPopupMenu*, int, MType, bool) {};
virtual void write(int, Xml&) const {}
- virtual void setParameter(int, float) {}
+ virtual float getParameter(unsigned long) { return 0.0; }
+ virtual void setParameter(unsigned long, float) {}
virtual int getControllerInfo(int, const char**, int*, int*, int*, int*) { return 0; }
};
diff --git a/muse/muse/track.h b/muse/muse/track.h
index 9449fd1b..c18d806f 100644
--- a/muse/muse/track.h
+++ b/muse/muse/track.h
@@ -321,6 +321,7 @@ class AudioTrack : public Track {
void writeProperties(int, Xml&) const;
void mapRackPluginsToControllers();
+ void showPendingPluginNativeGuis();
//virtual AudioTrack* clone() const = 0;
virtual AudioTrack* clone(bool cloneParts) const = 0;
diff --git a/muse/muse/vst.cpp b/muse/muse/vst.cpp
index 194e1993..74e34efa 100644
--- a/muse/muse/vst.cpp
+++ b/muse/muse/vst.cpp
@@ -514,10 +514,19 @@ void VstSynthIF::deactivate3()
}
//---------------------------------------------------------
+// getParameter
+//---------------------------------------------------------
+
+float VstSynthIF::getParameter(unsigned long idx)
+ {
+ return _fst->plugin->getParameter(_fst->plugin, idx);
+ }
+
+//---------------------------------------------------------
// setParameter
//---------------------------------------------------------
-void VstSynthIF::setParameter(int idx, float value)
+void VstSynthIF::setParameter(unsigned long idx, float value)
{
_fst->plugin->setParameter(_fst->plugin, idx, value);
}
diff --git a/muse/muse/vst.h b/muse/muse/vst.h
index 33eaaab3..51eade15 100644
--- a/muse/muse/vst.h
+++ b/muse/muse/vst.h
@@ -50,11 +50,14 @@ class VstSynthIF : public SynthIF
_guiVisible = false;
}
+ virtual bool initGui() { return true; };
+ virtual void guiHeartBeat() { }
virtual bool guiVisible() const;
virtual void showGui(bool v);
virtual bool hasGui() const;
virtual void getGeometry(int*, int*, int*, int*) const {}
virtual void setGeometry(int, int, int, int) {}
+ virtual void preProcessAlways() { };
virtual iMPEvent getData(MidiPort*, MPEventList*, iMPEvent, unsigned pos, int ports, unsigned n, float** buffer) ;
virtual bool putEvent(const MidiPlayEvent& ev);
virtual MidiPlayEvent receiveEvent();
@@ -68,7 +71,8 @@ class VstSynthIF : public SynthIF
virtual const char* getPatchName(int, int, MType, bool) { return ""; }
virtual void populatePatchPopup(QPopupMenu*, int, MType, bool) {};
virtual void write(int level, Xml& xml) const;
- virtual void setParameter(int idx, float value);
+ virtual float getParameter(unsigned long idx);
+ virtual void setParameter(unsigned long idx, float value);
virtual int getControllerInfo(int, const char**, int*, int*, int*, int*) { return 0; }
};