From 0fcb500389e91c0692f2b5fa9c95684b3416e254 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Fri, 1 Apr 2011 05:05:34 +0000 Subject: Initial support for custom LADSPA DSSI GUIs, such as those generated by FLAM. --- muse2/ChangeLog | 4 +++ muse2/muse/dssihost.cpp | 2 ++ muse2/muse/dssihost.h | 2 ++ muse2/muse/mixer/rack.cpp | 3 +- muse2/muse/osc.cpp | 85 +++++++++++++++++------------------------------ muse2/muse/osc.h | 2 +- muse2/muse/plugin.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++ muse2/muse/plugin.h | 10 ++++-- 8 files changed, 128 insertions(+), 59 deletions(-) diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 38047516..2d42c0d0 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,7 @@ +31.03.2011: + * Feature: Support for custom LADSPA DSSI GUIs, such as those generated by FLAM. (p4.0.19 Tim) + - Initial support. TODO: Refine how a particular UI file is chosen - uses first one found for now. + Also may need to support multiple choices if multiple lib-level and/or plugin-level UIs are found. 27.03.2011: - Fixed end/off-screen selections not being drawn in midi controller graphs. (Tim) - Reverted Midi Track Info ui layout more or less to pre- Mar 5, with some improvements. (Tim) diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp index 88ad0eed..2f434972 100644 --- a/muse2/muse/dssihost.cpp +++ b/muse2/muse/dssihost.cpp @@ -2967,6 +2967,8 @@ int DssiSynthIF::pluginID() { return (synth && int DssiSynthIF::id() { return 0; } // Synth is not part of a rack plugin chain. Always 0. QString DssiSynthIF::pluginLabel() const { return (synth && synth->dssi) ? QString(synth->dssi->LADSPA_Plugin->Label) : QString(); } QString DssiSynthIF::name() const { return synti->name(); } +QString DssiSynthIF::lib() const { return synth ? synth->completeBaseName() : QString(); } +QString DssiSynthIF::dirPath() const { return synth ? synth->absolutePath() : QString(); } AudioTrack* DssiSynthIF::track() { return (AudioTrack*)synti; } void DssiSynthIF::enableController(int i, bool v) { controls[i].enCtrl = v; } bool DssiSynthIF::controllerEnabled(int i) const { return controls[i].enCtrl; } diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h index c574a719..eab561a5 100644 --- a/muse2/muse/dssihost.h +++ b/muse2/muse/dssihost.h @@ -233,6 +233,8 @@ class DssiSynthIF : public SynthIF, public PluginIBase int id(); QString pluginLabel() const; QString name() const; + QString lib() const; + QString dirPath() const; AudioTrack* track(); void enableController(int /*i*/, bool v = true); bool controllerEnabled(int /*i*/) const; diff --git a/muse2/muse/mixer/rack.cpp b/muse2/muse/mixer/rack.cpp index 7cc5b077..daebaa30 100644 --- a/muse2/muse/mixer/rack.cpp +++ b/muse2/muse/mixer/rack.cpp @@ -224,7 +224,8 @@ void EffectRack::menuRequested(QListWidgetItem* it) upAction->setEnabled(true); if (idx == (PipelineDepth-1)) downAction->setEnabled(false); - if(!pipe->isDssiPlugin(idx)) + //if(!pipe->isDssiPlugin(idx)) + if(!pipe->has_dssi_ui(idx)) // p4.0.19 Tim. showNativeGuiAction->setEnabled(false); } diff --git a/muse2/muse/osc.cpp b/muse2/muse/osc.cpp index c5ff182d..8bfdfd68 100644 --- a/muse2/muse/osc.cpp +++ b/muse2/muse/osc.cpp @@ -830,7 +830,7 @@ void OscIF::oscSendConfigure(const char *key, const char *val) //bool OscIF::oscInitGui() bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QString& name, - const QString& label, const QString& filePath, const QString& dirPath) + const QString& label, const QString& filePath, const QString& guiPath) { // Are we already running? We don't want to allow another process do we... if((_oscGuiQProc != 0) && (_oscGuiQProc->state())) @@ -842,6 +842,12 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin return false; } + if(guiPath.isEmpty()) + { + fprintf(stderr, "OscIF::oscInitGui guiPath is empty\n"); + return false; + } + // // start gui // @@ -849,52 +855,13 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin //char oscUrl[1024]; QString oscUrl; - /* - QString typ; - QString baseName; - QString name; - QString label; - QString filePath; - QString dirPath; - #ifdef DSSI_SUPPORT - if(_oscSynthIF) - { - //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()); - typ = QT_TRANSLATE_NOOP("@default", "dssi_synth"); - baseName = _oscSynthIF->dssiSynth()->baseName(false); - label = _oscSynthIF->dssiSynthI()->name(); - name = _oscSynthIF->dssiSynth()->name(); - - dirPath = _oscSynthIF->dssiSynth()->dirPath(false); - filePath = _oscSynthIF->dssiSynth()->filePath(); - } - else - #endif - if(_oscPluginI) - { - typ = QT_TRANSLATE_NOOP("@default", "ladspa_efx"); - baseName = _oscPluginI->plugin()->lib(false); - //name = _oscPluginI->name(); - name = _oscPluginI->plugin()->label(); - label = _oscPluginI->label(); - - dirPath = _oscPluginI->plugin()->dirPath(false); - //dirPath.replace("ladspa", "dssi", true); - - filePath = _oscPluginI->plugin()->filePath(); - //filePath.replace("ladspa", "dssi", true); - } - else - return false; - */ - //snprintf(oscUrl, 1024, "%s/%s/%s", url, baseName.ascii(), name.ascii()); //snprintf(oscUrl, 1024, "%s%s/%s/%s", url, typ.toLatin1().constData(), baseName.toLatin1().constData(), name.toLatin1().constData()); //oscUrl = QString("%1%2/%3/%4").arg(QString(QT_TRANSLATE_NOOP("@default", url))).arg(typ).arg(baseName).arg(name); oscUrl = QString("%1%2/%3/%4").arg(QString(QT_TRANSLATE_NOOP("@default", url))).arg(typ).arg(baseName).arg(label); + // Removed p4.0.19 Tim + /* //QString guiPath(info.path() + "/" + info.baseName()); //QString guiPath(synth->info.dirPath() + "/" + synth->info.baseName()); QString guiPath(dirPath + "/" + baseName); @@ -944,20 +911,23 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin //synth->name().ascii()); name.toLatin1().constData()); #endif + */ - if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) && - (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) - { + //if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) && + // (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + //{ + // Changed by T356. // fork + execlp were causing the processes to remain after closing gui, requiring manual kill. // Changed to QProcess, works OK now. //if((guiPid = fork()) == 0) - { + //{ // No QProcess created yet? Do it now. Only once per SynthIF instance. Exists until parent destroyed. if(_oscGuiQProc == 0) _oscGuiQProc = new QProcess(muse); - QString program(fi.filePath()); + //QString program(fi.filePath()); + QString program(guiPath); QStringList arguments; arguments << oscUrl << filePath @@ -1012,11 +982,12 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin "channel 1", (void*)0); */ - fprintf(stderr, "exec %s %s %s %s failed: %s\n", + fprintf(stderr, "exec %s %s %s failed: %s\n", //fi.filePath().toAscii().data(), //fi.fileName().toAscii().data(), - fi.filePath().toLatin1().constData(), - fi.fileName().toLatin1().constData(), + //fi.filePath().toLatin1().constData(), + guiPath.toLatin1().constData(), + //fi.fileName().toLatin1().constData(), oscUrl.toLatin1().constData(), @@ -1035,10 +1006,11 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin #ifdef OSC_DEBUG fprintf(stderr, "OscIF::oscInitGui after QProcess\n"); #endif - } - } - } + //} + //} + //} //synth->_hasGui = true; + /* } else { printf("OscIF::oscInitGui %s: no dir for gui found: %s\n", @@ -1048,6 +1020,7 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin //synth->_hasGui = false; } + */ return true; } @@ -1305,7 +1278,8 @@ bool OscDssiIF::oscInitGui() return OscIF::oscInitGui(QT_TRANSLATE_NOOP("@default", "dssi_synth"), _oscSynthIF->dssiSynth()->baseName(), _oscSynthIF->dssiSynth()->name(), _oscSynthIF->dssiSynthI()->name(), - _oscSynthIF->dssiSynth()->filePath(), _oscSynthIF->dssiSynth()->path()); + //_oscSynthIF->dssiSynth()->filePath(), _oscSynthIF->dssiSynth()->path()); + _oscSynthIF->dssiSynth()->filePath(), _oscSynthIF->dssi_ui_filename()); // p4.0.19 } #endif // DSSI_SUPPORT @@ -1391,7 +1365,8 @@ bool OscEffectIF::oscInitGui() return OscIF::oscInitGui(QT_TRANSLATE_NOOP("@default", "ladspa_efx"), _oscPluginI->plugin()->lib(false), _oscPluginI->plugin()->label(), _oscPluginI->label(), - _oscPluginI->plugin()->filePath(), _oscPluginI->plugin()->dirPath(false)); + //_oscPluginI->plugin()->filePath(), _oscPluginI->plugin()->dirPath(false)); + _oscPluginI->plugin()->filePath(), _oscPluginI->dssi_ui_filename()); // p4.0.19 } diff --git a/muse2/muse/osc.h b/muse2/muse/osc.h index 7d9afa92..ea94451b 100644 --- a/muse2/muse/osc.h +++ b/muse2/muse/osc.h @@ -140,7 +140,7 @@ class OscIF OscControlFifo* _oscControlFifos; virtual bool oscInitGui(const QString& /*typ*/, const QString& /*baseName*/, const QString& /*name*/, - const QString& /*label*/, const QString& /*filePath*/, const QString& /*dirPath*/); + const QString& /*label*/, const QString& /*filePath*/, const QString& /*guiPath*/); public: OscIF(); diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp index 428afd24..88f73784 100644 --- a/muse2/muse/plugin.cpp +++ b/muse2/muse/plugin.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -1304,6 +1305,33 @@ bool Pipeline::isDssiPlugin(int idx) const return false; } +/* +//--------------------------------------------------------- +// dssi_ui_filename +//--------------------------------------------------------- + +QString dssi_ui_filename(int idx) const +{ + PluginI* p = (*this)[idx]; + if(p) + return p->dssi_ui_filename(); + + return QString(); +} +*/ + +//--------------------------------------------------------- +// has_dssi_ui +//--------------------------------------------------------- + +bool Pipeline::has_dssi_ui(int idx) const +{ + PluginI* p = (*this)[idx]; + if(p) + return !p->dssi_ui_filename().isEmpty(); + + return false; +} //--------------------------------------------------------- // showGui //--------------------------------------------------------- @@ -1432,6 +1460,57 @@ void Pipeline::apply(int ports, unsigned long nframes, float** buffer1) } +//--------------------------------------------------------- +// PluginIBase +//--------------------------------------------------------- + +QString PluginIBase::dssi_ui_filename() const +{ + //QString guiPath(info.path() + "/" + info.baseName()); + //QString guiPath(synth->info.dirPath() + "/" + synth->info.baseName()); + if(dirPath().isEmpty() || lib().isEmpty()) + return QString(); + + QString guiPath(dirPath() + "/" + lib()); + + //fprintf(stderr, "PluginIBase::dssi_ui_filename :%s\n", guiPath.toLatin1().constData()); + + QDir guiDir(guiPath, "*", QDir::Unsorted, QDir::Files); + if(!guiDir.exists()) + return QString(); + + QStringList list = guiDir.entryList(); + + for(int i = 0; i < list.count(); ++i) + { + QFileInfo fi(guiPath + QString("/") + list[i]); + QString gui(fi.filePath()); + if (gui.contains('_') == 0) + continue; + struct stat buf; + + if(stat(gui.toLatin1().constData(), &buf)) + { + + //perror("stat failed"); + //fprintf(stderr, "PluginIBase::dssi_ui_filename stat failed\n"); + continue; + } + + if (!((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) && + (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))) + { + //perror("stat failed"); + //fprintf(stderr, "PluginIBase::dssi_ui_filename File stat mode is wrong\n"); + continue; + } + + return gui; + } + + return QString(); +}; + //--------------------------------------------------------- // PluginI //--------------------------------------------------------- diff --git a/muse2/muse/plugin.h b/muse2/muse/plugin.h index 031eb566..8f31e573 100644 --- a/muse2/muse/plugin.h +++ b/muse2/muse/plugin.h @@ -288,22 +288,25 @@ class PluginIBase virtual int id() = 0; virtual QString pluginLabel() const = 0; virtual QString name() const = 0; + virtual QString lib() const = 0; + virtual QString dirPath() const = 0; virtual AudioTrack* track() = 0; - virtual void enableController(int /*i*/, bool v = true) = 0; + virtual void enableController(int /*i*/, bool /*v*/ = true) = 0; virtual bool controllerEnabled(int /*i*/) const = 0; virtual bool controllerEnabled2(int /*i*/) const = 0; virtual void updateControllers() = 0; virtual void writeConfiguration(int /*level*/, Xml& /*xml*/) = 0; - virtual bool readConfiguration(Xml& /*xml*/, bool readPreset=false) = 0; + virtual bool readConfiguration(Xml& /*xml*/, bool /*readPreset*/=false) = 0; virtual int parameters() const = 0; virtual void setParam(int /*i*/, double /*val*/) = 0; virtual double param(int /*i*/) const = 0; virtual const char* paramName(int /*i*/) = 0; virtual LADSPA_PortRangeHint range(int /*i*/) = 0; + QString dssi_ui_filename() const; }; //--------------------------------------------------------- @@ -430,6 +433,7 @@ class PluginI : public PluginIBase { QString name() const { return _name; } CtrlValueType valueType() const; QString lib() const { return _plugin->lib(); } + QString dirPath() const { return _plugin->dirPath(); } #ifdef OSC_SUPPORT OscEffectIF& oscIF() { return _oscif; } @@ -502,6 +506,8 @@ class Pipeline : public std::vector { QString name(int idx) const; void showGui(int, bool); bool isDssiPlugin(int) const; + //QString dssi_ui_filename(int) const; + bool has_dssi_ui(int idx) const; void showNativeGui(int, bool); void deleteGui(int idx); void deleteAllGuis(); -- cgit v1.2.3