# HG changeset patch # User Chris Cannam # Date 1154347425 0 # Node ID 3e4c384f518e1b174ea5d38091c4978ca75bfac7 # Parent 1a42221a1522b96fc5f96c800d9e941cb0170dd0 * Reorganising code base. This revision will not compile. diff -r 1a42221a1522 -r 3e4c384f518e base/ConfigFile.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ConfigFile.cpp Mon Jul 31 12:03:45 2006 +0000 @@ -0,0 +1,181 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "ConfigFile.h" + +#include "base/Exceptions.h" + +#include + +#include +#include +#include +#include + +ConfigFile::ConfigFile(QString filename) : + m_filename(filename), + m_loaded(false), + m_modified(false) +{ +} + +ConfigFile::~ConfigFile() +{ + try { + commit(); + } catch (FileOperationFailed f) { + std::cerr << "WARNING: ConfigFile::~ConfigFile: Commit failed for " + << m_filename.toStdString() << std::endl; + } +} + +QString +ConfigFile::get(QString key, QString deft) +{ + if (!m_loaded) load(); + + QMutexLocker locker(&m_mutex); + + if (m_data.find(key) == m_data.end()) return deft; + return m_data[key]; +} + +int +ConfigFile::getInt(QString key, int deft) +{ + return get(key, QString("%1").arg(deft)).toInt(); +} + +bool +ConfigFile::getBool(QString key, bool deft) +{ + QString value = get(key, deft ? "true" : "false").trimmed().toLower(); + return (value == "true" || value == "yes" || value == "on" || value == "1"); +} + +float +ConfigFile::getFloat(QString key, float deft) +{ + return get(key, QString("%1").arg(deft)).toFloat(); +} + +QStringList +ConfigFile::getStringList(QString key) +{ + return get(key).split('|'); +} + +void +ConfigFile::set(QString key, QString value) +{ + if (!m_loaded) load(); + + QMutexLocker locker(&m_mutex); + + m_data[key] = value; + + m_modified = true; +} + +void +ConfigFile::set(QString key, int value) +{ + set(key, QString("%1").arg(value)); +} + +void +ConfigFile::set(QString key, bool value) +{ + set(key, value ? QString("true") : QString("false")); +} + +void +ConfigFile::set(QString key, float value) +{ + set(key, QString("%1").arg(value)); +} + +void +ConfigFile::set(QString key, const QStringList &values) +{ + set(key, values.join("|")); +} + +void +ConfigFile::commit() +{ + QMutexLocker locker(&m_mutex); + + if (!m_modified) return; + + // Really we should write to another file and then move to the + // intended target, but I don't think we're all that particular + // about reliability here at the moment + + QFile file(m_filename); + + if (!file.open(QFile::WriteOnly | QFile::Text)) { + throw FileOperationFailed(m_filename, "open for writing"); + } + + QTextStream out(&file); + + for (DataMap::const_iterator i = m_data.begin(); i != m_data.end(); ++i) { + out << i->first << "=" << i->second << endl; + } + + m_modified = false; +} + +bool +ConfigFile::load() +{ + QMutexLocker locker(&m_mutex); + + if (m_loaded) return true; + + QFile file(m_filename); + + if (!file.open(QFile::ReadOnly | QFile::Text)) { + return false; + } + + QTextStream in(&file); + + m_data.clear(); + + while (!in.atEnd()) { + + QString line = in.readLine(2048); + QString key = line.section('=', 0, 0); + QString value = line.section('=', 1, -1); + if (key == "") continue; + + m_data[key] = value; + } + + m_loaded = true; + m_modified = false; + return true; +} + +void +ConfigFile::reset() +{ + QMutexLocker locker(&m_mutex); + m_loaded = false; + m_modified = false; +} + diff -r 1a42221a1522 -r 3e4c384f518e base/ConfigFile.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ConfigFile.h Mon Jul 31 12:03:45 2006 +0000 @@ -0,0 +1,89 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _CONFIG_FILE_H_ +#define _CONFIG_FILE_H_ + +#include +#include + +#include + +class ConfigFile +{ +public: + ConfigFile(QString filename); + virtual ~ConfigFile(); + + /** + * Get a value, with a default if it hasn't been set. + */ + QString get(QString key, QString deft = ""); + + bool getBool(QString key, bool deft); + + int getInt(QString key, int deft); + + float getFloat(QString key, float deft); + + QStringList getStringList(QString key); + + /** + * Set a value. Values must not contain carriage return or other + * non-printable characters. Keys must contain [a-zA-Z0-9_-] only. + */ + void set(QString key, QString value); + + void set(QString key, bool value); + + void set(QString key, int value); + + void set(QString key, float value); + + void set(QString key, const QStringList &values); // must not contain '|' + + /** + * Write the data to file. May throw FileOperationFailed. + * + * This is called automatically on destruction if any data has + * changed since it was last called. At that time, any exception + * will be ignored. If you want to ensure that exceptions are + * handled, call it yourself before destruction. + */ + void commit(); + + /** + * Return to the stored values. You can also call this before + * destruction if you want to ensure that any values modified so + * far are not written out to file on destruction. + */ + void reset(); + +protected: + bool load(); + + QString m_filename; + + typedef std::map DataMap; + DataMap m_data; + + bool m_loaded; + bool m_modified; + + QMutex m_mutex; +}; + +#endif + diff -r 1a42221a1522 -r 3e4c384f518e base/RecentFiles.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/RecentFiles.cpp Mon Jul 31 12:03:45 2006 +0000 @@ -0,0 +1,123 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "RecentFiles.h" +#include "ConfigFile.h" + +#include "base/Preferences.h" + +#include + +RecentFiles * +RecentFiles::m_instance = 0; + +RecentFiles * +RecentFiles::getInstance(int maxFileCount) +{ + if (!m_instance) { + m_instance = new RecentFiles(maxFileCount); + } + return m_instance; +} + +RecentFiles::RecentFiles(int maxFileCount) : + m_maxFileCount(maxFileCount) +{ + readFiles(); +} + +RecentFiles::~RecentFiles() +{ + // nothing +} + +void +RecentFiles::readFiles() +{ + m_files.clear(); + ConfigFile *cf = Preferences::getInstance()->getConfigFile(); + for (unsigned int i = 0; i < 100; ++i) { + QString key = QString("recent-file-%1").arg(i); + QString filename = cf->get(key); + if (filename == "") break; + if (i < m_maxFileCount) m_files.push_back(filename); + else cf->set(key, ""); + } + cf->commit(); +} + +void +RecentFiles::writeFiles() +{ + ConfigFile *cf = Preferences::getInstance()->getConfigFile(); + for (unsigned int i = 0; i < m_maxFileCount; ++i) { + QString key = QString("recent-file-%1").arg(i); + QString filename = ""; + if (i < m_files.size()) filename = m_files[i]; + cf->set(key, filename); + } + cf->commit(); +} + +void +RecentFiles::truncateAndWrite() +{ + while (m_files.size() > m_maxFileCount) { + m_files.pop_back(); + } + writeFiles(); +} + +std::vector +RecentFiles::getRecentFiles() const +{ + std::vector files; + for (unsigned int i = 0; i < m_maxFileCount; ++i) { + if (i < m_files.size()) { + files.push_back(m_files[i]); + } + } + return files; +} + +void +RecentFiles::addFile(QString filename) +{ + filename = QFileInfo(filename).absoluteFilePath(); + + bool have = false; + for (unsigned int i = 0; i < m_files.size(); ++i) { + if (m_files[i] == filename) { + have = true; + break; + } + } + + if (!have) { + m_files.push_front(filename); + } else { + std::deque newfiles; + newfiles.push_back(filename); + for (unsigned int i = 0; i < m_files.size(); ++i) { + if (m_files[i] == filename) continue; + newfiles.push_back(m_files[i]); + } + } + + truncateAndWrite(); + emit recentFilesChanged(); +} + + diff -r 1a42221a1522 -r 3e4c384f518e base/RecentFiles.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/RecentFiles.h Mon Jul 31 12:03:45 2006 +0000 @@ -0,0 +1,56 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RECENT_FILES_H_ +#define _RECENT_FILES_H_ + +#include +#include +#include +#include + +class RecentFiles : public QObject +{ + Q_OBJECT + +public: + // The maxFileCount argument will only be used the first time this is called + static RecentFiles *getInstance(int maxFileCount = 10); + + virtual ~RecentFiles(); + + int getMaxFileCount() const { return m_maxFileCount; } + + std::vector getRecentFiles() const; + + void addFile(QString filename); + +signals: + void recentFilesChanged(); + +protected: + RecentFiles(int maxFileCount); + + int m_maxFileCount; + std::deque m_files; + + void readFiles(); + void writeFiles(); + void truncateAndWrite(); + + static RecentFiles *m_instance; +}; + +#endif diff -r 1a42221a1522 -r 3e4c384f518e data/fileio/ConfigFile.cpp --- a/data/fileio/ConfigFile.cpp Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "ConfigFile.h" - -#include "base/Exceptions.h" - -#include - -#include -#include -#include -#include - -ConfigFile::ConfigFile(QString filename) : - m_filename(filename), - m_loaded(false), - m_modified(false) -{ -} - -ConfigFile::~ConfigFile() -{ - try { - commit(); - } catch (FileOperationFailed f) { - std::cerr << "WARNING: ConfigFile::~ConfigFile: Commit failed for " - << m_filename.toStdString() << std::endl; - } -} - -QString -ConfigFile::get(QString key, QString deft) -{ - if (!m_loaded) load(); - - QMutexLocker locker(&m_mutex); - - if (m_data.find(key) == m_data.end()) return deft; - return m_data[key]; -} - -int -ConfigFile::getInt(QString key, int deft) -{ - return get(key, QString("%1").arg(deft)).toInt(); -} - -bool -ConfigFile::getBool(QString key, bool deft) -{ - QString value = get(key, deft ? "true" : "false").trimmed().toLower(); - return (value == "true" || value == "yes" || value == "on" || value == "1"); -} - -float -ConfigFile::getFloat(QString key, float deft) -{ - return get(key, QString("%1").arg(deft)).toFloat(); -} - -QStringList -ConfigFile::getStringList(QString key) -{ - return get(key).split('|'); -} - -void -ConfigFile::set(QString key, QString value) -{ - if (!m_loaded) load(); - - QMutexLocker locker(&m_mutex); - - m_data[key] = value; - - m_modified = true; -} - -void -ConfigFile::set(QString key, int value) -{ - set(key, QString("%1").arg(value)); -} - -void -ConfigFile::set(QString key, bool value) -{ - set(key, value ? QString("true") : QString("false")); -} - -void -ConfigFile::set(QString key, float value) -{ - set(key, QString("%1").arg(value)); -} - -void -ConfigFile::set(QString key, const QStringList &values) -{ - set(key, values.join("|")); -} - -void -ConfigFile::commit() -{ - QMutexLocker locker(&m_mutex); - - if (!m_modified) return; - - // Really we should write to another file and then move to the - // intended target, but I don't think we're all that particular - // about reliability here at the moment - - QFile file(m_filename); - - if (!file.open(QFile::WriteOnly | QFile::Text)) { - throw FileOperationFailed(m_filename, "open for writing"); - } - - QTextStream out(&file); - - for (DataMap::const_iterator i = m_data.begin(); i != m_data.end(); ++i) { - out << i->first << "=" << i->second << endl; - } - - m_modified = false; -} - -bool -ConfigFile::load() -{ - QMutexLocker locker(&m_mutex); - - if (m_loaded) return true; - - QFile file(m_filename); - - if (!file.open(QFile::ReadOnly | QFile::Text)) { - return false; - } - - QTextStream in(&file); - - m_data.clear(); - - while (!in.atEnd()) { - - QString line = in.readLine(2048); - QString key = line.section('=', 0, 0); - QString value = line.section('=', 1, -1); - if (key == "") continue; - - m_data[key] = value; - } - - m_loaded = true; - m_modified = false; - return true; -} - -void -ConfigFile::reset() -{ - QMutexLocker locker(&m_mutex); - m_loaded = false; - m_modified = false; -} - diff -r 1a42221a1522 -r 3e4c384f518e data/fileio/ConfigFile.h --- a/data/fileio/ConfigFile.h Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _CONFIG_FILE_H_ -#define _CONFIG_FILE_H_ - -#include -#include - -#include - -class ConfigFile -{ -public: - ConfigFile(QString filename); - virtual ~ConfigFile(); - - /** - * Get a value, with a default if it hasn't been set. - */ - QString get(QString key, QString deft = ""); - - bool getBool(QString key, bool deft); - - int getInt(QString key, int deft); - - float getFloat(QString key, float deft); - - QStringList getStringList(QString key); - - /** - * Set a value. Values must not contain carriage return or other - * non-printable characters. Keys must contain [a-zA-Z0-9_-] only. - */ - void set(QString key, QString value); - - void set(QString key, bool value); - - void set(QString key, int value); - - void set(QString key, float value); - - void set(QString key, const QStringList &values); // must not contain '|' - - /** - * Write the data to file. May throw FileOperationFailed. - * - * This is called automatically on destruction if any data has - * changed since it was last called. At that time, any exception - * will be ignored. If you want to ensure that exceptions are - * handled, call it yourself before destruction. - */ - void commit(); - - /** - * Return to the stored values. You can also call this before - * destruction if you want to ensure that any values modified so - * far are not written out to file on destruction. - */ - void reset(); - -protected: - bool load(); - - QString m_filename; - - typedef std::map DataMap; - DataMap m_data; - - bool m_loaded; - bool m_modified; - - QMutex m_mutex; -}; - -#endif - diff -r 1a42221a1522 -r 3e4c384f518e data/fileio/RecentFiles.cpp --- a/data/fileio/RecentFiles.cpp Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "RecentFiles.h" -#include "ConfigFile.h" - -#include "base/Preferences.h" - -#include - -RecentFiles * -RecentFiles::m_instance = 0; - -RecentFiles * -RecentFiles::getInstance(int maxFileCount) -{ - if (!m_instance) { - m_instance = new RecentFiles(maxFileCount); - } - return m_instance; -} - -RecentFiles::RecentFiles(int maxFileCount) : - m_maxFileCount(maxFileCount) -{ - readFiles(); -} - -RecentFiles::~RecentFiles() -{ - // nothing -} - -void -RecentFiles::readFiles() -{ - m_files.clear(); - ConfigFile *cf = Preferences::getInstance()->getConfigFile(); - for (unsigned int i = 0; i < 100; ++i) { - QString key = QString("recent-file-%1").arg(i); - QString filename = cf->get(key); - if (filename == "") break; - if (i < m_maxFileCount) m_files.push_back(filename); - else cf->set(key, ""); - } - cf->commit(); -} - -void -RecentFiles::writeFiles() -{ - ConfigFile *cf = Preferences::getInstance()->getConfigFile(); - for (unsigned int i = 0; i < m_maxFileCount; ++i) { - QString key = QString("recent-file-%1").arg(i); - QString filename = ""; - if (i < m_files.size()) filename = m_files[i]; - cf->set(key, filename); - } - cf->commit(); -} - -void -RecentFiles::truncateAndWrite() -{ - while (m_files.size() > m_maxFileCount) { - m_files.pop_back(); - } - writeFiles(); -} - -std::vector -RecentFiles::getRecentFiles() const -{ - std::vector files; - for (unsigned int i = 0; i < m_maxFileCount; ++i) { - if (i < m_files.size()) { - files.push_back(m_files[i]); - } - } - return files; -} - -void -RecentFiles::addFile(QString filename) -{ - filename = QFileInfo(filename).absoluteFilePath(); - - bool have = false; - for (unsigned int i = 0; i < m_files.size(); ++i) { - if (m_files[i] == filename) { - have = true; - break; - } - } - - if (!have) { - m_files.push_front(filename); - } else { - std::deque newfiles; - newfiles.push_back(filename); - for (unsigned int i = 0; i < m_files.size(); ++i) { - if (m_files[i] == filename) continue; - newfiles.push_back(m_files[i]); - } - } - - truncateAndWrite(); - emit recentFilesChanged(); -} - - diff -r 1a42221a1522 -r 3e4c384f518e data/fileio/RecentFiles.h --- a/data/fileio/RecentFiles.h Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _RECENT_FILES_H_ -#define _RECENT_FILES_H_ - -#include -#include -#include -#include - -class RecentFiles : public QObject -{ - Q_OBJECT - -public: - // The maxFileCount argument will only be used the first time this is called - static RecentFiles *getInstance(int maxFileCount = 10); - - virtual ~RecentFiles(); - - int getMaxFileCount() const { return m_maxFileCount; } - - std::vector getRecentFiles() const; - - void addFile(QString filename); - -signals: - void recentFilesChanged(); - -protected: - RecentFiles(int maxFileCount); - - int m_maxFileCount; - std::deque m_files; - - void readFiles(); - void writeFiles(); - void truncateAndWrite(); - - static RecentFiles *m_instance; -}; - -#endif diff -r 1a42221a1522 -r 3e4c384f518e transform/FeatureExtractionPluginTransform.cpp --- a/transform/FeatureExtractionPluginTransform.cpp Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,494 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "FeatureExtractionPluginTransform.h" - -#include "plugin/FeatureExtractionPluginFactory.h" -#include "plugin/PluginXml.h" -#include "vamp-sdk/Plugin.h" - -#include "base/Model.h" -#include "base/Window.h" -#include "model/SparseOneDimensionalModel.h" -#include "model/SparseTimeValueModel.h" -#include "model/DenseThreeDimensionalModel.h" -#include "model/DenseTimeValueModel.h" -#include "model/NoteModel.h" -#include "fileio/FFTFuzzyAdapter.h" - -#include - -#include - -FeatureExtractionPluginTransform::FeatureExtractionPluginTransform(Model *inputModel, - QString pluginId, - int channel, - QString configurationXml, - QString outputName) : - Transform(inputModel), - m_plugin(0), - m_channel(channel), - m_stepSize(0), - m_blockSize(0), - m_descriptor(0), - m_outputFeatureNo(0) -{ -// std::cerr << "FeatureExtractionPluginTransform::FeatureExtractionPluginTransform: plugin " << pluginId.toStdString() << ", outputName " << outputName.toStdString() << std::endl; - - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); - - if (!factory) { - std::cerr << "FeatureExtractionPluginTransform: No factory available for plugin id \"" - << pluginId.toStdString() << "\"" << std::endl; - return; - } - - m_plugin = factory->instantiatePlugin(pluginId, m_input->getSampleRate()); - - if (!m_plugin) { - std::cerr << "FeatureExtractionPluginTransform: Failed to instantiate plugin \"" - << pluginId.toStdString() << "\"" << std::endl; - return; - } - - if (configurationXml != "") { - PluginXml(m_plugin).setParametersFromXml(configurationXml); - } - - m_blockSize = m_plugin->getPreferredBlockSize(); - m_stepSize = m_plugin->getPreferredStepSize(); - - if (m_blockSize == 0) m_blockSize = 1024; //!!! todo: ask user - if (m_stepSize == 0) m_stepSize = m_blockSize; //!!! likewise - - DenseTimeValueModel *input = getInput(); - if (!input) return; - - size_t channelCount = input->getChannelCount(); - if (m_plugin->getMaxChannelCount() < channelCount) { - channelCount = 1; - } - if (m_plugin->getMinChannelCount() > channelCount) { - std::cerr << "FeatureExtractionPluginTransform:: " - << "Can't provide enough channels to plugin (plugin min " - << m_plugin->getMinChannelCount() << ", max " - << m_plugin->getMaxChannelCount() << ", input model has " - << input->getChannelCount() << ")" << std::endl; - return; - } - - if (!m_plugin->initialise(channelCount, m_stepSize, m_blockSize)) { - std::cerr << "FeatureExtractionPluginTransform: Plugin " - << m_plugin->getName() << " failed to initialise!" << std::endl; - return; - } - - Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors(); - - if (outputs.empty()) { - std::cerr << "FeatureExtractionPluginTransform: Plugin \"" - << pluginId.toStdString() << "\" has no outputs" << std::endl; - return; - } - - for (size_t i = 0; i < outputs.size(); ++i) { - if (outputName == "" || outputs[i].name == outputName.toStdString()) { - m_outputFeatureNo = i; - m_descriptor = new Vamp::Plugin::OutputDescriptor - (outputs[i]); - break; - } - } - - if (!m_descriptor) { - std::cerr << "FeatureExtractionPluginTransform: Plugin \"" - << pluginId.toStdString() << "\" has no output named \"" - << outputName.toStdString() << "\"" << std::endl; - return; - } - -// std::cerr << "FeatureExtractionPluginTransform: output sample type " -// << m_descriptor->sampleType << std::endl; - - int binCount = 1; - float minValue = 0.0, maxValue = 0.0; - - if (m_descriptor->hasFixedBinCount) { - binCount = m_descriptor->binCount; - } - -// std::cerr << "FeatureExtractionPluginTransform: output bin count " -// << binCount << std::endl; - - if (binCount > 0 && m_descriptor->hasKnownExtents) { - minValue = m_descriptor->minValue; - maxValue = m_descriptor->maxValue; - } - - size_t modelRate = m_input->getSampleRate(); - size_t modelResolution = 1; - - switch (m_descriptor->sampleType) { - - case Vamp::Plugin::OutputDescriptor::VariableSampleRate: - if (m_descriptor->sampleRate != 0.0) { - modelResolution = size_t(modelRate / m_descriptor->sampleRate + 0.001); - } - break; - - case Vamp::Plugin::OutputDescriptor::OneSamplePerStep: - modelResolution = m_stepSize; - break; - - case Vamp::Plugin::OutputDescriptor::FixedSampleRate: - modelRate = size_t(m_descriptor->sampleRate + 0.001); - break; - } - - if (binCount == 0) { - - m_output = new SparseOneDimensionalModel(modelRate, modelResolution, - false); - - } else if (binCount == 1) { - - SparseTimeValueModel *model = new SparseTimeValueModel - (modelRate, modelResolution, minValue, maxValue, false); - model->setScaleUnits(outputs[m_outputFeatureNo].unit.c_str()); - - m_output = model; - - } else if (m_descriptor->sampleType == - Vamp::Plugin::OutputDescriptor::VariableSampleRate) { - - // We don't have a sparse 3D model, so interpret this as a - // note model. There's nothing to define which values to use - // as which parameters of the note -- for the moment let's - // treat the first as pitch, second as duration in frames, - // third (if present) as velocity. (Our note model doesn't - // yet store velocity.) - //!!! todo: ask the user! - - NoteModel *model = new NoteModel - (modelRate, modelResolution, minValue, maxValue, false); - model->setScaleUnits(outputs[m_outputFeatureNo].unit.c_str()); - - m_output = model; - - } else { - - m_output = new DenseThreeDimensionalModel(modelRate, modelResolution, - binCount, false); - - if (!m_descriptor->binNames.empty()) { - std::vector names; - for (size_t i = 0; i < m_descriptor->binNames.size(); ++i) { - names.push_back(m_descriptor->binNames[i].c_str()); - } - (dynamic_cast(m_output)) - ->setBinNames(names); - } - } -} - -FeatureExtractionPluginTransform::~FeatureExtractionPluginTransform() -{ - delete m_plugin; - delete m_descriptor; -} - -DenseTimeValueModel * -FeatureExtractionPluginTransform::getInput() -{ - DenseTimeValueModel *dtvm = - dynamic_cast(getInputModel()); - if (!dtvm) { - std::cerr << "FeatureExtractionPluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; - } - return dtvm; -} - -void -FeatureExtractionPluginTransform::run() -{ - DenseTimeValueModel *input = getInput(); - if (!input) return; - - if (!m_output) return; - - size_t sampleRate = m_input->getSampleRate(); - - size_t channelCount = input->getChannelCount(); - if (m_plugin->getMaxChannelCount() < channelCount) { - channelCount = 1; - } - - float **buffers = new float*[channelCount]; - for (size_t ch = 0; ch < channelCount; ++ch) { - buffers[ch] = new float[m_blockSize]; - } - - bool frequencyDomain = (m_plugin->getInputDomain() == - Vamp::Plugin::FrequencyDomain); - std::vector fftAdapters; - - if (frequencyDomain) { - for (size_t ch = 0; ch < channelCount; ++ch) { - fftAdapters.push_back(new FFTFuzzyAdapter - (getInput(), - channelCount == 1 ? m_channel : ch, - HanningWindow, - m_blockSize, - m_stepSize, - m_blockSize, - false)); - } - } - - long startFrame = m_input->getStartFrame(); - long endFrame = m_input->getEndFrame(); - long blockFrame = startFrame; - - long prevCompletion = 0; - - while (1) { - - if (frequencyDomain) { - if (blockFrame - int(m_blockSize)/2 > endFrame) break; - } else { - if (blockFrame >= endFrame) break; - } - -// std::cerr << "FeatureExtractionPluginTransform::run: blockFrame " -// << blockFrame << std::endl; - - long completion = - (((blockFrame - startFrame) / m_stepSize) * 99) / - ( (endFrame - startFrame) / m_stepSize); - - // channelCount is either m_input->channelCount or 1 - - for (size_t ch = 0; ch < channelCount; ++ch) { - if (frequencyDomain) { - int column = (blockFrame - startFrame) / m_stepSize; - for (size_t i = 0; i < m_blockSize/2; ++i) { - fftAdapters[ch]->getValuesAt - (column, i, buffers[ch][i*2], buffers[ch][i*2+1]); - } -/*!!! - float sum = 0.0; - for (size_t i = 0; i < m_blockSize/2; ++i) { - sum += buffers[ch][i*2]; - } - if (fabs(sum) < 0.0001) { - std::cerr << "WARNING: small sum for column " << column << " (sum is " << sum << ")" << std::endl; - } -*/ - } else { - getFrames(ch, channelCount, - blockFrame, m_blockSize, buffers[ch]); - } - } - - Vamp::Plugin::FeatureSet features = m_plugin->process - (buffers, Vamp::RealTime::frame2RealTime(blockFrame, sampleRate)); - - for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) { - Vamp::Plugin::Feature feature = - features[m_outputFeatureNo][fi]; - addFeature(blockFrame, feature); - } - - if (blockFrame == startFrame || completion > prevCompletion) { - setCompletion(completion); - prevCompletion = completion; - } - - blockFrame += m_stepSize; - } - - Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures(); - - for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) { - Vamp::Plugin::Feature feature = - features[m_outputFeatureNo][fi]; - addFeature(blockFrame, feature); - } - - if (frequencyDomain) { - for (size_t ch = 0; ch < channelCount; ++ch) { - delete fftAdapters[ch]; - } - } - - setCompletion(100); -} - -void -FeatureExtractionPluginTransform::getFrames(int channel, int channelCount, - long startFrame, long size, - float *buffer) -{ - long offset = 0; - - if (startFrame < 0) { - for (int i = 0; i < size && startFrame + i < 0; ++i) { - buffer[i] = 0.0f; - } - offset = -startFrame; - size -= offset; - if (size <= 0) return; - startFrame = 0; - } - - long got = getInput()->getValues - ((channelCount == 1 ? m_channel : channel), - startFrame, startFrame + size, buffer + offset); - - while (got < size) { - buffer[offset + got] = 0.0; - ++got; - } - - if (m_channel == -1 && channelCount == 1 && - getInput()->getChannelCount() > 1) { - // use mean instead of sum, as plugin input - int cc = getInput()->getChannelCount(); - for (long i = 0; i < size; ++i) { - buffer[i] /= cc; - } - } -} - -void -FeatureExtractionPluginTransform::addFeature(size_t blockFrame, - const Vamp::Plugin::Feature &feature) -{ - size_t inputRate = m_input->getSampleRate(); - -// std::cerr << "FeatureExtractionPluginTransform::addFeature(" -// << blockFrame << ")" << std::endl; - - int binCount = 1; - if (m_descriptor->hasFixedBinCount) { - binCount = m_descriptor->binCount; - } - - size_t frame = blockFrame; - - if (m_descriptor->sampleType == - Vamp::Plugin::OutputDescriptor::VariableSampleRate) { - - if (!feature.hasTimestamp) { - std::cerr - << "WARNING: FeatureExtractionPluginTransform::addFeature: " - << "Feature has variable sample rate but no timestamp!" - << std::endl; - return; - } else { - frame = Vamp::RealTime::realTime2Frame(feature.timestamp, inputRate); - } - - } else if (m_descriptor->sampleType == - Vamp::Plugin::OutputDescriptor::FixedSampleRate) { - - if (feature.hasTimestamp) { - //!!! warning: sampleRate may be non-integral - frame = Vamp::RealTime::realTime2Frame(feature.timestamp, - m_descriptor->sampleRate); - } else { - frame = m_output->getEndFrame() + 1; - } - } - - if (binCount == 0) { - - SparseOneDimensionalModel *model = getOutput(); - if (!model) return; - model->addPoint(SparseOneDimensionalModel::Point(frame, feature.label.c_str())); - - } else if (binCount == 1) { - - float value = 0.0; - if (feature.values.size() > 0) value = feature.values[0]; - - SparseTimeValueModel *model = getOutput(); - if (!model) return; - model->addPoint(SparseTimeValueModel::Point(frame, value, feature.label.c_str())); - - } else if (m_descriptor->sampleType == - Vamp::Plugin::OutputDescriptor::VariableSampleRate) { - - float pitch = 0.0; - if (feature.values.size() > 0) pitch = feature.values[0]; - - float duration = 1; - if (feature.values.size() > 1) duration = feature.values[1]; - - float velocity = 100; - if (feature.values.size() > 2) velocity = feature.values[2]; - - NoteModel *model = getOutput(); - if (!model) return; - - model->addPoint(NoteModel::Point(frame, pitch, duration, feature.label.c_str())); - - } else { - - DenseThreeDimensionalModel::BinValueSet values = feature.values; - - DenseThreeDimensionalModel *model = getOutput(); - if (!model) return; - - model->setBinValues(frame, values); - } -} - -void -FeatureExtractionPluginTransform::setCompletion(int completion) -{ - int binCount = 1; - if (m_descriptor->hasFixedBinCount) { - binCount = m_descriptor->binCount; - } - - if (binCount == 0) { - - SparseOneDimensionalModel *model = getOutput(); - if (!model) return; - model->setCompletion(completion); - - } else if (binCount == 1) { - - SparseTimeValueModel *model = getOutput(); - if (!model) return; - model->setCompletion(completion); - - } else if (m_descriptor->sampleType == - Vamp::Plugin::OutputDescriptor::VariableSampleRate) { - - NoteModel *model = getOutput(); - if (!model) return; - model->setCompletion(completion); - - } else { - - DenseThreeDimensionalModel *model = getOutput(); - if (!model) return; - model->setCompletion(completion); - } -} - diff -r 1a42221a1522 -r 3e4c384f518e transform/FeatureExtractionPluginTransform.h --- a/transform/FeatureExtractionPluginTransform.h Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _FEATURE_EXTRACTION_PLUGIN_TRANSFORM_H_ -#define _FEATURE_EXTRACTION_PLUGIN_TRANSFORM_H_ - -#include "Transform.h" - -#include "vamp-sdk/Plugin.h" - -class DenseTimeValueModel; - -class FeatureExtractionPluginTransform : public Transform -{ -public: - FeatureExtractionPluginTransform(Model *inputModel, - QString plugin, - int channel, - QString configurationXml = "", - QString outputName = ""); - virtual ~FeatureExtractionPluginTransform(); - -protected: - virtual void run(); - - Vamp::Plugin *m_plugin; - int m_channel; - size_t m_stepSize; - size_t m_blockSize; - Vamp::Plugin::OutputDescriptor *m_descriptor; - int m_outputFeatureNo; - - void addFeature(size_t blockFrame, - const Vamp::Plugin::Feature &feature); - - void setCompletion(int); - - void getFrames(int channel, int channelCount, - long startFrame, long size, float *buffer); - - // just casts - DenseTimeValueModel *getInput(); - template ModelClass *getOutput() { - ModelClass *mc = dynamic_cast(m_output); - if (!mc) { - std::cerr << "FeatureExtractionPluginTransform::getOutput: Output model not conformable" << std::endl; - } - return mc; - } -}; - -#endif - diff -r 1a42221a1522 -r 3e4c384f518e transform/RealTimePluginTransform.cpp --- a/transform/RealTimePluginTransform.cpp Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +0,0 @@ - -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "RealTimePluginTransform.h" - -#include "plugin/RealTimePluginFactory.h" -#include "plugin/RealTimePluginInstance.h" -#include "plugin/PluginXml.h" - -#include "base/Model.h" -#include "model/SparseTimeValueModel.h" -#include "model/DenseTimeValueModel.h" - -#include - -RealTimePluginTransform::RealTimePluginTransform(Model *inputModel, - QString pluginId, - int channel, - QString configurationXml, - QString units, - int output) : - Transform(inputModel), - m_plugin(0), - m_channel(channel), - m_outputNo(output) -{ - std::cerr << "RealTimePluginTransform::RealTimePluginTransform: plugin " << pluginId.toStdString() << ", output " << output << std::endl; - - RealTimePluginFactory *factory = - RealTimePluginFactory::instanceFor(pluginId); - - if (!factory) { - std::cerr << "RealTimePluginTransform: No factory available for plugin id \"" - << pluginId.toStdString() << "\"" << std::endl; - return; - } - - DenseTimeValueModel *input = getInput(); - if (!input) return; - - m_plugin = factory->instantiatePlugin(pluginId, 0, 0, m_input->getSampleRate(), - 1024, //!!! wants to be configurable - input->getChannelCount()); - - if (!m_plugin) { - std::cerr << "RealTimePluginTransform: Failed to instantiate plugin \"" - << pluginId.toStdString() << "\"" << std::endl; - return; - } - - if (configurationXml != "") { - PluginXml(m_plugin).setParametersFromXml(configurationXml); - } - - if (m_outputNo >= m_plugin->getControlOutputCount()) { - std::cerr << "RealTimePluginTransform: Plugin has fewer than desired " << m_outputNo << " control outputs" << std::endl; - return; - } - - SparseTimeValueModel *model = new SparseTimeValueModel - (input->getSampleRate(), 1024, //!!! - 0.0, 0.0, false); - - if (units != "") model->setScaleUnits(units); - - m_output = model; -} - -RealTimePluginTransform::~RealTimePluginTransform() -{ - delete m_plugin; -} - -DenseTimeValueModel * -RealTimePluginTransform::getInput() -{ - DenseTimeValueModel *dtvm = - dynamic_cast(getInputModel()); - if (!dtvm) { - std::cerr << "RealTimePluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; - } - return dtvm; -} - -void -RealTimePluginTransform::run() -{ - DenseTimeValueModel *input = getInput(); - if (!input) return; - - SparseTimeValueModel *model = dynamic_cast(m_output); - if (!model) return; - - if (m_outputNo >= m_plugin->getControlOutputCount()) return; - - size_t sampleRate = input->getSampleRate(); - int channelCount = input->getChannelCount(); - if (m_channel != -1) channelCount = 1; - - size_t blockSize = m_plugin->getBufferSize(); - - float **buffers = m_plugin->getAudioInputBuffers(); - - size_t startFrame = m_input->getStartFrame(); - size_t endFrame = m_input->getEndFrame(); - size_t blockFrame = startFrame; - - size_t prevCompletion = 0; - - int i = 0; - - while (blockFrame < endFrame) { - - size_t completion = - (((blockFrame - startFrame) / blockSize) * 99) / - ( (endFrame - startFrame) / blockSize); - - size_t got = 0; - - if (channelCount == 1) { - got = input->getValues - (m_channel, blockFrame, blockFrame + blockSize, buffers[0]); - while (got < blockSize) { - buffers[0][got++] = 0.0; - } - if (m_channel == -1 && channelCount > 1) { - // use mean instead of sum, as plugin input - for (size_t i = 0; i < got; ++i) { - buffers[0][i] /= channelCount; - } - } - } else { - for (size_t ch = 0; ch < channelCount; ++ch) { - got = input->getValues - (ch, blockFrame, blockFrame + blockSize, buffers[ch]); - while (got < blockSize) { - buffers[ch][got++] = 0.0; - } - } - } - - m_plugin->run(Vamp::RealTime::frame2RealTime(blockFrame, sampleRate)); - - float value = m_plugin->getControlOutputValue(m_outputNo); - - model->addPoint(SparseTimeValueModel::Point - (blockFrame - m_plugin->getLatency(), value, "")); - - if (blockFrame == startFrame || completion > prevCompletion) { - model->setCompletion(completion); - prevCompletion = completion; - } - - blockFrame += blockSize; - } - - model->setCompletion(100); -} - diff -r 1a42221a1522 -r 3e4c384f518e transform/RealTimePluginTransform.h --- a/transform/RealTimePluginTransform.h Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _REAL_TIME_PLUGIN_TRANSFORM_H_ -#define _REAL_TIME_PLUGIN_TRANSFORM_H_ - -#include "Transform.h" -#include "RealTimePluginInstance.h" - -class DenseTimeValueModel; - -class RealTimePluginTransform : public Transform -{ -public: - RealTimePluginTransform(Model *inputModel, - QString plugin, - int channel, - QString configurationXml = "", - QString units = "", - int output = 0); - virtual ~RealTimePluginTransform(); - -protected: - virtual void run(); - - RealTimePluginInstance *m_plugin; - int m_channel; - int m_outputNo; - - // just casts - DenseTimeValueModel *getInput(); -}; - -#endif - diff -r 1a42221a1522 -r 3e4c384f518e transform/Transform.cpp --- a/transform/Transform.cpp Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "Transform.h" - -Transform::Transform(Model *m) : - m_input(m), - m_output(0), - m_detached(false), - m_deleting(false) -{ -} - -Transform::~Transform() -{ - m_deleting = true; - wait(); - if (!m_detached) delete m_output; -} - diff -r 1a42221a1522 -r 3e4c384f518e transform/Transform.h --- a/transform/Transform.h Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _TRANSFORM_H_ -#define _TRANSFORM_H_ - -#include "Thread.h" - -#include "base/Model.h" - -typedef QString TransformName; - -/** - * A Transform turns one data model into another. - * - * Typically in this application, a Transform might have a - * DenseTimeValueModel as its input (e.g. an audio waveform) and a - * SparseOneDimensionalModel (e.g. detected beats) as its output. - * - * The Transform typically runs in the background, as a separate - * thread populating the output model. The model is available to the - * user of the Transform immediately, but may be initially empty until - * the background thread has populated it. - */ - -class Transform : public Thread -{ -public: - virtual ~Transform(); - - Model *getInputModel() { return m_input; } - Model *getOutputModel() { return m_output; } - Model *detachOutputModel() { m_detached = true; return m_output; } - -protected: - Transform(Model *m); - - Model *m_input; // I don't own this - Model *m_output; // I own this, unless... - bool m_detached; // ... this is true. - bool m_deleting; -}; - -#endif diff -r 1a42221a1522 -r 3e4c384f518e transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,480 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "TransformFactory.h" - -#include "FeatureExtractionPluginTransform.h" -#include "RealTimePluginTransform.h" - -#include "plugin/FeatureExtractionPluginFactory.h" -#include "plugin/RealTimePluginFactory.h" -#include "plugin/PluginXml.h" - -#include "widgets/PluginParameterDialog.h" - -#include "model/DenseTimeValueModel.h" - -#include -#include - -#include - -TransformFactory * -TransformFactory::m_instance = new TransformFactory; - -TransformFactory * -TransformFactory::getInstance() -{ - return m_instance; -} - -TransformFactory::~TransformFactory() -{ -} - -TransformFactory::TransformList -TransformFactory::getAllTransforms() -{ - if (m_transforms.empty()) populateTransforms(); - - TransformList list; - for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); - i != m_transforms.end(); ++i) { - list.push_back(i->second); - } - - return list; -} - -std::vector -TransformFactory::getAllTransformTypes() -{ - if (m_transforms.empty()) populateTransforms(); - - std::set types; - for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); - i != m_transforms.end(); ++i) { - types.insert(i->second.type); - } - - std::vector rv; - for (std::set::iterator i = types.begin(); i != types.end(); ++i) { - rv.push_back(*i); - } - - return rv; -} - -void -TransformFactory::populateTransforms() -{ - TransformDescriptionMap transforms; - - populateFeatureExtractionPlugins(transforms); - populateRealTimePlugins(transforms); - - // disambiguate plugins with similar descriptions - - std::map descriptions; - - for (TransformDescriptionMap::iterator i = transforms.begin(); - i != transforms.end(); ++i) { - - TransformDesc desc = i->second; - - ++descriptions[desc.description]; - ++descriptions[QString("%1 [%2]").arg(desc.description).arg(desc.maker)]; - } - - std::map counts; - m_transforms.clear(); - - for (TransformDescriptionMap::iterator i = transforms.begin(); - i != transforms.end(); ++i) { - - TransformDesc desc = i->second; - QString name = desc.name; - QString description = desc.description; - QString maker = desc.maker; - - if (descriptions[description] > 1) { - description = QString("%1 [%2]").arg(description).arg(maker); - if (descriptions[description] > 1) { - description = QString("%1 <%2>") - .arg(description).arg(++counts[description]); - } - } - - desc.description = description; - m_transforms[name] = desc; - } -} - -void -TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms) -{ - std::vector plugs = - FeatureExtractionPluginFactory::getAllPluginIdentifiers(); - - for (size_t i = 0; i < plugs.size(); ++i) { - - QString pluginId = plugs[i]; - - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); - - if (!factory) { - std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; - continue; - } - - Vamp::Plugin *plugin = - factory->instantiatePlugin(pluginId, 48000); - - if (!plugin) { - std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl; - continue; - } - - QString pluginDescription = plugin->getDescription().c_str(); - Vamp::Plugin::OutputList outputs = - plugin->getOutputDescriptors(); - - for (size_t j = 0; j < outputs.size(); ++j) { - - QString transformName = QString("%1:%2") - .arg(pluginId).arg(outputs[j].name.c_str()); - - QString userDescription; - QString friendlyName; - QString units = outputs[j].unit.c_str(); - - if (outputs.size() == 1) { - userDescription = pluginDescription; - friendlyName = pluginDescription; - } else { - userDescription = QString("%1: %2") - .arg(pluginDescription) - .arg(outputs[j].description.c_str()); - friendlyName = outputs[j].description.c_str(); - } - - bool configurable = (!plugin->getPrograms().empty() || - !plugin->getParameterDescriptors().empty()); - - transforms[transformName] = - TransformDesc(tr("Analysis Plugins"), - transformName, - userDescription, - friendlyName, - plugin->getMaker().c_str(), - units, - configurable); - } - } -} - -void -TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms) -{ - std::vector plugs = - RealTimePluginFactory::getAllPluginIdentifiers(); - - QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$"); - - for (size_t i = 0; i < plugs.size(); ++i) { - - QString pluginId = plugs[i]; - - RealTimePluginFactory *factory = - RealTimePluginFactory::instanceFor(pluginId); - - if (!factory) { - std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; - continue; - } - - const RealTimePluginDescriptor *descriptor = - factory->getPluginDescriptor(pluginId); - - if (!descriptor) { - std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl; - continue; - } - - if (descriptor->controlOutputPortCount == 0 || - descriptor->audioInputPortCount == 0) continue; - -// std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl; - - QString pluginDescription = descriptor->name.c_str(); - - for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) { - - QString transformName = QString("%1:%2").arg(pluginId).arg(j); - QString userDescription; - QString units; - - if (j < descriptor->controlOutputPortNames.size() && - descriptor->controlOutputPortNames[j] != "") { - - QString portName = descriptor->controlOutputPortNames[j].c_str(); - - userDescription = tr("%1: %2") - .arg(pluginDescription) - .arg(portName); - - if (unitRE.indexIn(portName) >= 0) { - units = unitRE.cap(1); - } - - } else if (descriptor->controlOutputPortCount > 1) { - - userDescription = tr("%1: Output %2") - .arg(pluginDescription) - .arg(j + 1); - - } else { - - userDescription = pluginDescription; - } - - - bool configurable = (descriptor->parameterCount > 0); - - transforms[transformName] = - TransformDesc(tr("Other Plugins"), - transformName, - userDescription, - userDescription, - descriptor->maker.c_str(), - units, - configurable); - } - } -} - -QString -TransformFactory::getTransformDescription(TransformName name) -{ - if (m_transforms.find(name) != m_transforms.end()) { - return m_transforms[name].description; - } else return ""; -} - -QString -TransformFactory::getTransformFriendlyName(TransformName name) -{ - if (m_transforms.find(name) != m_transforms.end()) { - return m_transforms[name].friendlyName; - } else return ""; -} - -QString -TransformFactory::getTransformUnits(TransformName name) -{ - if (m_transforms.find(name) != m_transforms.end()) { - return m_transforms[name].units; - } else return ""; -} - -bool -TransformFactory::isTransformConfigurable(TransformName name) -{ - if (m_transforms.find(name) != m_transforms.end()) { - return m_transforms[name].configurable; - } else return false; -} - -bool -TransformFactory::getTransformChannelRange(TransformName name, - int &min, int &max) -{ - QString id = name.section(':', 0, 2); - - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - Vamp::Plugin *plugin = - FeatureExtractionPluginFactory::instanceFor(id)-> - instantiatePlugin(id, 48000); - if (!plugin) return false; - - min = plugin->getMinChannelCount(); - max = plugin->getMaxChannelCount(); - delete plugin; - - return true; - - } else if (RealTimePluginFactory::instanceFor(id)) { - - const RealTimePluginDescriptor *descriptor = - RealTimePluginFactory::instanceFor(id)-> - getPluginDescriptor(id); - if (!descriptor) return false; - - min = descriptor->audioInputPortCount; - max = descriptor->audioInputPortCount; - - return true; - } - - return false; -} - -bool -TransformFactory::getChannelRange(TransformName name, Vamp::PluginBase *plugin, - int &minChannels, int &maxChannels) -{ - Vamp::Plugin *vp = 0; - if ((vp = dynamic_cast(plugin))) { - minChannels = vp->getMinChannelCount(); - maxChannels = vp->getMaxChannelCount(); - return true; - } else { - return getTransformChannelRange(name, minChannels, maxChannels); - } -} - -bool -TransformFactory::getConfigurationForTransform(TransformName name, - Model *inputModel, - int &channel, - QString &configurationXml) -{ - QString id = name.section(':', 0, 2); - QString output = name.section(':', 3); - - bool ok = false; - configurationXml = m_lastConfigurations[name]; - -// std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; - - Vamp::PluginBase *plugin = 0; - - if (FeatureExtractionPluginFactory::instanceFor(id)) { - - plugin = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin - (id, inputModel->getSampleRate()); - - } else if (RealTimePluginFactory::instanceFor(id)) { - - plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin - (id, 0, 0, inputModel->getSampleRate(), 1024, 1); - } - - if (plugin) { - if (configurationXml != "") { - PluginXml(plugin).setParametersFromXml(configurationXml); - } - - int sourceChannels = 1; - if (dynamic_cast(inputModel)) { - sourceChannels = dynamic_cast(inputModel) - ->getChannelCount(); - } - - int minChannels = 1, maxChannels = sourceChannels; - getChannelRange(name, plugin, minChannels, maxChannels); - - int targetChannels = sourceChannels; - if (sourceChannels < minChannels) targetChannels = minChannels; - if (sourceChannels > maxChannels) targetChannels = maxChannels; - - int defaultChannel = channel; - - PluginParameterDialog *dialog = new PluginParameterDialog(plugin, - sourceChannels, - targetChannels, - defaultChannel, - output); - if (dialog->exec() == QDialog::Accepted) { - ok = true; - } - configurationXml = PluginXml(plugin).toXmlString(); - channel = dialog->getChannel(); - delete dialog; - delete plugin; - } - - if (ok) m_lastConfigurations[name] = configurationXml; - - return ok; -} - -Transform * -TransformFactory::createTransform(TransformName name, Model *inputModel, - int channel, QString configurationXml, bool start) -{ - Transform *transform = 0; - - //!!! use channel - - QString id = name.section(':', 0, 2); - QString output = name.section(':', 3); - - if (FeatureExtractionPluginFactory::instanceFor(id)) { - transform = new FeatureExtractionPluginTransform(inputModel, - id, - channel, - configurationXml, - output); - } else if (RealTimePluginFactory::instanceFor(id)) { - transform = new RealTimePluginTransform(inputModel, - id, - channel, - configurationXml, - getTransformUnits(name), - output.toInt()); - } else { - std::cerr << "TransformFactory::createTransform: Unknown transform \"" - << name.toStdString() << "\"" << std::endl; - return transform; - } - - if (start && transform) transform->start(); - transform->setObjectName(name); - return transform; -} - -Model * -TransformFactory::transform(TransformName name, Model *inputModel, - int channel, QString configurationXml) -{ - Transform *t = createTransform(name, inputModel, channel, - configurationXml, false); - - if (!t) return 0; - - connect(t, SIGNAL(finished()), this, SLOT(transformFinished())); - - t->start(); - return t->detachOutputModel(); -} - -void -TransformFactory::transformFinished() -{ - QObject *s = sender(); - Transform *transform = dynamic_cast(s); - - if (!transform) { - std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl; - return; - } - - transform->wait(); // unnecessary but reassuring - delete transform; -} - diff -r 1a42221a1522 -r 3e4c384f518e transform/TransformFactory.h --- a/transform/TransformFactory.h Mon Jul 31 11:49:58 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _TRANSFORM_FACTORY_H_ -#define _TRANSFORM_FACTORY_H_ - -#include "Transform.h" - -#include - -namespace Vamp { class PluginBase; } - -class TransformFactory : public QObject -{ - Q_OBJECT - -public: - virtual ~TransformFactory(); - - static TransformFactory *getInstance(); - - // The name is intended to be computer-referenceable, and unique - // within the application. The description is intended to be - // human readable. In principle it doesn't have to be unique, but - // the factory will add suffixes to ensure that it is, all the - // same (just to avoid user confusion). The friendly name is a - // shorter version of the description. The type is also intended - // to be user-readable, for use in menus. - - struct TransformDesc { - TransformDesc() { } - TransformDesc(QString _type, TransformName _name, QString _description, - QString _friendlyName, QString _maker, - QString _units, bool _configurable) : - type(_type), name(_name), description(_description), - friendlyName(_friendlyName), - maker(_maker), units(_units), configurable(_configurable) { } - QString type; - TransformName name; - QString description; - QString friendlyName; - QString maker; - QString units; - bool configurable; - }; - typedef std::vector TransformList; - - TransformList getAllTransforms(); - - std::vector getAllTransformTypes(); - - /** - * Get a configuration XML string for the given transform (by - * asking the user, most likely). Returns true if the transform - * is acceptable, false if the operation should be cancelled. - */ - bool getConfigurationForTransform(TransformName name, Model *inputModel, - int &channel, - QString &configurationXml); - - /** - * Return the output model resulting from applying the named - * transform to the given input model. The transform may still be - * working in the background when the model is returned; check the - * output model's isReady completion status for more details. - * - * If the transform is unknown or the input model is not an - * appropriate type for the given transform, or if some other - * problem occurs, return 0. - * - * The returned model is owned by the caller and must be deleted - * when no longer needed. - */ - Model *transform(TransformName name, Model *inputModel, - int channel, QString configurationXml = ""); - - /** - * Full description of a transform, suitable for putting on a menu. - */ - QString getTransformDescription(TransformName name); - - /** - * Brief but friendly description of a transform, suitable for use - * as the name of the output layer. - */ - QString getTransformFriendlyName(TransformName name); - - QString getTransformUnits(TransformName name); - - /** - * Return true if the transform has any configurable parameters, - * i.e. if getConfigurationForTransform can ever return a non-trivial - * (not equivalent to empty) configuration string. - */ - bool isTransformConfigurable(TransformName name); - - /** - * If the transform has a prescribed number or range of channel - * inputs, return true and set minChannels and maxChannels to the - * minimum and maximum number of channel inputs the transform can - * accept. - */ - bool getTransformChannelRange(TransformName name, - int &minChannels, int &maxChannels); - - //!!! Need some way to indicate that the input model has changed / - //been deleted so as not to blow up backgrounded transform! -- Or - //indeed, if the output model has been deleted -- could equally - //well happen! - - //!!! Need transform category! - -protected slots: - void transformFinished(); - -protected: - Transform *createTransform(TransformName name, Model *inputModel, - int channel, QString configurationXml, bool start); - - struct TransformIdent - { - TransformName name; - QString configurationXml; - }; - - typedef std::map TransformConfigurationMap; - TransformConfigurationMap m_lastConfigurations; - - typedef std::map TransformDescriptionMap; - TransformDescriptionMap m_transforms; - - void populateTransforms(); - void populateFeatureExtractionPlugins(TransformDescriptionMap &); - void populateRealTimePlugins(TransformDescriptionMap &); - - bool getChannelRange(TransformName name, - Vamp::PluginBase *plugin, int &min, int &max); - - static TransformFactory *m_instance; -}; - - -#endif