changeset 75:163f3428bbe0

* Create temporary directory, cleaned up on exit, and use it to store (inter alia) audio samples for the sample-player plugin. * Ensure newly added layers always have unique names * Make sure configure pairs for real-time plugins are stored in the configuration Xml along with parameter & program settings
author Chris Cannam
date Mon, 10 Apr 2006 13:52:32 +0000
parents 47fd14e29813
children af2725b5d6fe
files base/ViewManager.cpp base/ViewManager.h plugin/DSSIPluginInstance.cpp plugin/PluginXml.cpp plugin/RealTimePluginInstance.h plugin/plugins/SamplePlayer.cpp plugin/plugins/SamplePlayer.h
diffstat 7 files changed, 201 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/base/ViewManager.cpp	Fri Apr 07 17:50:33 2006 +0000
+++ b/base/ViewManager.cpp	Mon Apr 10 13:52:32 2006 +0000
@@ -20,6 +20,11 @@
 
 #include <iostream>
 
+#include <QDir>
+#include <QFile>
+
+#include <cassert>
+
 // #define DEBUG_VIEW_MANAGER 1
 
 ViewManager::ViewManager() :
@@ -45,6 +50,11 @@
 	    SLOT(considerZoomChange(void *, unsigned long, bool)));
 }
 
+ViewManager::~ViewManager()
+{
+    if (m_tmpdir != "") deleteTemporaryDirectory(m_tmpdir);
+}
+
 unsigned long
 ViewManager::getGlobalCentreFrame() const
 {
@@ -351,6 +361,94 @@
     }
 }
 
+QString
+ViewManager::getTemporaryDirectory()
+{
+    if (m_tmpdir != "") return m_tmpdir;
+
+    // Generate a temporary directory.  Qt4.1 doesn't seem to be able
+    // to do this for us, and mkdtemp is not standard.  This method is
+    // based on the way glibc does mkdtemp.
+
+    static QString chars =
+        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+    QString suffix;
+    int padlen = 6, attempts = 100;
+    unsigned int r = time(0) ^ getpid();
+
+    for (int i = 0; i < padlen; ++i) {
+        suffix += "X";
+    }
+    
+    for (int j = 0; j < attempts; ++j) {
+
+        unsigned int v = r;
+        
+        for (int i = 0; i < padlen; ++i) {
+            suffix[i] = chars[v % 62];
+            v /= 62;
+        }
+
+        QString candidate = QString("sv_%1").arg(suffix);
+
+        if (QDir::temp().mkpath(candidate)) {
+            m_tmpdir = QDir::temp().filePath(candidate);
+            break;
+        }
+
+        r = r + 7777;
+    }
+
+    if (m_tmpdir == "") {
+        std::cerr << "ERROR: ViewManager::getTemporaryDirectory: "
+                  << "Unable to create a temporary directory!" << std::endl;
+        assert(0);
+    }
+
+    return m_tmpdir;
+}
+
+void
+ViewManager::deleteTemporaryDirectory(QString tmpdir)
+{
+    if (tmpdir == "") return;
+    
+    QDir dir(tmpdir);
+    dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
+
+    for (unsigned int i = 0; i < dir.count(); ++i) {
+
+        QFileInfo fi(dir.filePath(dir[i]));
+
+        if (fi.isDir()) {
+            deleteTemporaryDirectory(fi.absoluteFilePath());
+        } else {
+            if (!QFile(fi.absoluteFilePath()).remove()) {
+                std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: "
+                          << "Failed to unlink file \""
+                          << fi.absoluteFilePath().toStdString() << "\""
+                          << std::endl;
+            }
+        }
+    }
+
+    QString dirname = dir.dirName();
+    if (dirname != "") {
+        if (!dir.cdUp()) {
+            std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: "
+                      << "Failed to cd to parent directory of "
+                      << tmpdir.toStdString() << std::endl;
+            return;
+        }
+        if (!dir.rmdir(dirname)) {
+            std::cerr << "WARNING: ViewManager::deleteTemporaryDirectory: "
+                      << "Failed to remove directory "
+                      << dirname.toStdString() << std::endl;
+        } 
+    }
+}
+
 #ifdef INCLUDE_MOCFILES
 #include "ViewManager.moc.cpp"
 #endif
--- a/base/ViewManager.h	Fri Apr 07 17:50:33 2006 +0000
+++ b/base/ViewManager.h	Mon Apr 10 13:52:32 2006 +0000
@@ -43,6 +43,7 @@
 
 public:
     ViewManager();
+    virtual ~ViewManager();
 
     void setAudioPlaySource(AudioPlaySource *source);
 
@@ -104,6 +105,8 @@
     void setOverlayMode(OverlayMode mode);
     OverlayMode getOverlayMode() const { return m_overlayMode; }
 
+    QString getTemporaryDirectory();
+
 signals:
     /** Emitted when a widget pans.  The originator identifies the widget. */
     void centreFrameChanged(void *originator, unsigned long frame, bool locked);
@@ -181,6 +184,9 @@
     };
 
     OverlayMode m_overlayMode;
+
+    void deleteTemporaryDirectory(QString);
+    QString m_tmpdir;
 };
 
 #endif
--- a/plugin/DSSIPluginInstance.cpp	Fri Apr 07 17:50:33 2006 +0000
+++ b/plugin/DSSIPluginInstance.cpp	Mon Apr 10 13:52:32 2006 +0000
@@ -828,6 +828,8 @@
 
     m_programCacheValid = false;
 
+    m_configurationData[key] = value;
+
     std::string qm;
 
     // Ignore return values from reserved key configuration calls such
--- a/plugin/PluginXml.cpp	Fri Apr 07 17:50:33 2006 +0000
+++ b/plugin/PluginXml.cpp	Mon Apr 10 13:52:32 2006 +0000
@@ -24,6 +24,7 @@
 #include <QDomAttr>
 
 #include "vamp-sdk/PluginBase.h"
+#include "RealTimePluginInstance.h"
 
 #include <iostream>
 
@@ -63,6 +64,29 @@
             .arg(m_plugin->getParameter(i->name));
     }
 
+    RealTimePluginInstance *rtpi =
+        dynamic_cast<RealTimePluginInstance *>(m_plugin);
+    if (rtpi) {
+        std::map<std::string, std::string> configurePairs =
+            rtpi->getConfigurePairs();
+        QString config;
+        for (std::map<std::string, std::string>::iterator i = configurePairs.begin();
+             i != configurePairs.end(); ++i) {
+            QString key = i->first.c_str();
+            QString value = i->second.c_str();
+            key.replace(";", "[[SEMICOLON]]");
+            key.replace("=", "[[EQUALS]]");
+            value.replace(";", "[[SEMICOLON]]");
+            value.replace("=", "[[EQUALS]]");
+            if (config != "") config += ";";
+            config += QString("%1=%2").arg(key).arg(value);
+        }
+        if (config != "") {
+            s += QString("configuration=\"%1\" ")
+                .arg(encodeEntities(config));
+        }
+    }
+
     s += "/>\n";
     return s;
 }
@@ -90,6 +114,29 @@
         std::cerr << "WARNING: PluginXml::setParameters: Plugin version does not match (attributes have " << version << ", my version is " << m_plugin->getPluginVersion() << ")" << std::endl;
     }
 
+    RealTimePluginInstance *rtpi =
+        dynamic_cast<RealTimePluginInstance *>(m_plugin);
+    if (rtpi) {
+        QString config = attrs.value("configuration");
+        if (config != "") {
+            QStringList configList = config.split(";");
+            for (QStringList::iterator i = configList.begin();
+                 i != configList.end(); ++i) {
+                QStringList kv = i->split("=");
+                if (kv.count() < 2) {
+                    std::cerr << "WARNING: PluginXml::setParameters: Malformed configure pair string: \"" << i->toStdString() << "\"" << std::endl;
+                    continue;
+                }
+                QString key(kv[0]), value(kv[1]);
+                key.replace("[[SEMICOLON]]", ";");
+                key.replace("[[EQUALS]]", ";");
+                value.replace("[[SEMICOLON]]", ";");
+                value.replace("[[SEMICOLON]]", ";");
+                rtpi->configure(key.toStdString(), value.toStdString());
+            }
+        }
+    }
+
     if (!m_plugin->getPrograms().empty()) {
         m_plugin->selectProgram(attrs.value("program").toStdString());
     }
--- a/plugin/RealTimePluginInstance.h	Fri Apr 07 17:50:33 2006 +0000
+++ b/plugin/RealTimePluginInstance.h	Mon Apr 10 13:52:32 2006 +0000
@@ -28,6 +28,7 @@
 #include <QStringList>
 #include <vector>
 #include <string>
+#include <map>
 
 class RealTimePluginFactory;
 	
@@ -132,6 +133,10 @@
 
     virtual std::string getType() const { return "Real-Time Plugin"; }
 
+    virtual std::map<std::string, std::string> getConfigurePairs() {
+        return m_configurationData;
+    }
+
 protected:
     RealTimePluginInstance(RealTimePluginFactory *factory, QString identifier) :
 	m_factory(factory), m_identifier(identifier) { }
@@ -139,6 +144,8 @@
     RealTimePluginFactory *m_factory;
     QString m_identifier;
 
+    std::map<std::string, std::string> m_configurationData;
+
     friend class PluginFactory;
 };
 
--- a/plugin/plugins/SamplePlayer.cpp	Fri Apr 07 17:50:33 2006 +0000
+++ b/plugin/plugins/SamplePlayer.cpp	Mon Apr 10 13:52:32 2006 +0000
@@ -96,7 +96,7 @@
 {
     2, // DSSI API version
     &ladspaDescriptor,
-    0, // Configure
+    configure,
     getProgram,
     selectProgram,
     getMidiController,
@@ -128,6 +128,7 @@
     m_sampleCount(0),
     m_sampleRate(sampleRate),
     m_sampleNo(0),
+    m_samplePath("samples"),
     m_sampleSearchComplete(false),
     m_pendingProgramChange(-1)
 {
@@ -207,6 +208,28 @@
     delete (SamplePlayer *)handle;
 }
 
+char *
+SamplePlayer::configure(LADSPA_Handle handle, const char *key, const char *value)
+{
+    if (key && !strcmp(key, "samplepath")) {
+
+        SamplePlayer *player = (SamplePlayer *)handle;
+
+	QMutexLocker locker(&player->m_mutex);
+
+        player->m_samplePath = value;
+
+        if (player->m_sampleSearchComplete) {
+            player->m_sampleSearchComplete = false;
+            player->searchSamples();
+        }
+
+        return 0;
+    }
+
+    return strdup("Unknown configure key");
+}
+
 const DSSI_Program_Descriptor *
 SamplePlayer::getProgram(LADSPA_Handle handle, unsigned long program)
 {
@@ -317,22 +340,25 @@
 {
     if (m_sampleSearchComplete) return;
 
-    //!!!
-//    QString path = "/usr/share/hydrogen/data/drumkits/EasternHop-1";
-
     std::cerr << "Current working directory is \"" << getcwd(0, 0) << "\"" << std::endl;
 
-    QString path = "samples";
-    
     std::cerr << "SamplePlayer::searchSamples: Path is \""
-	      << path.toLocal8Bit().data() << "\"" << std::endl;
+	      << m_samplePath.toLocal8Bit().data() << "\"" << std::endl;
 
-    QDir dir(path, "*.wav");
-    for (unsigned int i = 0; i < dir.count(); ++i) {
-	QFileInfo file(dir.filePath(dir[i]));
-	m_samples.push_back(std::pair<QString, QString>
-			    (file.baseName(), file.filePath()));
-	std::cerr << "Found: " << dir[i].toLocal8Bit().data() << std::endl;
+    QStringList dirList = m_samplePath.split(QRegExp("[:;]"));
+
+    for (QStringList::iterator i = dirList.begin(); i != dirList.end(); ++i) {
+
+        QDir dir(*i, "*.wav");
+
+        for (unsigned int i = 0; i < dir.count(); ++i) {
+            QFileInfo file(dir.filePath(dir[i]));
+            if (file.isReadable()) {
+                m_samples.push_back(std::pair<QString, QString>
+                                    (file.baseName(), file.filePath()));
+                std::cerr << "Found: " << dir[i].toLocal8Bit().data() << std::endl;
+            }
+        }
     }
 
     m_sampleSearchComplete = true;
--- a/plugin/plugins/SamplePlayer.h	Fri Apr 07 17:50:33 2006 +0000
+++ b/plugin/plugins/SamplePlayer.h	Mon Apr 10 13:52:32 2006 +0000
@@ -62,6 +62,7 @@
     static void run(LADSPA_Handle, unsigned long);
     static void deactivate(LADSPA_Handle);
     static void cleanup(LADSPA_Handle);
+    static char *configure(LADSPA_Handle, const char *, const char *);
     static const DSSI_Program_Descriptor *getProgram(LADSPA_Handle, unsigned long);
     static void selectProgram(LADSPA_Handle, unsigned long, unsigned long);
     static int getMidiController(LADSPA_Handle, unsigned long);
@@ -90,6 +91,7 @@
     int m_velocities[Polyphony];
     long m_sampleNo;
 
+    QString m_samplePath;
     QString m_program;
     std::vector<std::pair<QString, QString> > m_samples; // program name, path
     bool m_sampleSearchComplete;