Mercurial > hg > sonic-annotator
changeset 0:581b1b150a4d
* copy to sonic-annotator
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AudioDBFeatureWriter.cpp Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,214 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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 <fstream> + +#include <QFileInfo> + +#include "AudioDBFeatureWriter.h" + +using namespace std; +using namespace Vamp; + +string +AudioDBFeatureWriter::catalogueIdParam = "catid"; + +string +AudioDBFeatureWriter::baseDirParam = "basedir"; + +struct AudioDBFeatureWriter::TrackStream +{ + QString trackid; + ofstream* ofs; +}; + +AudioDBFeatureWriter::AudioDBFeatureWriter() : + catalogueId("catalog"), baseDir("audiodb") +{ + +} + +AudioDBFeatureWriter::~AudioDBFeatureWriter() +{ + // close all open files + for (map<string, TrackStream>::iterator iter = dbfiles.begin(); iter != dbfiles.end(); ++iter) + { + if (iter->second.ofs) { + iter->second.ofs->close(); + delete iter->second.ofs; + } + } + + // TODO: error handling on close +} + +AudioDBFeatureWriter::ParameterList +AudioDBFeatureWriter::getSupportedParameters() const +{ + ParameterList pl; + Parameter p; + + p.name = catalogueIdParam; + p.description = "Catalogue ID"; + p.hasArg = true; + pl.push_back(p); + + p.name = baseDirParam; + p.description = "Base output directory path"; + p.hasArg = true; + pl.push_back(p); + + return pl; +} + +void +AudioDBFeatureWriter::setParameters(map<string, string> ¶ms) +{ + if (params.find(catalogueIdParam) != params.end()) { + setCatalogueId(params[catalogueIdParam]); + params.erase(catalogueIdParam); + } + if (params.find(baseDirParam) != params.end()) { + setBaseDirectory(params[baseDirParam]); + params.erase(baseDirParam); + } +} + +void +AudioDBFeatureWriter::setCatalogueId(const string &catid) +{ + catalogueId = catid; +} + +void +AudioDBFeatureWriter::setBaseDirectory(const string &base) +{ + baseDir = base; +} + +void AudioDBFeatureWriter::write(QString trackid, + const Transform &transform, + const Vamp::Plugin::OutputDescriptor& output, + const Vamp::Plugin::FeatureList& featureList, + std::string summaryType) +{ + //!!! use summaryType + if (summaryType != "") { + //!!! IMPLEMENT + cerr << "ERROR: AudioDBFeatureWriter::write: Writing summaries is not yet implemented!" << endl; + exit(1); + } + + + // binary output for FeatureSet + + // feature-dimension feature-1 feature-2 ... + // timestamp-1 timestamp-2 ... + + // audioDB has to write each feature to a different file + // assume a simple naming convention of + // <catalog-id>/<track-id>.<feature-id> + // with timestamps in a corresponding <catalog-id>/<track-id>.<feature-id>.timestamp file + // (start and end times in seconds for each frame -- somewhat optional) + + // the feature writer holds a map of open file descriptors + // the catalog-id is passed in to the feature writer's constructor + + // NB -- all "floats" in the file should in fact be doubles + + // TODO: + // - write feature end rather than start times, once end time is available in vamp + // - write a power file, probably by wrapping plugin in a PluginPowerAdapter :) + + if (output.binCount == 0) // this kind of feature just outputs timestamps and labels, assume of no interest to audioDB + return; + + for (int i = 0; i < featureList.size(); ++i) + { + // replace output files if necessary + if (replaceDBFile(trackid, output.identifier)) + { + // write the feature length for the next track feature record + // binCount has to be set + // - it can be zero, i.e. if the output is really a set of labels + timestamps + *dbfiles[output.identifier].ofs /*<< ios::binary*/ << output.binCount; + + cerr << "writing bin count " << output.binCount << " for " << output.identifier << endl; + } + + if (replaceDBFile(trackid, output.identifier + ".timestamp")) + { + // write the start time to the timestamp file + // as we want it for the first feature in the file + *dbfiles[output.identifier + ".timestamp"].ofs << featureList[i].timestamp.toString() << endl; + } + + if (dbfiles[output.identifier].ofs) { + for (int j = 0; j < featureList[i].values.size(); ++j) + *dbfiles[output.identifier].ofs /*<< ios::binary*/ << featureList[i].values[j]; + + // write the *end* time of each feature to the timestamp file + // NOT IMPLEMENTED YET +// *dbfiles[output.identifier + ".timestamp"].ofs << featureList[i].timestamp.toString() << endl; + } + } +} + +bool AudioDBFeatureWriter::openDBFile(QString trackid, const string& identifier) +{ + QString trackBase = QFileInfo(trackid).fileName(); + string filepath = baseDir + "/" + catalogueId + "/" + + trackBase.toStdString() + "." + identifier; + cerr << "AudioDBFeatureWriter::openDBFile: filepath is \"" << filepath << "\"" << endl; + ofstream* ofs = new ofstream(filepath.c_str()); + if (!*ofs) + { + cerr << "ERROR AudioDBFeatureWriter::openDBFile(): can't open file " << filepath << endl; + return false; + } + TrackStream ts; + ts.trackid = trackid; + ts.ofs = ofs; + dbfiles[identifier] = ts; + return true; +} + +// replace file if no file open for this track, else return false +bool AudioDBFeatureWriter::replaceDBFile(QString trackid, + const string& identifier) +{ + if (dbfiles.find(identifier) != dbfiles.end() && dbfiles[identifier].trackid == trackid) + return false; // have an open file for this track + + if (dbfiles.find(identifier) != dbfiles.end() && dbfiles[identifier].trackid != trackid) + { + // close the current file + if (dbfiles[identifier].ofs) { + dbfiles[identifier].ofs->close(); + delete dbfiles[identifier].ofs; + dbfiles[identifier].ofs = 0; + } + } + + // open a new file + if (!openDBFile(trackid, identifier)) { + dbfiles[identifier].ofs = 0; + return false; //!!! should throw an exception, otherwise we'll try to open the file again and again every time we want to write to it + } + + return true; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AudioDBFeatureWriter.h Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,61 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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 _AUDIO_DB_FEATURE_WRITER_H_ +#define _AUDIO_DB_FEATURE_WRITER_H_ + +#include <string> +#include <map> + +using std::string; +using std::map; + +#include "transform/FeatureWriter.h" + +class AudioDBFeatureWriter : public FeatureWriter +{ +public: + AudioDBFeatureWriter(); + virtual ~AudioDBFeatureWriter(); + + virtual ParameterList getSupportedParameters() const; + virtual void setParameters(map<string, string> ¶ms); + + virtual void setCatalogueId(const string &); + virtual void setBaseDirectory(const string &); + + virtual void write(QString trackid, + const Transform &transform, + const Vamp::Plugin::OutputDescriptor &output, + const Vamp::Plugin::FeatureList &features, + std::string summaryType = ""); + + virtual void finish() { } + +private: + string catalogueId; + string baseDir; + + static string catalogueIdParam; + static string baseDirParam; + + struct TrackStream; + map<string, TrackStream> dbfiles; + + bool openDBFile(QString trackid, const string& identifier); + bool replaceDBFile(QString trackid, const string& identifier); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DefaultFeatureWriter.cpp Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,77 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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 <iostream> +#include <map> + +using namespace std; + +#include "DefaultFeatureWriter.h" + +void DefaultFeatureWriter::write(QString trackid, + const Transform &transform, + const Vamp::Plugin::OutputDescriptor& output, + const Vamp::Plugin::FeatureList& featureList, + std::string summaryType) +{ + // generic XML output + + /* + + <feature> + <name>output.name</name> + <timestamp>feature.timestamp</timestamp> + <values>output.binName[0]:feature.value[0]...</values> + <label>feature.label</label> + </feature> + + */ + + for (int i = 0; i < featureList.size(); ++i) + { + if (summaryType == "") { + cout << "<feature>" << endl; + } else { + cout << "<summary type=\"" << summaryType << "\">" << endl; + } + cout << "\t<name>" << output.name << "</name>" << endl; + if (featureList[i].hasTimestamp) { + cout << "\t<timestamp>" << featureList[i].timestamp << "</timestamp>" << endl; + } + if (featureList[i].hasDuration) { + cout << "\t<duration>" << featureList[i].duration << "</duration>" << endl; + } + if (featureList[i].values.size() > 0) + { + cout << "\t<values>"; + for (int j = 0; j < featureList[i].values.size(); ++j) + { + if (j > 0) + cout << " "; + if (output.binNames.size() > 0) + cout << output.binNames[j] << ":"; + cout << featureList[i].values[j]; + } + cout << "</values>" << endl; + } + if (featureList[i].label.length() > 0) + cout << "\t<label>" << featureList[i].label << "</label>" << endl; + if (summaryType == "") { + cout << "</feature>" << endl; + } else { + cout << "</summary>" << endl; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DefaultFeatureWriter.h Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,34 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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 _DEFAULT_FEATURE_WRITER_H_ +#define _DEFAULT_FEATURE_WRITER_H_ + + +#include "transform/FeatureWriter.h" + +class DefaultFeatureWriter : public FeatureWriter +{ +public: + virtual ~DefaultFeatureWriter() { } + virtual void write(QString trackid, + const Transform &transform, + const Vamp::Plugin::OutputDescriptor &output, + const Vamp::Plugin::FeatureList &features, + std::string summaryType = ""); + virtual void finish() { } +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FeatureExtractionManager.cpp Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,702 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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 "FeatureExtractionManager.h" + +#include <vamp-hostsdk/PluginChannelAdapter.h> +#include <vamp-hostsdk/PluginBufferingAdapter.h> +#include <vamp-hostsdk/PluginInputDomainAdapter.h> +#include <vamp-hostsdk/PluginSummarisingAdapter.h> +#include <vamp-hostsdk/PluginLoader.h> + +#include <iostream> + +using namespace std; + +using Vamp::Plugin; +using Vamp::PluginBase; +using Vamp::HostExt::PluginLoader; +using Vamp::HostExt::PluginChannelAdapter; +using Vamp::HostExt::PluginBufferingAdapter; +using Vamp::HostExt::PluginInputDomainAdapter; +using Vamp::HostExt::PluginSummarisingAdapter; + +#include "data/fileio/FileSource.h" +#include "data/fileio/AudioFileReader.h" +#include "data/fileio/AudioFileReaderFactory.h" +#include "data/fileio/PlaylistFileReader.h" +#include "base/TempDirectory.h" +#include "base/ProgressPrinter.h" +#include "transform/TransformFactory.h" +#include "rdf/RDFTransformFactory.h" +#include "transform/FeatureWriter.h" + +#include <QTextStream> +#include <QFile> +#include <QFileInfo> + +FeatureExtractionManager::FeatureExtractionManager() : + m_summariesOnly(false), + // We can read using an arbitrary fixed block size -- + // PluginBufferingAdapter handles this for us. It's likely to be + // quicker to use larger sizes than smallish ones like 1024 + m_blockSize(16384), + m_defaultSampleRate(0), + m_sampleRate(0), + m_channels(1) +{ +} + +FeatureExtractionManager::~FeatureExtractionManager() +{ + for (PluginMap::iterator pi = m_plugins.begin(); + pi != m_plugins.end(); ++pi) { + delete pi->first; + } +} + +void FeatureExtractionManager::setChannels(int channels) +{ + m_channels = channels; +} + +void FeatureExtractionManager::setDefaultSampleRate(int sampleRate) +{ + m_defaultSampleRate = sampleRate; +} + +static PluginSummarisingAdapter::SummaryType +getSummaryType(string name) +{ + if (name == "min") return PluginSummarisingAdapter::Minimum; + if (name == "max") return PluginSummarisingAdapter::Maximum; + if (name == "mean") return PluginSummarisingAdapter::Mean; + if (name == "median") return PluginSummarisingAdapter::Median; + if (name == "mode") return PluginSummarisingAdapter::Mode; + if (name == "sum") return PluginSummarisingAdapter::Sum; + if (name == "variance") return PluginSummarisingAdapter::Variance; + if (name == "sd") return PluginSummarisingAdapter::StandardDeviation; + if (name == "count") return PluginSummarisingAdapter::Count; + return PluginSummarisingAdapter::UnknownSummaryType; +} + +bool FeatureExtractionManager::setSummaryTypes(const set<string> &names, + bool summariesOnly, + const PluginSummarisingAdapter::SegmentBoundaries &boundaries) +{ + for (SummaryNameSet::const_iterator i = names.begin(); + i != names.end(); ++i) { + if (getSummaryType(*i) == PluginSummarisingAdapter::UnknownSummaryType) { + cerr << "ERROR: Unknown summary type \"" << *i << "\"" << endl; + return false; + } + } + m_summaries = names; + m_summariesOnly = summariesOnly; + m_boundaries = boundaries; + return true; +} + +bool FeatureExtractionManager::addFeatureExtractor +(Transform transform, const vector<FeatureWriter*> &writers) +{ + //!!! exceptions rather than return values? + + if (transform.getSampleRate() == 0) { + if (m_sampleRate == 0) { + cerr << "NOTE: Transform does not specify a sample rate, using default rate of " << m_defaultSampleRate << endl; + transform.setSampleRate(m_defaultSampleRate); + m_sampleRate = m_defaultSampleRate; + } else { + cerr << "NOTE: Transform does not specify a sample rate, using previous transform's rate of " << m_sampleRate << endl; + transform.setSampleRate(m_sampleRate); + } + } + + if (m_sampleRate == 0) { + m_sampleRate = transform.getSampleRate(); + } + + if (transform.getSampleRate() != m_sampleRate) { + cerr << "WARNING: Transform sample rate " << transform.getSampleRate() << " does not match previously specified transform rate of " << m_sampleRate << " -- only a single rate is supported for each run" << endl; + cerr << "WARNING: Using previous rate of " << m_sampleRate << " for this transform as well" << endl; + transform.setSampleRate(m_sampleRate); + } + + Plugin *plugin = 0; + + // Remember what the original transform looked like, and index + // based on this -- because we may be about to fill in the zeros + // for step and block size, but we want any further copies with + // the same zeros to match this one + Transform originalTransform = transform; + + if (m_transformPluginMap.find(transform) == m_transformPluginMap.end()) { + + // Test whether we already have a transform that is identical + // to this, except for the output requested and/or the summary + // type -- if so, they should share plugin instances (a vital + // optimisation) + + for (TransformPluginMap::iterator i = m_transformPluginMap.begin(); + i != m_transformPluginMap.end(); ++i) { + Transform test = i->first; + test.setOutput(transform.getOutput()); + test.setSummaryType(transform.getSummaryType()); + if (transform == test) { + cerr << "NOTE: Already have transform identical to this one (for \"" + << transform.getIdentifier().toStdString() + << "\") in every detail except output identifier and/or " + << "summary type; sharing its plugin instance" << endl; + plugin = i->second; + if (transform.getSummaryType() != Transform::NoSummary && + !dynamic_cast<PluginSummarisingAdapter *>(plugin)) { + plugin = new PluginSummarisingAdapter(plugin); + i->second = plugin; + } + break; + } + } + + if (!plugin) { + + TransformFactory *tf = TransformFactory::getInstance(); + + PluginBase *pb = tf->instantiatePluginFor(transform); + plugin = tf->downcastVampPlugin(pb); + if (!plugin) { + //!!! todo: handle non-Vamp plugins too, or make the main --list + // option print out only Vamp transforms + cerr << "ERROR: Failed to load plugin for transform \"" + << transform.getIdentifier().toStdString() << "\"" << endl; + delete pb; + return false; + } + + // We will provide the plugin with arbitrary step and + // block sizes (so that we can use the same read/write + // block size for all transforms), and to that end we use + // a PluginBufferingAdapter. However, we need to know the + // underlying step size so that we can provide the right + // context for dense outputs. (Although, don't forget + // that the PluginBufferingAdapter rewrites + // OneSamplePerStep outputs so as to use FixedSampleRate + // -- so it supplies the sample rate in the output + // feature. I'm not sure whether we can easily use that.) + + size_t pluginStepSize = plugin->getPreferredStepSize(); + size_t pluginBlockSize = plugin->getPreferredBlockSize(); + + // adapt the plugin for buffering, channels, etc. + if (plugin->getInputDomain() == Plugin::FrequencyDomain) { + plugin = new PluginInputDomainAdapter(plugin); + } + + PluginBufferingAdapter *pba = new PluginBufferingAdapter(plugin); + plugin = pba; + + if (transform.getStepSize() != 0) { + pba->setPluginStepSize(transform.getStepSize()); + } else { + transform.setStepSize(pluginStepSize); + } + + if (transform.getBlockSize() != 0) { + pba->setPluginBlockSize(transform.getBlockSize()); + } else { + transform.setBlockSize(pluginBlockSize); + } + + plugin = new PluginChannelAdapter(plugin); + + if (!m_summaries.empty() || + transform.getSummaryType() != Transform::NoSummary) { + PluginSummarisingAdapter *adapter = + new PluginSummarisingAdapter(plugin); + adapter->setSummarySegmentBoundaries(m_boundaries); + plugin = adapter; + } + + if (!plugin->initialise(m_channels, m_blockSize, m_blockSize)) { + cerr << "ERROR: Plugin initialise (channels = " << m_channels << ", stepSize = " << m_blockSize << ", blockSize = " << m_blockSize << ") failed." << endl; + delete plugin; + return false; + } + +// cerr << "Initialised plugin" << endl; + + size_t actualStepSize = 0; + size_t actualBlockSize = 0; + pba->getActualStepAndBlockSizes(actualStepSize, actualBlockSize); + transform.setStepSize(actualStepSize); + transform.setBlockSize(actualBlockSize); + + Plugin::OutputList outputs = plugin->getOutputDescriptors(); + for (int i = 0; i < (int)outputs.size(); ++i) { + +// cerr << "Newly initialised plugin output " << i << " has bin count " << outputs[i].binCount << endl; + + m_pluginOutputs[plugin][outputs[i].identifier] = outputs[i]; + m_pluginOutputIndices[outputs[i].identifier] = i; + } + + cerr << "NOTE: Loaded and initialised plugin " << plugin + << " for transform \"" + << transform.getIdentifier().toStdString() << "\"" << endl; + } + + if (transform.getOutput() == "") { + transform.setOutput + (plugin->getOutputDescriptors()[0].identifier.c_str()); + } + + m_transformPluginMap[transform] = plugin; + + if (!(originalTransform == transform)) { + m_transformPluginMap[originalTransform] = plugin; + } + + } else { + + plugin = m_transformPluginMap[transform]; + } + + m_plugins[plugin][transform] = writers; + + return true; +} + +bool FeatureExtractionManager::addDefaultFeatureExtractor +(TransformId transformId, const vector<FeatureWriter*> &writers) +{ + TransformFactory *tf = TransformFactory::getInstance(); + + if (m_sampleRate == 0) { + if (m_defaultSampleRate == 0) { + cerr << "ERROR: Default transform requested, but no default sample rate available" << endl; + return false; + } else { + cerr << "NOTE: Using default sample rate of " << m_defaultSampleRate << " for default transform" << endl; + m_sampleRate = m_defaultSampleRate; + } + } + + Transform transform = tf->getDefaultTransformFor(transformId, m_sampleRate); + + return addFeatureExtractor(transform, writers); +} + +bool FeatureExtractionManager::addFeatureExtractorFromFile +(QString transformXmlFile, const vector<FeatureWriter*> &writers) +{ + RDFTransformFactory factory + (QUrl::fromLocalFile(QFileInfo(transformXmlFile).absoluteFilePath()) + .toString()); + ProgressPrinter printer("Parsing transforms RDF file"); + std::vector<Transform> transforms = factory.getTransforms(&printer); + if (!factory.isOK()) { + cerr << "WARNING: FeatureExtractionManager::addFeatureExtractorFromFile: Failed to parse transforms file: " << factory.getErrorString().toStdString() << endl; + if (factory.isRDF()) { + return false; // no point trying it as XML + } + } + if (!transforms.empty()) { + bool success = true; + for (int i = 0; i < (int)transforms.size(); ++i) { + if (!addFeatureExtractor(transforms[i], writers)) { + success = false; + } + } + return success; + } + + QFile file(transformXmlFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + cerr << "ERROR: Failed to open transform XML file \"" + << transformXmlFile.toStdString() << "\" for reading" << endl; + return false; + } + + QTextStream *qts = new QTextStream(&file); + QString qs = qts->readAll(); + delete qts; + file.close(); + + Transform transform(qs); + + return addFeatureExtractor(transform, writers); +} + +void FeatureExtractionManager::extractFeatures(QString audioSource) +{ + if (m_plugins.empty()) return; + + ProgressPrinter printer("Retrieving audio data..."); + + FileSource source(audioSource, &printer); + if (!source.isAvailable()) { + cerr << "ERROR: File or URL \"" << audioSource.toStdString() + << "\" could not be located" << endl; + exit(1); + } + + source.waitForData(); + + if (QFileInfo(audioSource).suffix().toLower() == "m3u") { + PlaylistFileReader reader(source); + if (reader.isOK()) { + vector<QString> files = reader.load(); + for (int i = 0; i < (int)files.size(); ++i) { + extractFeatures(files[i]); + } + return; + } else { + cerr << "ERROR: Playlist \"" << audioSource.toStdString() + << "\" could not be opened" << endl; + exit(1); + } + } + + if (m_sampleRate == 0) { + cerr << "ERROR: Internal error in FeatureExtractionManager::extractFeatures: Plugin list is non-empty, but no sample rate set" << endl; + exit(1); + } + + AudioFileReader *reader = + AudioFileReaderFactory::createReader(source, m_sampleRate, &printer); + + if (!reader) { + cerr << "ERROR: File or URL \"" << audioSource.toStdString() + << "\" could not be opened" << endl; + exit(1); + } + + size_t channels = reader->getChannelCount(); + + cerr << "Opened " << channels << "-channel file or URL \"" << audioSource.toStdString() << "\"" << endl; + + // reject file if it has too few channels, plugin will handle if it has too many + if ((int)channels < m_channels) { + //!!! should not be terminating here! + cerr << "ERROR: File or URL \"" << audioSource.toStdString() << "\" has less than " << m_channels << " channels" << endl; + exit(1); + } + + // allocate audio buffers + float **data = new float *[m_channels]; + for (int c = 0; c < m_channels; ++c) { + data[c] = new float[m_blockSize]; + } + + size_t frameCount = reader->getFrameCount(); + +// cerr << "file has " << frameCount << " frames" << endl; + + for (PluginMap::iterator pi = m_plugins.begin(); + pi != m_plugins.end(); ++pi) { + + Plugin *plugin = pi->first; + +// std::cerr << "Calling reset on " << plugin << std::endl; + plugin->reset(); + + for (TransformWriterMap::iterator ti = pi->second.begin(); + ti != pi->second.end(); ++ti) { + + const Transform &transform = ti->first; + + //!!! we may want to set the start and duration times for extraction + // in the transform record (defaults of zero indicate extraction + // from the whole file) +// transform.setStartTime(RealTime::zeroTime); +// transform.setDuration +// (RealTime::frame2RealTime(reader->getFrameCount(), m_sampleRate)); + + string outputId = transform.getOutput().toStdString(); + if (m_pluginOutputs[plugin].find(outputId) == + m_pluginOutputs[plugin].end()) { + //!!! throw? + cerr << "WARNING: Nonexistent plugin output \"" << outputId << "\" requested for transform \"" + << transform.getIdentifier().toStdString() << "\", ignoring this transform" + << endl; +/* + cerr << "Known outputs for all plugins are as follows:" << endl; + for (PluginOutputMap::const_iterator k = m_pluginOutputs.begin(); + k != m_pluginOutputs.end(); ++k) { + cerr << "Plugin " << k->first << ": "; + if (k->second.empty()) { + cerr << "(none)"; + } + for (OutputMap::const_iterator i = k->second.begin(); + i != k->second.end(); ++i) { + cerr << "\"" << i->first << "\" "; + } + cerr << endl; + } +*/ + } + } + } + + long startFrame = 0; + long endFrame = frameCount; + +/*!!! No -- there is no single transform to pull this stuff from -- + * the transforms may have various start and end times, need to be far + * cleverer about this if we're going to support them + + RealTime trStartRT = transform.getStartTime(); + RealTime trDurationRT = transform.getDuration(); + + long trStart = RealTime::realTime2Frame(trStartRT, m_sampleRate); + long trDuration = RealTime::realTime2Frame(trDurationRT, m_sampleRate); + + if (trStart == 0 || trStart < startFrame) { + trStart = startFrame; + } + + if (trDuration == 0) { + trDuration = endFrame - trStart; + } + if (trStart + trDuration > endFrame) { + trDuration = endFrame - trStart; + } + + startFrame = trStart; + endFrame = trStart + trDuration; +*/ + + for (PluginMap::iterator pi = m_plugins.begin(); + pi != m_plugins.end(); ++pi) { + + for (TransformWriterMap::const_iterator ti = pi->second.begin(); + ti != pi->second.end(); ++ti) { + + const vector<FeatureWriter *> &writers = ti->second; + + for (int j = 0; j < (int)writers.size(); ++j) { + FeatureWriter::TrackMetadata m; + m.title = reader->getTitle(); + m.maker = reader->getMaker(); + writers[j]->setTrackMetadata(audioSource, m); + } + } + } + + ProgressPrinter extractionProgress("Extracting and writing features..."); + int progress = 0; + + for (long i = startFrame; i < endFrame; i += m_blockSize) { + + //!!! inefficient, although much of the inefficiency may be + // susceptible to optimisation + + SampleBlock frames; + reader->getInterleavedFrames(i, m_blockSize, frames); + + // We have to do our own channel handling here; we can't just + // leave it to the plugin adapter because the same plugin + // adapter may have to serve for input files with various + // numbers of channels (so the adapter is simply configured + // with a fixed channel count, generally 1). + + int rc = reader->getChannelCount(); + + for (int j = 0; j < m_blockSize; ++j) { + for (int c = 0; c < m_channels; ++c) { + int index; + if (c < rc) { + index = j * rc + c; + data[c][j] = 0.f; + } else { + index = j * rc + (c % rc); + } + if (index < (int)frames.size()) { + data[c][j] += frames[index]; + } + } + } + + Vamp::RealTime timestamp = Vamp::RealTime::frame2RealTime + (i, m_sampleRate); + + for (PluginMap::iterator pi = m_plugins.begin(); + pi != m_plugins.end(); ++pi) { + + Plugin *plugin = pi->first; + Plugin::FeatureSet featureSet = plugin->process(data, timestamp); + + if (!m_summariesOnly) { + writeFeatures(audioSource, plugin, featureSet); + } + } + + int pp = progress; + progress = ((i - startFrame) * 100) / (endFrame - startFrame); + if (progress > pp) extractionProgress.setProgress(progress); + } + + for (PluginMap::iterator pi = m_plugins.begin(); + pi != m_plugins.end(); ++pi) { + + Plugin *plugin = pi->first; + Plugin::FeatureSet featureSet = plugin->getRemainingFeatures(); + + if (!m_summariesOnly) { + writeFeatures(audioSource, plugin, featureSet); + } + + if (!m_summaries.empty()) { + PluginSummarisingAdapter *adapter = + dynamic_cast<PluginSummarisingAdapter *>(plugin); + if (!adapter) { + cerr << "WARNING: Summaries requested, but plugin is not a summarising adapter" << endl; + } else { + for (SummaryNameSet::const_iterator sni = m_summaries.begin(); + sni != m_summaries.end(); ++sni) { + featureSet.clear(); + //!!! problem here -- we are requesting summaries + //!!! for all outputs, but they in principle have + //!!! different averaging requirements depending + //!!! on whether their features have duration or + //!!! not + featureSet = adapter->getSummaryForAllOutputs + (getSummaryType(*sni), + PluginSummarisingAdapter::ContinuousTimeAverage); + writeFeatures(audioSource, plugin, featureSet,//!!! *sni); + Transform::stringToSummaryType(sni->c_str())); + } + } + } + + writeSummaries(audioSource, plugin); + } + + finish(); + + extractionProgress.setProgress(100); + + TempDirectory::getInstance()->cleanup(); +} + +void +FeatureExtractionManager::writeSummaries(QString audioSource, Plugin *plugin) +{ + // caller should have ensured plugin is in m_plugins + PluginMap::iterator pi = m_plugins.find(plugin); + + for (TransformWriterMap::const_iterator ti = pi->second.begin(); + ti != pi->second.end(); ++ti) { + + const Transform &transform = ti->first; + const vector<FeatureWriter *> &writers = ti->second; + + Transform::SummaryType summaryType = transform.getSummaryType(); + PluginSummarisingAdapter::SummaryType pType = + (PluginSummarisingAdapter::SummaryType)summaryType; + + if (transform.getSummaryType() == Transform::NoSummary) { + continue; + } + + PluginSummarisingAdapter *adapter = + dynamic_cast<PluginSummarisingAdapter *>(plugin); + if (!adapter) { + cerr << "FeatureExtractionManager::writeSummaries: INTERNAL ERROR: Summary requested for transform, but plugin is not a summarising adapter" << endl; + continue; + } + + Plugin::FeatureSet featureSet = adapter->getSummaryForAllOutputs + (pType, PluginSummarisingAdapter::ContinuousTimeAverage); + +// cout << "summary type " << int(pType) << " for transform:" << endl << transform.toXmlString().toStdString()<< endl << "... feature set with " << featureSet.size() << " elts" << endl; + + writeFeatures(audioSource, plugin, featureSet, summaryType); + } +} + +void FeatureExtractionManager::writeFeatures(QString audioSource, + Plugin *plugin, + const Plugin::FeatureSet &features, + Transform::SummaryType summaryType) +{ + // caller should have ensured plugin is in m_plugins + PluginMap::iterator pi = m_plugins.find(plugin); + + for (TransformWriterMap::const_iterator ti = pi->second.begin(); + ti != pi->second.end(); ++ti) { + + const Transform &transform = ti->first; + const vector<FeatureWriter *> &writers = ti->second; + + if (transform.getSummaryType() != Transform::NoSummary && + m_summaries.empty() && + summaryType == Transform::NoSummary) { + continue; + } + + if (transform.getSummaryType() != Transform::NoSummary && + summaryType != Transform::NoSummary && + transform.getSummaryType() != summaryType) { + continue; + } + + string outputId = transform.getOutput().toStdString(); + + if (m_pluginOutputs[plugin].find(outputId) == + m_pluginOutputs[plugin].end()) { + continue; + } + + const Plugin::OutputDescriptor &desc = + m_pluginOutputs[plugin][outputId]; + + int outputIndex = m_pluginOutputIndices[outputId]; + Plugin::FeatureSet::const_iterator fsi = features.find(outputIndex); + if (fsi == features.end()) continue; + + for (int j = 0; j < (int)writers.size(); ++j) { + writers[j]->write + (audioSource, transform, desc, fsi->second, + Transform::summaryTypeToString(summaryType).toStdString()); + } + } +} + +void FeatureExtractionManager::finish() +{ + for (PluginMap::iterator pi = m_plugins.begin(); + pi != m_plugins.end(); ++pi) { + + for (TransformWriterMap::iterator ti = pi->second.begin(); + ti != pi->second.end(); ++ti) { + + vector<FeatureWriter *> &writers = ti->second; + + for (int i = 0; i < (int)writers.size(); ++i) { + writers[i]->flush(); + writers[i]->finish(); + } + } + } +} + +void FeatureExtractionManager::print(Transform transform) const +{ + QString qs; + QTextStream qts(&qs); + transform.toXml(qts); + cerr << qs.toStdString() << endl; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FeatureExtractionManager.h Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,110 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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_MANAGER_H_ +#define _FEATURE_EXTRACTION_MANAGER_H_ + +#include <vector> +#include <set> +#include <string> + +#include <vamp-hostsdk/Plugin.h> +#include <vamp-hostsdk/PluginSummarisingAdapter.h> +#include <transform/Transform.h> + +using std::vector; +using std::set; +using std::string; +using std::pair; +using std::map; + +class FeatureWriter; + +class FeatureExtractionManager +{ +public: + FeatureExtractionManager(); + virtual ~FeatureExtractionManager(); + + void setChannels(int channels); + void setDefaultSampleRate(int sampleRate); + + bool setSummaryTypes(const set<string> &summaryTypes, + bool summariesOnly, + const Vamp::HostExt::PluginSummarisingAdapter::SegmentBoundaries &boundaries); + + bool addFeatureExtractor(Transform transform, + const vector<FeatureWriter*> &writers); + + bool addFeatureExtractorFromFile(QString transformXmlFile, + const vector<FeatureWriter*> &writers); + + bool addDefaultFeatureExtractor(TransformId transformId, + const vector<FeatureWriter*> &writers); + + void extractFeatures(QString audioSource); + +private: + // A plugin may have many outputs, so we can have more than one + // transform requested for a single plugin. The things we want to + // run in our process loop are plugins rather than their outputs, + // so we maintain a map from the plugins to the transforms desired + // of them and then iterate through this map + + typedef map<Transform, vector<FeatureWriter *> > TransformWriterMap; + typedef map<Vamp::Plugin *, TransformWriterMap> PluginMap; + PluginMap m_plugins; + + // And a map back from transforms to their plugins. Note that + // this is keyed by transform, not transform ID -- two differently + // configured transforms with the same ID must use different + // plugin instances. + + typedef map<Transform, Vamp::Plugin *> TransformPluginMap; + TransformPluginMap m_transformPluginMap; + + // Cache the plugin output descriptors, mapping from plugin to a + // map from output ID to output descriptor. + typedef map<string, Vamp::Plugin::OutputDescriptor> OutputMap; + typedef map<Vamp::Plugin *, OutputMap> PluginOutputMap; + PluginOutputMap m_pluginOutputs; + + // Map from plugin output identifier to plugin output index + typedef map<string, int> OutputIndexMap; + OutputIndexMap m_pluginOutputIndices; + + typedef set<std::string> SummaryNameSet; + SummaryNameSet m_summaries; + bool m_summariesOnly; + Vamp::HostExt::PluginSummarisingAdapter::SegmentBoundaries m_boundaries; + + void writeSummaries(QString audioSource, Vamp::Plugin *); + + void writeFeatures(QString audioSource, + Vamp::Plugin *, + const Vamp::Plugin::FeatureSet &, + Transform::SummaryType summaryType = + Transform::NoSummary); + void finish(); + + int m_blockSize; + int m_defaultSampleRate; + int m_sampleRate; + int m_channels; + + void print(Transform transform) const; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FeatureWriterFactory.cpp Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,49 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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 "FeatureWriterFactory.h" + +#include "DefaultFeatureWriter.h" +#include "rdf/RDFFeatureWriter.h" +#include "AudioDBFeatureWriter.h" +#include "transform/CSVFeatureWriter.h" + +set<string> +FeatureWriterFactory::getWriterTags() +{ + set<string> tags; + tags.insert("default"); + tags.insert("rdf"); + tags.insert("audiodb"); + tags.insert("csv"); + return tags; +} + +FeatureWriter * +FeatureWriterFactory::createWriter(string tag) +{ + if (tag == "default") { + return new DefaultFeatureWriter(); + } else if (tag == "rdf") { + return new RDFFeatureWriter(); + } else if (tag == "audiodb") { + return new AudioDBFeatureWriter(); + } else if (tag == "csv") { + return new CSVFeatureWriter(); + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FeatureWriterFactory.h Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,36 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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_WRITER_FACTORY_H_ +#define _FEATURE_WRITER_FACTORY_H_ + +#include <set> +#include <string> + +using std::set; +using std::string; + +class FeatureWriter; + +class FeatureWriterFactory +{ +public: + static set<string> getWriterTags(); + static FeatureWriter *createWriter(string tag); +}; + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,287 @@ + +Sonic Annotator +=============== + +Sonic Annotator is a utility program for batch feature extraction from +audio files. It runs Vamp audio analysis plugins on audio files, and +can write the result features in a selection of formats. + + +A Quick Tutorial +---------------- + +To use Sonic Annotator, you need to tell it three things: what audio +files to extract features from; what features to extract; and how and +where to write the results. You can also optionally tell it to +summarise the features. + + +1. What audio files to extract features from + +Sonic Annotator accepts a list of audio files on the command line. +Any argument that is not understood as a supported command-line option +will be taken to be the name of an audio file. Any number of files +may be listed. + +Several common audio file formats are supported, including MP3, Ogg, +and a number of PCM formats such as WAV and AIFF. AAC is supported on +OS/X only, and only if not DRM protected. WMA is not supported. + +File paths do not have to be local; you can also provide remote HTTP +or FTP URLs for Sonic Annotator to retrieve. + +Sonic Annotator also accepts the names of playlist files (.m3u +extension) and will process every file found in the playlist. + +Finally, you can provide a local directory path instead of a file, +together with the -r (recursive) option, for Sonic Annotator to +process every audio file found in that directory or any of its +subdirectories. + + +2. What features to extract + +Sonic Annotator applies "transforms" to its input audio files, where a +transform (in this terminology) consists of a Vamp plugin together +with a certain set of parameters and a specified execution context: +step and block size, sample rate, etc. + +(See http://www.vamp-plugins.org/ for more information about Vamp +plugins.) + +To use a particular transform, specify its filename on the command +line with the -t option. + +Transforms are usually described in RDF, following the transform part +of the Vamp plugin ontology (http://purl.org/ontology/vamp/). A +Transform may use any Vamp plugin that is currently installed and +available on the system. You can obtain a list of available plugin +outputs by running Sonic Annotator with the -l option, and you can +obtain a skeleton transform description for one of these plugins with +the -s option. + +For example, if the example plugins from the Vamp plugin SDK are +available and no other plugins are installed, you might have an +exchange like this: + + $ sonic-annotator -l + vamp:vamp-example-plugins:amplitudefollower:amplitude + vamp:vamp-example-plugins:fixedtempo:acf + vamp:vamp-example-plugins:fixedtempo:detectionfunction + vamp:vamp-example-plugins:fixedtempo:filtered_acf + vamp:vamp-example-plugins:fixedtempo:tempo + vamp:vamp-example-plugins:fixedtempo:candidates + vamp:vamp-example-plugins:percussiononsets:detectionfunction + vamp:vamp-example-plugins:percussiononsets:onsets + vamp:vamp-example-plugins:powerspectrum:powerspectrum + vamp:vamp-example-plugins:spectralcentroid:linearcentroid + vamp:vamp-example-plugins:spectralcentroid:logcentroid + vamp:vamp-example-plugins:zerocrossing:counts + vamp:vamp-example-plugins:zerocrossing:zerocrossings + $ sonic-annotator -s vamp:vamp-example-plugins:fixedtempo:tempo + @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . + @prefix vamp: <http://purl.org/ontology/vamp/> . + @prefix : <#> . + + :transform a vamp:Transform ; + vamp:plugin <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#fixedtempo> ; + vamp:step_size "64"^^xsd:int ; + vamp:block_size "256"^^xsd:int ; + vamp:parameter_binding [ + vamp:parameter [ vamp:identifier "maxbpm" ] ; + vamp:value "190"^^xsd:float ; + ] ; + vamp:parameter_binding [ + vamp:parameter [ vamp:identifier "maxdflen" ] ; + vamp:value "10"^^xsd:float ; + ] ; + vamp:parameter_binding [ + vamp:parameter [ vamp:identifier "minbpm" ] ; + vamp:value "50"^^xsd:float ; + ] ; + vamp:output <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#fixedtempo_output_tempo> . + $ + +The output of -s is an RDF/Turtle document describing the default +settings for the Tempo output of the Fixed Tempo Estimator plugin in +the Vamp plugin SDK. + +(The exact format of the RDF printed may differ -- e.g. if the +plugin's RDF description is not installed and so its "home" URI is not +known -- but the result should be functionally equivalent to this.) + +You could run this transform by saving the RDF to a file and +specifying that file with -t: + + $ sonic-annotator -s vamp:vamp-example-plugins:fixedtempo:tempo > test.n3 + $ sonic-annotator -t test.n3 audio.wav -w csv --csv-stdout + (... logging output on stderr, then ...) + "audio.wav",0.002902494,5.196916099,68.7916,"68.8 bpm" + $ + +The single line of output above consists of the audio file name, the +timestamp and duration for a single feature, the value of that feature +(the estimated tempo of the given region of time from that file, in +bpm -- the plugin in question performs a single tempo estimation and +nothing else) and the feature's label. + +A quicker way to achieve the above is to use the -d (default) option +to tell Sonic Annotator to use directly the default configuration for +a named transform: + + $ sonic-annotator -d vamp:vamp-example-plugins:fixedtempo:tempo audio.wav -w csv --csv-stdout + (... some log output on stderr, then ...) + "audio.wav",0.002902494,5.196916099,68.7916,"68.8 bpm" + $ + +Although handy for experimentation, the -d option is inadvisable in +any "production" situation because the plugin configuration is not +guaranteed to be the same each time (for example if an updated version +of a plugin changes some of its defaults). It's better to save a +well-defined transform to file and refer to that, even if it is simply +the transform created by the skeleton option. + +To run more than one transform on the same audio files, just put more +than one set of transform RDF descriptions in the same file, or give +the -t option more than once with separate transform description +files. Remember that if you want to specify more than one transform +in the same file, they will need to have distinct URIs (that is, the +":transform" part of the example above, which may be any arbitrary +name, must be distinct for each described transform). + + +3. How and where to write the results + +Sonic Annotator supports various different output modules (and it is +fairly easy for the developer to add new ones). You have to choose at +least one output module; use the -w (writer) option to do so. Each +module has its own set of parameters which can be adjusted on the +command line, as well as its own default rules about where to write +the results. + +The following writers are currently supported. (Others exist, but are +not properly implemented or not supported.) + + * csv + + Writes the results into comma-separated data files. + + One file is created for each transform applied to each input audio + file, named after the input audio file and transform name with .csv + suffix and ":" replaced by "_" throughout, placed in the same + directory as the audio file. + + To instruct Sonic Annotator to place the output files in another + location, use --csv-basedir with a directory name. + + To write a single file with all data in it, use --csv-one-file. + + To write all data to stdout instead of to a file, use --csv-stdout. + + Sonic Annotator will not write to an output file that already + exists. If you want to make it do this, use --csv-force to + overwrite or --csv-append to append to it. + + The data generated consists of one line for each result feature, + containing the feature timestamp, feature duration if present, all + of the feature's bin values in order, followed by the feature's + label if present. If the --csv-one-file or --csv-stdout option is + specified, then an additional column will appear before any of the + above, containing the audio file name from which the feature was + extracted, if it differs from that of the previous row. + + The default column separator is a comma; you can specify a + different one with the --csv-separator option. + + * rdf + + Writes the results into RDF/Turtle documents following the Audio + Features ontology (http://purl.org/ontology/af/). + + One file is created for each input audio file containing the + features extracted by all transforms applied to that file, named + after the input audio file with .n3 extension, placed in the same + directory as the audio file. + + To instruct Sonic Annotator to place the output files in another + location, use --rdf-basedir with a directory name. + + To write a single file with all data (from all input audio files) + in it, use --rdf-one-file. + + To write one file for each transform applied to each input audio + file, named after the input audio file and transform name with .n3 + suffix and ":" replaced by "_" throughout, use --rdf-many-files. + + To write all data to stdout instead of to a file, use --rdf-stdout. + + Sonic Annotator will not write to an output file that already + exists. If you want to make it do this, use --rdf-force to + overwrite or --rdf-append to append to it. + + Sonic Annotator will use plugin description RDF if available to + enhance its output (for example identifying note onset times as + note onset times, if the plugin's RDF says that is what it + produces, rather than writing them as plain events). Best results + will be obtained if an RDF document is provided with your plugins + (for example, vamp-example-plugins.n3) and you have this installed + in the same location as the plugins. To override this enhanced + output and write plain events for all features, use --rdf-plain. + + The output RDF will include an available_as property linking the + results to the original audio signal URI. By default, this will + point to the URI of the file or resource containing the audio that + Sonic Annotator processed, such as the file:/// location on disk. + To override this, for example to process a local copy of a file + while generating RDF that describes a copy of it available on a + network, you can use the --rdf-signal-uri option to specify an + alternative signal URI. + + +4. Optionally, how to summarise the features + +Sonic Annotator can also calculate and write summaries of features, +such as mean and median values. + +To obtain a summary as well as the feature results, just use the -S +option, naming the type of summary you want (min, max, mean, median, +mode, sum, variance, sd or count). You can also tell it to produce +only the summary, not the individual features, with --summary-only. + +Alternatively, you can specify a summary in a transform description. +The following example tells Sonic Annotator to write both the times of +note onsets estimated by the simple percussion onset detector example +plugin, and the variance of the plugin's onset detection function. +(It will only process the audio file and run the plugin once.) + + @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. + @prefix vamp: <http://purl.org/ontology/vamp/>. + @prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. + @prefix : <#>. + + :transform1 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_onsets . + + :transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_detectionfunction ; + vamp:summary_type "variance" . + +Sonic Annotator can also summarise in segments -- if you provide a +comma-separated list of times as an argument to the --segments option, +it will calculate one summary for each segment bounded by the times +you provided. For example, + + $ sonic-annotator -d vamp:vamp-example-plugins:percussiononsets:detectionfunction -S variance --sumary-only --segments 1,2,3 -w csv --csv-stdout audio.wav + (... some log output on stderr, then ...) + ,0.000000000,1.000000000,variance,1723.99,"(variance, continuous-time average)" + ,1.000000000,1.000000000,variance,1981.75,"(variance, continuous-time average)" + ,2.000000000,1.000000000,variance,1248.79,"(variance, continuous-time average)" + ,3.000000000,7.031020407,variance,1030.06,"(variance, continuous-time average)" + +Here the first row contains a summary covering the time period from 0 +to 1 second, the second from 1 to 2 seconds, the third from 2 to 3 +seconds and the fourth from 3 seconds to the end of the (short) audio +file. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/deploy_mac.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,34 @@ +#!/bin/bash + +# this script should be executed from the directory that contains the app directory (application bundle) +# it copies the required 3rd party libraries into the application bundle and corrects the library install names and references + +TARGETPATH="sonic-annotator.app/Contents/Frameworks/" + +mkdir "$TARGETPATH" + +QTPREFIX=/Library/Frameworks/ +QTFWKS="QtXml QtCore QtNetwork" + +# copy the dynamic libraries into the app bundle + +for FWK in $QTFWKS; do + cp ${QTPREFIX}${FWK}.framework/Versions/4/${FWK} "${TARGETPATH}" +done + +# change the id's of the dylibs +for FWK in $QTFWKS; do + install_name_tool -id @executable_path/../Frameworks/${FWK} "$TARGETPATH/$FWK" +done + +# tell the linker to look for dylibs in the app bundle +for FWK in $QTFWKS; do + install_name_tool -change ${FWK}.framework/Versions/4/${FWK} @executable_path/../Frameworks/${FWK} "sonic-annotator.app/Contents/MacOS/sonic-annotator" +done + +# correct dependencies between QT dylibs +for FWK in $QTFWKS; do + case $FWK in QtCore) continue;; esac + install_name_tool -change QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore "$TARGETPATH/${FWK}" +done +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/feature-description-example.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,82 @@ + +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix dc: <http://purl.org/dc/elements/1.1/> . +@prefix mo: <http://purl.org/ontology/mo/> . +@prefix af: <http://purl.org/ontology/af/> . +@prefix event: <http://purl.org/NET/c4dm/event.owl#> . +@prefix tl: <http://purl.org/NET/c4dm/timeline.owl#> . +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . +@prefix : <#> . + + +# Describe the signal we're annotating, and associate it with a +# timeline (the timeline is named as :base_timeline but never given +# any attributes in this document). Any feature that is associated +# with the same timeline will be taken as derived from this signal. + +:audio_signal a mo:Signal ; + mo:available_as <file:///path/to/myfile.wav> ; + mo:time :signal_interval . + +:signal_interval a tl:Interval ; + tl:onTimeLine :base_timeline ; + tl:beginsAt "PT0"^^xsd:duration . + + +# A sparse feature event. + +:event0 a af:Onset ; + event:time :time0 . + +:time0 a tl:Instant ; + tl:onTimeLine :base_timeline ; + tl:at "PT0.185759637S"^^xsd:duration . + +# Alternatively we could write that with a blank node. + +:event1 a af:Onset ; + event:time [ + a tl:Instant ; + tl:onTimeLine :base_timeline ; + tl:at "PT0.510839002S"^^xsd:duration ; + ] . + + +# For a dense feature, we need an appropriately sampled, windowed timeline. + +:feature_timeline a tl:DiscreteTimeLine . + +:feature_timeline_map a tl:UniformSamplingWindowingMap ; + tl:rangeTimeLine :feature_timeline ; + tl:domainTimeLine :base_timeline ; + tl:sampleRate "44100"^^xsd:int ; + tl:windowLength "1024"^^xsd:int ; + tl:hopSize "512"^^xsd:int . + + +# ... and an interval, defined in terms of hops (the discrete steps of +# the windowed timeline). + +:feature_interval a tl:Interval ; + tl:onTimeLine :feature_timeline ; + tl:beginsAt "0"^^xsd:int ; + tl:duration "5634"^^xsd:int . + + +# Then our feature is a signal that is on the interval we just +# described. We associate it explicitly with the original audio +# signal, although presumably we could leave the association implicit, +# to be derived from the relationships between timelines, just as it +# is for the sparse features above. + +:audio_signal af:signal_feature :feature1 . + +:feature_signal_type rdfs:subClassOf af:DetectionFunction ; + dc:title "Detection Function from Simple Percussion Onset Detector" . + +:feature1 a :feature_signal_type ; + mo:time :feature_interval ; + af:dimensions "12 12345" ; + af:value "0 0 0 0 0 0 0 1 2 3 1 24 236 123213 (etc)" . +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,735 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Annotator + A utility for batch feature extraction from audio files. + Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. + Copyright 2007-2008 QMUL. + + 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 <vector> +#include <string> +#include <iostream> + +#include <QCoreApplication> +#include <QSettings> +#include <QStringList> +#include <QString> +#include <QFileInfo> +#include <QDir> + +using std::cout; +using std::cerr; +using std::endl; +using std::vector; +using std::string; + +#include "base/Exceptions.h" +#include "base/TempDirectory.h" + +#include "data/fileio/AudioFileReaderFactory.h" +#include "data/fileio/PlaylistFileReader.h" + +#include "transform/Transform.h" +#include "transform/TransformFactory.h" + +#include "FeatureExtractionManager.h" +#include "transform/FeatureWriter.h" +#include "FeatureWriterFactory.h" + +#include "rdf/RDFTransformFactory.h" + +#include <vamp-hostsdk/PluginSummarisingAdapter.h> + +#ifdef HAVE_FFTW3 +#include <fftw3.h> +#endif + +// Desired options: +// +// * output preference: +// - all data in one file +// - one file per input file +// - one file per input file per transform +// - (any use for: one file per transform?) +// +// * output location: +// - same directory as input file +// - current directory +// +// * output filename: +// - based on input (obvious choice for one file per input file modes) +// - specified on command line (obvious choice for all in one file mode) +// +// * output format: one or more of +// - RDF +// - AudioDB +// - Vamp Simple Host format +// - CSV +// +// * input handling: +// - run each transform on each input file separately +// - provide all input files to the same transform, one per channel +// +// * format-specific options: +// - RDF format: fancy/plain RDF +// - CSV format: separator, timestamp type +// note: do the output file/location also count as format-specific options? +// an output writer that wrote to a database would have different options... +// +// * debug level and progress output +// +// * other potential options: +// - ignore version mismatches in Transform specifications +// - sample rate: force a given rate; use file rate instead of rate in +// Transform spec +// +// * other potential instructions: +// - write out a skeleton Transform file for a specified plugin +// - write out skeleton RDF for a plugin library (i.e. do the job of +// RDF template_generator) +// - verify that RDF for a plugin library matches the plugin +// +// MAYBE: +// * transform(s) to run: +// - supply transform file names on command line +// - use all transforms found in a given directory? +// +// MAYBE: +// * input files to transform: +// - supply file names or URIs on command line +// - use all files in a given directory or tree + +static QString +wrap(QString s, int len, int pfx = 0) +{ + QString ws; + QStringList sl(s.split(' ')); + int i = 0, c = 0; + while (i < sl.size()) { + int wl = sl[i].length(); + if (c + wl < len) { + if (c > 0) { + ws += ' '; + ++c; + } + } else { + if (c > 0) { + ws += '\n'; + for (int j = 0; j < pfx; ++j) ws += ' '; + c = 0; + } + } + ws += sl[i]; + c += wl; + ++i; + } + return ws; +} + +void usage(QString myname) +{ + set<string> writers = FeatureWriterFactory::getWriterTags(); + + cerr << endl; + cerr << "Sonic Annotator" << endl; + cerr << "A utility for batch feature extraction from audio files." << endl; + cerr << "Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London." << endl; + cerr << "Copyright 2007-2008 Queen Mary, University of London." << endl; + cerr << endl; + cerr << "This program is free software. You may redistribute copies of it under the" << endl; + cerr << "terms of the GNU General Public License <http://www.gnu.org/licenses/gpl.html>." << endl; + cerr << "This program is supplied with NO WARRANTY, to the extent permitted by law." << endl; + cerr << endl; + cerr << " Usage: " << myname.toStdString() + << " [-mr] -t trans.xml [...] -w <writer> [...] <audio> [...]" << endl; + cerr << " " << myname.toStdString() + << " [-mr] -T trans.txt [...] -w <writer> [...] <audio> [...]" << endl; + cerr << " " << myname.toStdString() + << " -s <transform>" << endl; + cerr << " " << myname.toStdString() + << " [-lh]" << endl; + cerr << endl; + cerr << "Where <audio> is an audio file or URL to use as input: either a local file" << endl; + cerr << "path, local \"file://\" URL, or remote \"http://\" or \"ftp://\" URL." << endl; + cerr << endl; + + QString extensions = AudioFileReaderFactory::getKnownExtensions(); + QStringList extlist = extensions.split(" ", QString::SkipEmptyParts); + if (!extlist.empty()) { + cerr << "The following audio file extensions are recognised:" << endl; + cerr << " "; + int c = 2; + for (int i = 0; i < extlist.size(); ++i) { + QString ext = extlist[i]; + if (ext.startsWith("*.")) ext = ext.right(ext.length()-2); + c += ext.length() + 2; + if (c >= 80) { + cerr << "\n "; + c -= 78; + } + cerr << ext.toStdString(); + if (i + 1 == extlist.size()) cerr << "."; + else cerr << ", "; + } + cerr << endl; + } + + cerr << "Playlist files in M3U format are also supported." << endl; + cerr << endl; + cerr << "Transformation options:" << endl; + cerr << endl; + cerr << " -t, --transform <T> Apply transform described in transform file <T> to" << endl; + cerr << " all input audio files. You may supply this option" << endl; + cerr << " multiple times. You must supply this option or -T at" << endl; + cerr << " least once for any work to be done. Transform format" << endl; + cerr << " may be SV transform XML or Vamp transform RDF. See" << endl; + cerr << " documentation for examples." << endl; + cerr << endl; + cerr << " -T, --transforms <T> Apply all transforms described in transform files" << endl; + cerr << " whose names are listed in text file <T>. You may supply" << endl; + cerr << " this option multiple times." << endl; + cerr << endl; + cerr << " -d, --default <I> Apply the default transform for transform id <I>. This" << endl; + cerr << " is equivalent to generating a skeleton transform for this" << endl; + cerr << " id (using the -s option, below) and then applying that," << endl; + cerr << " unmodified, with the -t option in the normal way. Note" << endl; + cerr << " that the results may vary as the implementation's default" << endl; + cerr << " processing parameters are not guaranteed. Do not use" << endl; + cerr << " this in production systems. You may supply this option" << endl; + cerr << " multiple times, and mix it with -t and -T." << endl; + cerr << endl; + cerr << " -w, --writer <W> Write output using writer type <W>." << endl; + cerr << " Supported writer types are: "; + for (set<string>::const_iterator i = writers.begin(); + i != writers.end(); ) { + cerr << *i; + if (++i != writers.end()) cerr << ", "; + else cerr << "."; + } + cerr << endl; + cerr << " You may supply this option multiple times. You must" << endl; + cerr << " supply this option at least once for any work to be done." << endl; + cerr << endl; + cerr << " -S, --summary <S> In addition to the result features, write summary feature" << endl; + cerr << " of summary type <S>." << endl; + cerr << " Supported summary types are: min, max, mean, median, mode," << endl; + cerr << " sum, variance, sd, count." << endl; + cerr << " You may supply this option multiple times." << endl; + cerr << endl; + cerr << " --summary-only Write only summary features; do not write the regular" << endl; + cerr << " result features." << endl; + cerr << endl; + cerr << " --segments <A>,<B>[,...]" << endl; + cerr << " Summarise in segments, with segment boundaries" << endl; + cerr << " at A, B, ... seconds." << endl; + cerr << endl; + +/*!!! This feature not implemented yet (sniff) + cerr << " -m, --multiplex If multiple input audio files are given, use mono" << endl; + cerr << " mixdowns of all files as the input channels for a single" << endl; + cerr << " invocation of each transform, instead of running the" << endl; + cerr << " transform against all files separately." << endl; + cerr << endl; +*/ + + cerr << " -r, --recursive If any of the <audio> arguments is found to be a local" << endl; + cerr << " directory, search the tree starting at that directory" << endl; + cerr << " for all supported audio files and take all of those as" << endl; + cerr << " input instead." << endl; + cerr << endl; + cerr << "Housekeeping options:" << endl; + cerr << endl; + cerr << " -l, --list List all known transform ids to standard output." << endl; + cerr << endl; + cerr << " -s, --skeleton <I> Generate a skeleton transform file for transform id <I>" << endl; + cerr << " and write it to standard output." << endl; + cerr << endl; + cerr << " -h, --help Show this help." << endl; + + cerr << endl; + cerr << "If no -w (or --writer) options are supplied, either the -l -s or -h option (or" << endl; + cerr << "long equivalent) must be given instead." << endl; + + for (set<string>::const_iterator i = writers.begin(); + i != writers.end(); ++i) { + FeatureWriter *w = FeatureWriterFactory::createWriter(*i); + if (!w) { + cerr << " (Internal error: failed to create writer of this type)" << endl; + continue; + } + FeatureWriter::ParameterList params = w->getSupportedParameters(); + delete w; + if (params.empty()) { + continue; + } + cerr << endl; + cerr << "Additional options for writer type \"" << *i << "\":" << endl; + cerr << endl; + for (FeatureWriter::ParameterList::const_iterator j = params.begin(); + j != params.end(); ++j) { + cerr << " --" << *i << "-" << j->name << " "; + int spaceage = 16 - int(i->length()) - int(j->name.length()); + if (j->hasArg) { cerr << "<X> "; spaceage -= 4; } + for (int k = 0; k < spaceage; ++k) cerr << " "; + QString s(j->description.c_str()); + s = wrap(s, 56, 22); + cerr << s.toStdString() << endl; + } + } + + cerr << endl; + exit(0); +} + +void +listTransforms() +{ + TransformList transforms = + TransformFactory::getInstance()->getAllTransformDescriptions(); + + for (TransformList::const_iterator iter = transforms.begin(); + iter != transforms.end(); ++iter) { + const TransformDescription &transform = *iter; + if (transform.type == TransformDescription::Analysis) { + cout << transform.identifier.toStdString() << endl; + } + } +} + +void +printSkeleton(QString id) +{ + Transform transform = + TransformFactory::getInstance()->getDefaultTransformFor(id); + cout << "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> ." << endl + << "@prefix vamp: <http://purl.org/ontology/vamp/> ." << endl + << "@prefix : <#> ." << endl << endl; + QString rdf = RDFTransformFactory::writeTransformToRDF + (transform, ":transform"); + cout << rdf.toStdString(); +} + +void +findSourcesRecursive(QString dirname, QStringList &addTo, int &found) +{ + QDir dir(dirname); + + QString printable = dir.dirName().left(20); + cerr << "\rScanning \"" << printable.toStdString() << "\"..." + << QString(" ").left(20 - printable.length()).toStdString() + << " [" << found << " audio file(s)]"; + + QString extensions = AudioFileReaderFactory::getKnownExtensions(); + QStringList extlist = extensions.split(" ", QString::SkipEmptyParts); + + QStringList files = dir.entryList + (extlist, QDir::Files | QDir::Readable); + for (int i = 0; i < files.size(); ++i) { + addTo.push_back(dir.filePath(files[i])); + ++found; + } + + QStringList subdirs = dir.entryList + (QStringList(), QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); + for (int i = 0; i < subdirs.size(); ++i) { + findSourcesRecursive(dir.filePath(subdirs[i]), addTo, found); + } +} + + +int main(int argc, char **argv) +{ + QCoreApplication application(argc, argv); + + QCoreApplication::setOrganizationName("QMUL"); + QCoreApplication::setOrganizationDomain("qmul.ac.uk"); + QCoreApplication::setApplicationName("Sonic Annotator"); + + QStringList args = application.arguments(); + set<string> requestedWriterTags; + set<string> requestedTransformFiles; + set<string> requestedTransformListFiles; + set<string> requestedDefaultTransforms; + set<string> requestedSummaryTypes; +//!!! bool multiplex = false; + bool recursive = false; + bool list = false; + bool summaryOnly = false; + QString skeletonFor = ""; + QString myname = args[0]; + myname = QFileInfo(myname).baseName(); + QStringList otherArgs; + Vamp::HostExt::PluginSummarisingAdapter::SegmentBoundaries boundaries; + + QString helpStr = myname + ": use -h or --help option for help"; + + for (int i = 1; i < args.size(); ++i) { + + QString arg = args[i]; + bool last = ((i + 1) == args.size()); + + if (arg == "-h" || arg == "--help" || arg == "-?") { + usage(myname); + } + + if (arg == "-w" || arg == "--writer") { + if (last || args[i+1].startsWith("-")) { + cerr << myname.toStdString() << ": argument expected for \"" + << arg.toStdString() << "\" option" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } else { + string tag = args[++i].toStdString(); + if (requestedWriterTags.find(tag) != requestedWriterTags.end()) { + cerr << myname.toStdString() << ": NOTE: duplicate specification of writer type \"" << tag << "\" ignored" << endl; + } else { + requestedWriterTags.insert(tag); + } + continue; + } + } else if (arg == "-t" || arg == "--transform") { + if (last || args[i+1].startsWith("-")) { + cerr << myname.toStdString() << ": argument expected for \"" + << arg.toStdString() << "\" option" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } else { + string transform = args[++i].toStdString(); + if (requestedTransformFiles.find(transform) != + requestedTransformFiles.end()) { + cerr << myname.toStdString() << ": NOTE: duplicate specification of transform file \"" << transform << "\" ignored" << endl; + } else { + requestedTransformFiles.insert(transform); + } + continue; + } + } else if (arg == "-T" || arg == "--transforms") { + if (last || args[i+1].startsWith("-")) { + cerr << myname.toStdString() << ": argument expected for \"" + << arg.toStdString() << "\" option" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } else { + string transform = args[++i].toStdString(); + if (requestedTransformListFiles.find(transform) != + requestedTransformListFiles.end()) { + cerr << myname.toStdString() << ": NOTE: duplicate specification of transform list file \"" << transform << "\" ignored" << endl; + } else { + requestedTransformListFiles.insert(transform); + } + continue; + } + } else if (arg == "-d" || arg == "--default") { + if (last || args[i+1].startsWith("-")) { + cerr << myname.toStdString() << ": argument expected for \"" + << arg.toStdString() << "\" option" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } else { + string deft = args[++i].toStdString(); + if (requestedDefaultTransforms.find(deft) != + requestedDefaultTransforms.end()) { + cerr << myname.toStdString() << ": NOTE: duplicate specification of default transform \"" << deft << "\" ignored" << endl; + } else { + requestedDefaultTransforms.insert(deft); + } + continue; + } + } else if (arg == "-S" || arg == "--summary") { + if (last || args[i+1].startsWith("-")) { + cerr << myname.toStdString() << ": argument expected for \"" + << arg.toStdString() << "\" option" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } else { + string summary = args[++i].toStdString(); + requestedSummaryTypes.insert(summary); + continue; + } + } else if (arg == "--summary-only") { + summaryOnly = true; + continue; + } else if (arg == "--segments") { + if (last) { + cerr << myname.toStdString() << ": argument expected for \"" + << arg.toStdString() << "\" option" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } else { + string segmentSpec = args[++i].toStdString(); + QStringList segmentStrs = QString(segmentSpec.c_str()).split(','); + for (int j = 0; j < segmentStrs.size(); ++j) { + bool good = false; + boundaries.insert(Vamp::RealTime::fromSeconds + (segmentStrs[j].toDouble(&good))); + if (!good) { + cerr << myname.toStdString() << ": segment boundaries must be numeric" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + } + } +/*!!! + } else if (arg == "-m" || arg == "--multiplex") { + multiplex = true; + cerr << myname.toStdString() + << ": WARNING: Multiplex argument not yet implemented" << endl; //!!! + continue; +*/ + } else if (arg == "-r" || arg == "--recursive") { + recursive = true; + continue; + } else if (arg == "-l" || arg == "--list") { + list = true; + continue; + } else if (arg == "-s" || arg == "--skeleton") { + if (last || args[i+1].startsWith("-")) { + cerr << myname.toStdString() << ": usage: " + << myname.toStdString() << " " << arg.toStdString() + << " <transform>" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } else { + skeletonFor = args[++i]; + continue; + } + } else { + otherArgs.push_back(args[i]); + } + } + + if (list) { + if (!requestedWriterTags.empty() || skeletonFor != "") { + cerr << helpStr.toStdString() << endl; + exit(2); + } + listTransforms(); + exit(0); + } + if (skeletonFor != "") { + if (!requestedWriterTags.empty()) { + cerr << helpStr.toStdString() << endl; + exit(2); + } + printSkeleton(skeletonFor); + exit(0); + } + + if (requestedTransformFiles.empty() && + requestedTransformListFiles.empty() && + requestedDefaultTransforms.empty()) { + cerr << myname.toStdString() + << ": no transform(s) specified" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + + if (requestedWriterTags.empty()) { + cerr << myname.toStdString() + << ": no writer(s) specified" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + + if (!boundaries.empty()) { + if (requestedSummaryTypes.empty()) { + cerr << myname.toStdString() + << ": summary segment boundaries provided, but no summary type specified" + << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + } + +#ifdef HAVE_FFTW3 + QSettings settings; + settings.beginGroup("FFTWisdom"); + QString wisdom = settings.value("wisdom").toString(); + if (wisdom != "") { + fftw_import_wisdom_from_string(wisdom.toLocal8Bit().data()); + } + settings.endGroup(); +#endif + + FeatureExtractionManager manager; + + if (!requestedSummaryTypes.empty()) { + if (!manager.setSummaryTypes(requestedSummaryTypes, + summaryOnly, + boundaries)) { + cerr << myname.toStdString() + << ": failed to set requested summary types" << endl; + exit(1); + } + } + + // the manager dictates the sample rate and number of channels + // to work at - files with too few channels are rejected, + // too many channels are handled as usual by the Vamp plugin + + //!!! Review this: although we probably do want to fix the channel + // count here, we don't necessarily want to fix the rate: it's + // specified in the Transform file. + + manager.setDefaultSampleRate(44100); + manager.setChannels(1); + + vector<FeatureWriter *> writers; + + for (set<string>::const_iterator i = requestedWriterTags.begin(); + i != requestedWriterTags.end(); ++i) { + + FeatureWriter *writer = FeatureWriterFactory::createWriter(*i); + + if (!writer) { + cerr << myname.toStdString() << ": unknown feature writer \"" + << *i << "\"" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + + map<string, string> writerArgs; + FeatureWriter::ParameterList pl(writer->getSupportedParameters()); + + for (int k = 0; k < pl.size(); ++k) { + + string argbase = pl[k].name; + QString literal = QString("--%1-%2") + .arg(i->c_str()).arg(argbase.c_str()); + + for (int j = 0; j < otherArgs.size(); ) { + + if (otherArgs[j] != literal) { + ++j; + continue; + } + + otherArgs.removeAt(j); + + if (pl[k].hasArg) { + if (j < otherArgs.size()) { + writerArgs[argbase] = otherArgs[j].toStdString(); + otherArgs.removeAt(j); + } else { + cerr << myname.toStdString() << ": " + << "argument required for \"" + << literal.toStdString() << "\" option" + << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + } else { + writerArgs[argbase] = ""; + } + } + } + + writer->setParameters(writerArgs); + + writers.push_back(writer); + } + + for (int i = 0; i < otherArgs.size(); ++i) { + if (otherArgs[i].startsWith("-")) { + cerr << myname.toStdString() << ": unknown option \"" + << otherArgs[i].toStdString() << "\"" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + } + + if (otherArgs.empty()) { + cerr << myname.toStdString() << ": no input(s) specified" << endl; + cerr << helpStr.toStdString() << endl; + exit(2); + } + + for (set<string>::const_iterator i = requestedTransformListFiles.begin(); + i != requestedTransformListFiles.end(); ++i) { + PlaylistFileReader reader(i->c_str()); + if (reader.isOK()) { + vector<QString> files = reader.load(); + for (int j = 0; j < files.size(); ++j) { + requestedTransformFiles.insert(files[j].toStdString()); + } + } else { + cerr << myname.toStdString() << ": failed to read template list file \"" << *i << "\"" << endl; + exit(2); + } + } + + bool haveFeatureExtractor = false; + + for (set<string>::const_iterator i = requestedTransformFiles.begin(); + i != requestedTransformFiles.end(); ++i) { + if (manager.addFeatureExtractorFromFile(i->c_str(), writers)) { + haveFeatureExtractor = true; + } + } + + for (set<string>::const_iterator i = requestedDefaultTransforms.begin(); + i != requestedDefaultTransforms.end(); ++i) { + if (manager.addDefaultFeatureExtractor(i->c_str(), writers)) { + haveFeatureExtractor = true; + } + } + + if (!haveFeatureExtractor) { + cerr << myname.toStdString() << ": no feature extractors added" << endl; + exit(2); + } + + QStringList sources; + if (!recursive) { + sources = otherArgs; + } else { + for (QStringList::const_iterator i = otherArgs.begin(); + i != otherArgs.end(); ++i) { + if (QDir(*i).exists()) { + cerr << "Directory found and recursive flag set, scanning for audio files..." << endl; + int found = 0; + findSourcesRecursive(*i, sources, found); + cerr << "\rDone, found " << found << " supported audio file(s) " << endl; + } else { + sources.push_back(*i); + } + } + } + + for (QStringList::const_iterator i = sources.begin(); + i != sources.end(); ++i) { + std::cerr << "Extracting features for: \"" << i->toStdString() << "\"" << std::endl; + try { + manager.extractFeatures(*i); + } catch (FailedToOpenFile f) { + cerr << "ERROR: Failed to open output file for feature writer: " + << f.what() << endl; + break; + } + } + + for (int i = 0; i < writers.size(); ++i) delete writers[i]; + +#ifdef HAVE_FFTW3 + settings.beginGroup("FFTWisdom"); + char *cwisdom = fftw_export_wisdom_to_string(); + if (cwisdom) { + settings.setValue("wisdom", cwisdom); + fftw_free(cwisdom); + } + settings.endGroup(); +#endif + + TempDirectory::getInstance()->cleanup(); + + return 0; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qm-keydetector.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,77 @@ +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. +@prefix xsd: <http://www.w3.org/2001/XMLSchema#>. +@prefix vamp: <http://www.vamp-plugins.org/ontology/> . +@prefix vampex: <http://www.vamp-plugins.org/examples/> . +@prefix qvp: <http://vamp-plugins.org/plugin/qm-vamp-plugins/>. +@prefix owl: <http://www.w3.org/2002/07/owl#> . +@prefix dc: <http://purl.org/dc/elements/1.1/> . +@prefix af: <http://purl.org/ontology/af/> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix cc: <http://web.resource.org/cc/> . +@prefix thisplug: <http://vamp-plugins.org/plugin/qm-vamp-plugins/qm-keydetector#> . +@prefix : <> . + +<> a vamp:PluginDescription ; + foaf:maker <http://chrissutton.org/me> ; + foaf:primaryTopic qvp:qm-keydetector . + +qvp:qm-keydetector a vamp:Plugin ; + dc:title "Key Detector" ; + dc:description ""; + foaf:maker :katynoland, :chrislandone ; +# cc:license <http://creativecommons.org/licenses/BSD/> ; what is the license for QM Vamp plugins ? + vamp:identifier "qm-keydetector" ; # The Vamp identifier for the plugin + vamp:vamp_API_version vamp:version_v1.1b ; # Made up - this plugin doesn't actually specify it + owl:versionInfo "2" ; + vamp:input_domain vamp:TimeDomain ; + + vamp:parameter_descriptor thisplug:pd1 ; + vamp:parameter_descriptor thisplug:pd2 ; + vamp:output_descriptor thisplug:od1 ; + vamp:output_descriptor thisplug:od2 ; + vamp:output_descriptor thisplug:od3 . + +:katynoland a foaf:Person; + foaf:name "Katy Noland" . +:chrislandone a foaf:Person; + foaf:name "Christian Landone" . + +# Note : any need for these to have proper URIs ? +thisplug:pd1 a vamp:ParameterDescriptor ; + vamp:identifier "tuning" ; + dc:title "Tuning Frequency" ; + dc:format "Hz" ; + vamp:minValue 420 ; #might be useful when interpreting plugin output + vamp:maxValue 460 ; + vamp:defaultValue 440 . + +thisplug:pd2 a vamp:ParameterDescriptor ; + vamp:identifier "length" ; + dc:title "Window Length" ; + vamp:minValue 1 ; #might be useful when interpreting plugin output + vamp:maxValue 30 ; + vamp:defaultValue 10 . + +thisplug:od1 a vamp:OutputDescriptor ; + vamp:identifier "tonic" ; + dc:title "Tonic Pitch" ; + vamp:fixed_bin_count "true" ; + vamp:bin_count 1 ; + vamp:sample_type vamp:OneSamplePerStep . + + +thisplug:od2 a vamp:OutputDescriptor ; + vamp:identifier "mode" ; + dc:title "Key Mode" ; + vamp:fixed_bin_count "true" ; + vamp:bin_count 1 ; + vamp:bin_names "Major = 0, Minor = 1" ; # might need a rethink + vamp:sample_type vamp:OneSamplePerStep . + +thisplug:od3 a vamp:OutputDescriptor ; + vamp:identifier "key" ; + dc:title "Key" ; + vamp:fixed_bin_count "true" ; + vamp:bin_count 1 ; + vamp:sample_type vamp:OneSamplePerStep ; + vamp:computes_feature_type <http://purl.org/NET/c4dm/keys.owl#Key> .
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/runner.pro Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,71 @@ + +TEMPLATE = app + +SV_UNIT_PACKAGES = vamp vamp-hostsdk samplerate mad id3tag oggz fishsound sndfile lrdf redland rasqal raptor + +#linux-g++:LIBS += -Wl,-Bstatic +#linux-g++:DEFINES += BUILD_STATIC + +load(../sonic-visualiser/sv.prf) + +LIBPATH += /usr/local/lib + +CONFIG += sv qt thread warn_on stl rtti exceptions console +QT += xml network +QT -= gui + +# Using the "console" CONFIG flag above should ensure this happens for +# normal Windows builds, but the console feature doesn't get picked up +# in my local cross-compile setup because qmake itself doesn't know to +# look for win32 features +win32-x-g++:QMAKE_LFLAGS += -Wl,-subsystem,console + +# If you have compiled your Vamp plugin SDK with FFTW (using its +# HAVE_FFTW3 flag), you can define the same flag here to ensure the +# program saves and restores FFTW wisdom in its configuration properly +# +#DEFINES += HAVE_FFTW3 + +TARGET = sonic-annotator + +DEPENDPATH += . ../sonic-visualiser i18n main +INCLUDEPATH += . ../sonic-visualiser main +LIBPATH = ../sonic-visualiser/audioio ../sonic-visualiser/data ../sonic-visualiser/plugin ../sonic-visualiser/rdf ../sonic-visualiser/transform ../sonic-visualiser/base ../sonic-visualiser/system $$LIBPATH + +QMAKE_CXXFLAGS_RELEASE += -fmessage-length=80 -fdiagnostics-show-location=every-line + +contains(DEFINES, BUILD_STATIC):LIBS -= -ljack + +#LIBS = -lsvaudioio -lsvdata -lsvtransform -lsvplugin -lsvrdf -lsvbase -lsvsystem $$LIBS +LIBS = -lsvdata -lsvtransform -lsvplugin -lsvrdf -lsvdata -lsvbase -lsvsystem $$LIBS + +PRE_TARGETDEPS += ../sonic-visualiser/audioio/libsvaudioio.a \ + ../sonic-visualiser/data/libsvdata.a \ + ../sonic-visualiser/transform/libsvtransform.a \ + ../sonic-visualiser/plugin/libsvplugin.a \ + ../sonic-visualiser/rdf/libsvrdf.a \ + ../sonic-visualiser/base/libsvbase.a \ + ../sonic-visualiser/system/libsvsystem.a + +OBJECTS_DIR = tmp_obj +MOC_DIR = tmp_moc + +# Input +HEADERS += \ + AudioDBFeatureWriter.h \ + FeatureWriterFactory.h \ + DefaultFeatureWriter.h \ + FeatureExtractionManager.h + +SOURCES += \ + main.cpp \ + DefaultFeatureWriter.cpp \ + FeatureExtractionManager.cpp \ + AudioDBFeatureWriter.cpp \ + FeatureWriterFactory.cpp + + + + +# Restore dynamic linkage, in case we went static earlier +linux-g++:LIBS += -Wl,-Bdynamic -lpthread -ldl -lz
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-query Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,17 @@ + +PREFIX vamp: <http://purl.org/ontology/vamp/> +PREFIX examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#> + +SELECT ?transform ?library ?library_id ?plugin +FROM <file:///work/runner/transforms/percussiononsets.n3> +FROM <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins> + +WHERE { + ?transform a vamp:Transform . + ?transform vamp:plugin ?plugin . + ?plugin a vamp:Plugin . + ?library a vamp:PluginLibrary . + ?library vamp:identifier ?library_id . + ?library vamp:available_plugin ?plugin . +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-query-dense-output Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,16 @@ + +PREFIX vamp: <http://purl.org/ontology/vamp/> +PREFIX mo: <http://purl.org/ontology/mo/> +PREFIX af: <http://purl.org/ontology/af/> + +SELECT ?signal_source ?feature_signal_type ?value +FROM <file:///share/music/wav/12-You Look So Fine.n3> + +WHERE { + ?signal mo:available_as ?signal_source . + ?signal a mo:Signal . + ?signal af:signal_feature ?feature . + ?feature a ?feature_signal_type. + ?feature af:value ?value . +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-query-plugin-for-transform Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,23 @@ + +PREFIX vamp: <http://purl.org/ontology/vamp/> + +SELECT ?transform ?plugin ?step_size ?block_size ?window_type ?program ?sample_rate ?start ?duration ?param_id ?param_value +FROM <file:///work/runner/transforms/percussiononsets.n3> + +WHERE { + ?transform a vamp:Transform . + ?transform vamp:plugin ?plugin . + OPTIONAL { ?transform vamp:step_size ?step_size } . + OPTIONAL { ?transform vamp:block_size ?block_size } . + OPTIONAL { ?transform vamp:window_type ?window_type } . + OPTIONAL { ?transform vamp:program ?program } . + OPTIONAL { ?transform vamp:sample_rate ?sample_rate } . + OPTIONAL { ?transform vamp:start ?start } . + OPTIONAL { ?transform vamp:duration ?duration } . + OPTIONAL { + ?transform vamp:parameter ?param . + ?param vamp:identifier ?param_id . + ?param vamp:value ?param_value + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-query-plugin-output-types Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,18 @@ + +PREFIX vamp: <http://purl.org/ontology/vamp/> +PREFIX examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#> + +SELECT ?output_id ?output_type ?feature_type ?event_type ?unit +FROM <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins> + +WHERE { + ?plugin a vamp:Plugin . + ?plugin vamp:identifier "percussiononsets" . + ?plugin vamp:output_descriptor ?output . + ?output vamp:identifier ?output_id . + ?output a ?output_type . + OPTIONAL { ?output vamp:computes_feature_type ?feature_type } . + OPTIONAL { ?output vamp:computes_event_type ?event_type } . + OPTIONAL { ?output vamp:unit ?unit } . +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-query-pluginid-for-rdf Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,15 @@ + +PREFIX vamp: <http://purl.org/ontology/vamp/> +PREFIX examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#> + +SELECT ?plugin ?library_id ?plugin_id +FROM <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins> + +WHERE { + ?plugin a vamp:Plugin . + ?plugin vamp:identifier ?plugin_id . + OPTIONAL { ?library a vamp:PluginLibrary . + ?library vamp:identifier ?library_id . + ?library vamp:available_plugin ?plugin . } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-query-transform-params Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,13 @@ +PREFIX vamp: <http://purl.org/ontology/vamp/> + +SELECT ?transform ?param_id ?param_value + +FROM <file:///work/runner/transforms/percussiononsets.n3> + +WHERE { + ?transform vamp:parameter_binding ?binding . + ?binding vamp:parameter ?param . + ?param vamp:identifier ?param_id . + ?binding vamp:value ?param_value . + } +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-query-transforms Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,21 @@ + +PREFIX vamp: <http://purl.org/ontology/vamp/> + +SELECT ?transform ?plugin ?output ?program + ?step_size ?block_size ?window_type + ?sample_rate ?start ?duration + +FROM <file:///work/runner/transforms/percussiononsets.n3> + +WHERE { + ?transform a vamp:Transform ; + vamp:plugin ?plugin . + OPTIONAL { ?transform vamp:output ?output } . + OPTIONAL { ?transform vamp:program ?program } . + OPTIONAL { ?transform vamp:step_size ?step_size } . + OPTIONAL { ?transform vamp:block_size ?block_size } . + OPTIONAL { ?transform vamp:window_type ?window_type } . + OPTIONAL { ?transform vamp:sample_rate ?sample_rate } . + OPTIONAL { ?transform vamp:start ?start } . + OPTIONAL { ?transform vamp:duration ?duration } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-queries/test-roqet Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,13 @@ + +PREFIX : <file:///work/runner/transforms/test.n3#> + +SELECT ?result ?mand + +FROM <file:///work/runner/transforms/test.n3> + +WHERE { + ?result :mand ?mand . + OPTIONAL { ?result :opt1 ?opt1 } . + OPTIONAL { ?result :opt2 ?opt2 } . +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-audioformat-percussiononsets-mp3.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,4 @@ +0.058049886 +0.824308390 +1.706666666 +2.461315192
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-audioformat-percussiononsets-ogg.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.777868480 +1.648616780 +2.414875283
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-audioformat-percussiononsets-wav.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.777868480 +1.648616780 +2.414875283
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-basic-percussiononsets-no-parameters-default-output.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.777868480 +1.648616780 +2.414875283
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-basic-percussiononsets-no-parameters.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.777868480 +1.648616780 +2.414875283
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-basic-percussiononsets-set-parameters.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,13 @@ +0.162539682 +0.290249433 +0.394739229 +0.777868480 +1.648616780 +2.414875283 +3.041814058 +3.134693877 +3.157913832 +3.599092970 +3.831292517 +4.504671201 +4.748480725
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-basic-percussiononsets-set-sample-rate.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.766258503 +1.648616780 +2.414875283
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-basic-percussiononsets-set-step-and-block-size.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.780294784 +1.648662131 +2.415328797
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-basic-percussiononsets.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.777868480 +1.648616780 +2.414875283
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-basic-skeleton-1.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,3 @@ +0.777868480 +1.648616780 +2.414875283
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-summaries-percussiononsets-all-summaries-only.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,9 @@ +0.000000000,count,448 +0.000000000,max,503 +0.000000000,mean,162.123 +0.000000000,median,168 +0.000000000,min,0 +0.000000000,mode,0 +0.000000000,sd,46.82 +0.000000000,sum,72631 +0.000000000,variance,2192.12
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-summaries-percussiononsets-from-rdf.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,7 @@ +0.777868480 +1.648616780 +2.414875283 +0.000000000,mean,668.509 +0.000000000,mean,162.123 +0.000000000,median,168 +0.000000000,mode,0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-summaries-percussiononsets-from-rdf.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,159 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix dc: <http://purl.org/dc/elements/1.1/> . +@prefix mo: <http://purl.org/ontology/mo/> . +@prefix af: <http://purl.org/ontology/af/> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix event: <http://purl.org/NET/c4dm/event.owl#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . +@prefix tl: <http://purl.org/NET/c4dm/timeline.owl#> . +@prefix vamp: <http://purl.org/ontology/vamp/> . + +:transform_0_onsets + vamp:output <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets_output_onsets> ; + vamp:plugin <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets> ; + vamp:sample_rate "44100"^^xsd:float ; + a vamp:Transform . + +<file:///work/runner/tests/audio/3clicks8.wav> + a mo:AudioFile . + +:signal_1 + mo:available_as <file:///work/runner/tests/audio/3clicks8.wav> ; + mo:time [ + tl:onTimeLine :signal_timeline_1 ; + a tl:Interval + ] ; + a mo:Signal . + +:event_2 + event:time [ + tl:at "PT0.777868480S"^^xsd:duration ; + tl:onTimeLine :signal_timeline_1 ; + a tl:Instant + ] ; + vamp:computed_by :transform_0_onsets ; + a af:Onset . + +:event_3 + event:time [ + tl:at "PT1.648616780S"^^xsd:duration ; + tl:onTimeLine :signal_timeline_1 ; + a tl:Instant + ] ; + vamp:computed_by :transform_0_onsets ; + a af:Onset . + +:event_4 + event:time [ + tl:at "PT2.414875283S"^^xsd:duration ; + tl:onTimeLine :signal_timeline_1 ; + a tl:Instant + ] ; + vamp:computed_by :transform_0_onsets ; + a af:Onset . + +:transform_5_detectionfunction + vamp:block_size "4096"^^xsd:int ; + vamp:output <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets_output_detectionfunction> ; + vamp:plugin <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets> ; + vamp:sample_rate "44100"^^xsd:float ; + vamp:step_size "2048"^^xsd:int ; + vamp:summary_type "mean" ; + a vamp:Transform . + +:event_type_6 + dc:description "Broadband energy rise detection function" ; + dc:format "" ; + dc:title "Detection Function" ; + rdfs:subClassOf event:Event . + +:event_7 + event:time [ + tl:beginsAt "PT0.000000000S"^^xsd:duration ; + tl:duration "PT5.201269840S"^^xsd:duration ; + tl:onTimeLine :signal_timeline_1 ; + a tl:Interval + ] ; + af:feature "668.509" ; + vamp:computed_by :transform_5_detectionfunction ; + a :event_type_6 ; + rdfs:label "(mean value, continuous-time average)" . + +:transform_8_detectionfunction + vamp:block_size "1024"^^xsd:int ; + vamp:output <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets_output_detectionfunction> ; + vamp:plugin <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets> ; + vamp:sample_rate "44100"^^xsd:float ; + vamp:step_size "512"^^xsd:int ; + vamp:summary_type "mean" ; + a vamp:Transform . + +:event_type_9 + dc:description "Broadband energy rise detection function" ; + dc:format "" ; + dc:title "Detection Function" ; + rdfs:subClassOf event:Event . + +:event_10 + event:time [ + tl:beginsAt "PT0.000000000S"^^xsd:duration ; + tl:duration "PT5.201269840S"^^xsd:duration ; + tl:onTimeLine :signal_timeline_1 ; + a tl:Interval + ] ; + af:feature "162.123" ; + vamp:computed_by :transform_8_detectionfunction ; + a :event_type_9 ; + rdfs:label "(mean value, continuous-time average)" . + +:transform_11_detectionfunction + vamp:output <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets_output_detectionfunction> ; + vamp:plugin <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets> ; + vamp:sample_rate "44100"^^xsd:float ; + vamp:summary_type "median" ; + a vamp:Transform . + +:event_type_12 + dc:description "Broadband energy rise detection function" ; + dc:format "" ; + dc:title "Detection Function" ; + rdfs:subClassOf event:Event . + +:event_13 + event:time [ + tl:beginsAt "PT0.000000000S"^^xsd:duration ; + tl:duration "PT5.201269840S"^^xsd:duration ; + tl:onTimeLine :signal_timeline_1 ; + a tl:Interval + ] ; + af:feature "168" ; + vamp:computed_by :transform_11_detectionfunction ; + a :event_type_12 ; + rdfs:label "(median value, continuous-time average)" . + +:transform_14_detectionfunction + vamp:output <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets_output_detectionfunction> ; + vamp:plugin <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#percussiononsets> ; + vamp:sample_rate "44100"^^xsd:float ; + vamp:summary_type "mode" ; + a vamp:Transform . + +:event_type_15 + dc:description "Broadband energy rise detection function" ; + dc:format "" ; + dc:title "Detection Function" ; + rdfs:subClassOf event:Event . + +:event_16 + event:time [ + tl:beginsAt "PT0.000000000S"^^xsd:duration ; + tl:duration "PT5.201269840S"^^xsd:duration ; + tl:onTimeLine :signal_timeline_1 ; + a tl:Interval + ] ; + af:feature "0" ; + vamp:computed_by :transform_14_detectionfunction ; + a :event_type_15 ; + rdfs:label "(modal value, continuous-time average)" . +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-summaries-percussiononsets-with-mean.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,449 @@ +0.000000000,0 +0.011609977,170 +0.023219954,184 +0.034829931,166 +0.046439909,174 +0.058049886,179 +0.069659863,162 +0.081269841,157 +0.092879818,156 +0.104489795,182 +0.116099773,168 +0.127709750,168 +0.139319727,155 +0.150929705,200 +0.162539682,163 +0.174149659,178 +0.185759637,164 +0.197369614,166 +0.208979591,137 +0.220589569,155 +0.232199546,177 +0.243809523,145 +0.255419501,172 +0.267029478,155 +0.278639455,201 +0.290249433,166 +0.301859410,169 +0.313469387,158 +0.325079365,169 +0.336689342,155 +0.348299319,187 +0.359909297,177 +0.371519274,149 +0.383129251,196 +0.394739229,160 +0.406349206,174 +0.417959183,165 +0.429569160,149 +0.441179138,181 +0.452789115,180 +0.464399092,156 +0.476009070,163 +0.487619047,188 +0.499229024,173 +0.510839002,160 +0.522448979,168 +0.534058956,154 +0.545668934,155 +0.557278911,161 +0.568888888,163 +0.580498866,172 +0.592108843,168 +0.603718820,181 +0.615328798,167 +0.626938775,172 +0.638548752,158 +0.650158730,172 +0.661768707,167 +0.673378684,180 +0.684988662,188 +0.696598639,160 +0.708208616,166 +0.719818594,158 +0.731428571,176 +0.743038548,153 +0.754648526,173 +0.766258503,449 +0.777868480,30 +0.789478458,70 +0.801088435,181 +0.812698412,165 +0.824308390,174 +0.835918367,181 +0.847528344,179 +0.859138321,154 +0.870748299,169 +0.882358276,150 +0.893968253,189 +0.905578231,159 +0.917188208,172 +0.928798185,157 +0.940408163,167 +0.952018140,169 +0.963628117,155 +0.975238095,189 +0.986848072,178 +0.998458049,168 +1.010068027,169 +1.021678004,178 +1.033287981,157 +1.044897959,166 +1.056507936,162 +1.068117913,170 +1.079727891,186 +1.091337868,178 +1.102947845,178 +1.114557823,155 +1.126167800,173 +1.137777777,156 +1.149387755,158 +1.160997732,170 +1.172607709,167 +1.184217687,160 +1.195827664,180 +1.207437641,153 +1.219047619,154 +1.230657596,171 +1.242267573,159 +1.253877551,194 +1.265487528,170 +1.277097505,157 +1.288707482,184 +1.300317460,156 +1.311927437,173 +1.323537414,184 +1.335147392,168 +1.346757369,182 +1.358367346,147 +1.369977324,164 +1.381587301,163 +1.393197278,165 +1.404807256,181 +1.416417233,172 +1.428027210,169 +1.439637188,165 +1.451247165,166 +1.462857142,158 +1.474467120,162 +1.486077097,188 +1.497687074,176 +1.509297052,176 +1.520907029,159 +1.532517006,183 +1.544126984,178 +1.555736961,168 +1.567346938,171 +1.578956916,158 +1.590566893,153 +1.602176870,189 +1.613786848,171 +1.625396825,142 +1.637006802,503 +1.648616780,0 +1.660226757,30 +1.671836734,189 +1.683446712,146 +1.695056689,174 +1.706666666,171 +1.718276643,169 +1.729886621,164 +1.741496598,181 +1.753106575,180 +1.764716553,163 +1.776326530,174 +1.787936507,135 +1.799546485,193 +1.811156462,187 +1.822766439,176 +1.834376417,172 +1.845986394,155 +1.857596371,185 +1.869206349,167 +1.880816326,173 +1.892426303,162 +1.904036281,166 +1.915646258,167 +1.927256235,179 +1.938866213,170 +1.950476190,158 +1.962086167,168 +1.973696145,162 +1.985306122,182 +1.996916099,167 +2.008526077,185 +2.020136054,165 +2.031746031,184 +2.043356009,157 +2.054965986,167 +2.066575963,164 +2.078185941,160 +2.089795918,181 +2.101405895,165 +2.113015873,181 +2.124625850,161 +2.136235827,176 +2.147845804,177 +2.159455782,150 +2.171065759,185 +2.182675736,173 +2.194285714,162 +2.205895691,169 +2.217505668,171 +2.229115646,140 +2.240725623,196 +2.252335600,155 +2.263945578,171 +2.275555555,186 +2.287165532,157 +2.298775510,166 +2.310385487,169 +2.321995464,183 +2.333605442,186 +2.345215419,138 +2.356825396,162 +2.368435374,180 +2.380045351,165 +2.391655328,181 +2.403265306,444 +2.414875283,27 +2.426485260,150 +2.438095238,166 +2.449705215,177 +2.461315192,174 +2.472925170,165 +2.484535147,158 +2.496145124,178 +2.507755102,177 +2.519365079,172 +2.530975056,174 +2.542585034,168 +2.554195011,165 +2.565804988,168 +2.577414965,149 +2.589024943,171 +2.600634920,164 +2.612244897,163 +2.623854875,182 +2.635464852,162 +2.647074829,156 +2.658684807,173 +2.670294784,188 +2.681904761,166 +2.693514739,157 +2.705124716,170 +2.716734693,167 +2.728344671,191 +2.739954648,154 +2.751564625,175 +2.763174603,157 +2.774784580,169 +2.786394557,160 +2.798004535,163 +2.809614512,191 +2.821224489,158 +2.832834467,184 +2.844444444,164 +2.856054421,176 +2.867664399,182 +2.879274376,180 +2.890884353,138 +2.902494331,170 +2.914104308,172 +2.925714285,172 +2.937324263,168 +2.948934240,186 +2.960544217,171 +2.972154195,154 +2.983764172,185 +2.995374149,172 +3.006984126,164 +3.018594104,176 +3.030204081,195 +3.041814058,160 +3.053424036,124 +3.065034013,181 +3.076643990,170 +3.088253968,178 +3.099863945,165 +3.111473922,164 +3.123083900,194 +3.134693877,157 +3.146303854,205 +3.157913832,163 +3.169523809,159 +3.181133786,184 +3.192743764,145 +3.204353741,170 +3.215963718,155 +3.227573696,161 +3.239183673,164 +3.250793650,184 +3.262403628,175 +3.274013605,155 +3.285623582,164 +3.297233560,181 +3.308843537,182 +3.320453514,145 +3.332063492,177 +3.343673469,162 +3.355283446,153 +3.366893424,185 +3.378503401,174 +3.390113378,167 +3.401723356,187 +3.413333333,157 +3.424943310,170 +3.436553287,169 +3.448163265,166 +3.459773242,171 +3.471383219,165 +3.482993197,158 +3.494603174,181 +3.506213151,168 +3.517823129,175 +3.529433106,162 +3.541043083,167 +3.552653061,179 +3.564263038,167 +3.575873015,156 +3.587482993,209 +3.599092970,179 +3.610702947,159 +3.622312925,180 +3.633922902,152 +3.645532879,169 +3.657142857,189 +3.668752834,170 +3.680362811,156 +3.691972789,165 +3.703582766,179 +3.715192743,173 +3.726802721,163 +3.738412698,170 +3.750022675,181 +3.761632653,177 +3.773242630,181 +3.784852607,166 +3.796462585,153 +3.808072562,164 +3.819682539,209 +3.831292517,159 +3.842902494,194 +3.854512471,164 +3.866122448,184 +3.877732426,163 +3.889342403,173 +3.900952380,165 +3.912562358,164 +3.924172335,182 +3.935782312,170 +3.947392290,160 +3.959002267,173 +3.970612244,160 +3.982222222,174 +3.993832199,179 +4.005442176,179 +4.017052154,145 +4.028662131,196 +4.040272108,155 +4.051882086,170 +4.063492063,180 +4.075102040,156 +4.086712018,159 +4.098321995,182 +4.109931972,175 +4.121541950,173 +4.133151927,164 +4.144761904,186 +4.156371882,160 +4.167981859,175 +4.179591836,178 +4.191201814,159 +4.202811791,177 +4.214421768,181 +4.226031746,177 +4.237641723,163 +4.249251700,158 +4.260861678,188 +4.272471655,163 +4.284081632,158 +4.295691609,164 +4.307301587,164 +4.318911564,183 +4.330521541,160 +4.342131519,182 +4.353741496,172 +4.365351473,172 +4.376961451,179 +4.388571428,154 +4.400181405,166 +4.411791383,174 +4.423401360,156 +4.435011337,174 +4.446621315,169 +4.458231292,169 +4.469841269,178 +4.481451247,175 +4.493061224,193 +4.504671201,153 +4.516281179,160 +4.527891156,176 +4.539501133,167 +4.551111111,184 +4.562721088,163 +4.574331065,150 +4.585941043,156 +4.597551020,182 +4.609160997,168 +4.620770975,168 +4.632380952,152 +4.643990929,174 +4.655600907,186 +4.667210884,168 +4.678820861,173 +4.690430839,184 +4.702040816,169 +4.713650793,166 +4.725260770,164 +4.736870748,193 +4.748480725,155 +4.760090702,164 +4.771700680,181 +4.783310657,142 +4.794920634,183 +4.806530612,181 +4.818140589,185 +4.829750566,171 +4.841360544,184 +4.852970521,156 +4.864580498,162 +4.876190476,182 +4.887800453,161 +4.899410430,175 +4.911020408,168 +4.922630385,172 +4.934240362,151 +4.945850340,176 +4.957460317,171 +4.969070294,93 +4.980680272,0 +4.992290249,0 +5.003900226,0 +5.015510204,0 +5.027120181,0 +5.038730158,0 +5.050340136,0 +5.061950113,0 +5.073560090,0 +5.085170068,0 +5.096780045,0 +5.108390022,0 +5.120000000,0 +5.131609977,0 +5.143219954,0 +5.154829931,0 +5.166439909,0 +5.178049886,0 +5.189659863,0 +0.000000000,mean,162.123
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/expected/transforms-summaries-percussiononsets.csv Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,448 @@ +0.000000000,0 +0.011609977,170 +0.023219954,184 +0.034829931,166 +0.046439909,174 +0.058049886,179 +0.069659863,162 +0.081269841,157 +0.092879818,156 +0.104489795,182 +0.116099773,168 +0.127709750,168 +0.139319727,155 +0.150929705,200 +0.162539682,163 +0.174149659,178 +0.185759637,164 +0.197369614,166 +0.208979591,137 +0.220589569,155 +0.232199546,177 +0.243809523,145 +0.255419501,172 +0.267029478,155 +0.278639455,201 +0.290249433,166 +0.301859410,169 +0.313469387,158 +0.325079365,169 +0.336689342,155 +0.348299319,187 +0.359909297,177 +0.371519274,149 +0.383129251,196 +0.394739229,160 +0.406349206,174 +0.417959183,165 +0.429569160,149 +0.441179138,181 +0.452789115,180 +0.464399092,156 +0.476009070,163 +0.487619047,188 +0.499229024,173 +0.510839002,160 +0.522448979,168 +0.534058956,154 +0.545668934,155 +0.557278911,161 +0.568888888,163 +0.580498866,172 +0.592108843,168 +0.603718820,181 +0.615328798,167 +0.626938775,172 +0.638548752,158 +0.650158730,172 +0.661768707,167 +0.673378684,180 +0.684988662,188 +0.696598639,160 +0.708208616,166 +0.719818594,158 +0.731428571,176 +0.743038548,153 +0.754648526,173 +0.766258503,449 +0.777868480,30 +0.789478458,70 +0.801088435,181 +0.812698412,165 +0.824308390,174 +0.835918367,181 +0.847528344,179 +0.859138321,154 +0.870748299,169 +0.882358276,150 +0.893968253,189 +0.905578231,159 +0.917188208,172 +0.928798185,157 +0.940408163,167 +0.952018140,169 +0.963628117,155 +0.975238095,189 +0.986848072,178 +0.998458049,168 +1.010068027,169 +1.021678004,178 +1.033287981,157 +1.044897959,166 +1.056507936,162 +1.068117913,170 +1.079727891,186 +1.091337868,178 +1.102947845,178 +1.114557823,155 +1.126167800,173 +1.137777777,156 +1.149387755,158 +1.160997732,170 +1.172607709,167 +1.184217687,160 +1.195827664,180 +1.207437641,153 +1.219047619,154 +1.230657596,171 +1.242267573,159 +1.253877551,194 +1.265487528,170 +1.277097505,157 +1.288707482,184 +1.300317460,156 +1.311927437,173 +1.323537414,184 +1.335147392,168 +1.346757369,182 +1.358367346,147 +1.369977324,164 +1.381587301,163 +1.393197278,165 +1.404807256,181 +1.416417233,172 +1.428027210,169 +1.439637188,165 +1.451247165,166 +1.462857142,158 +1.474467120,162 +1.486077097,188 +1.497687074,176 +1.509297052,176 +1.520907029,159 +1.532517006,183 +1.544126984,178 +1.555736961,168 +1.567346938,171 +1.578956916,158 +1.590566893,153 +1.602176870,189 +1.613786848,171 +1.625396825,142 +1.637006802,503 +1.648616780,0 +1.660226757,30 +1.671836734,189 +1.683446712,146 +1.695056689,174 +1.706666666,171 +1.718276643,169 +1.729886621,164 +1.741496598,181 +1.753106575,180 +1.764716553,163 +1.776326530,174 +1.787936507,135 +1.799546485,193 +1.811156462,187 +1.822766439,176 +1.834376417,172 +1.845986394,155 +1.857596371,185 +1.869206349,167 +1.880816326,173 +1.892426303,162 +1.904036281,166 +1.915646258,167 +1.927256235,179 +1.938866213,170 +1.950476190,158 +1.962086167,168 +1.973696145,162 +1.985306122,182 +1.996916099,167 +2.008526077,185 +2.020136054,165 +2.031746031,184 +2.043356009,157 +2.054965986,167 +2.066575963,164 +2.078185941,160 +2.089795918,181 +2.101405895,165 +2.113015873,181 +2.124625850,161 +2.136235827,176 +2.147845804,177 +2.159455782,150 +2.171065759,185 +2.182675736,173 +2.194285714,162 +2.205895691,169 +2.217505668,171 +2.229115646,140 +2.240725623,196 +2.252335600,155 +2.263945578,171 +2.275555555,186 +2.287165532,157 +2.298775510,166 +2.310385487,169 +2.321995464,183 +2.333605442,186 +2.345215419,138 +2.356825396,162 +2.368435374,180 +2.380045351,165 +2.391655328,181 +2.403265306,444 +2.414875283,27 +2.426485260,150 +2.438095238,166 +2.449705215,177 +2.461315192,174 +2.472925170,165 +2.484535147,158 +2.496145124,178 +2.507755102,177 +2.519365079,172 +2.530975056,174 +2.542585034,168 +2.554195011,165 +2.565804988,168 +2.577414965,149 +2.589024943,171 +2.600634920,164 +2.612244897,163 +2.623854875,182 +2.635464852,162 +2.647074829,156 +2.658684807,173 +2.670294784,188 +2.681904761,166 +2.693514739,157 +2.705124716,170 +2.716734693,167 +2.728344671,191 +2.739954648,154 +2.751564625,175 +2.763174603,157 +2.774784580,169 +2.786394557,160 +2.798004535,163 +2.809614512,191 +2.821224489,158 +2.832834467,184 +2.844444444,164 +2.856054421,176 +2.867664399,182 +2.879274376,180 +2.890884353,138 +2.902494331,170 +2.914104308,172 +2.925714285,172 +2.937324263,168 +2.948934240,186 +2.960544217,171 +2.972154195,154 +2.983764172,185 +2.995374149,172 +3.006984126,164 +3.018594104,176 +3.030204081,195 +3.041814058,160 +3.053424036,124 +3.065034013,181 +3.076643990,170 +3.088253968,178 +3.099863945,165 +3.111473922,164 +3.123083900,194 +3.134693877,157 +3.146303854,205 +3.157913832,163 +3.169523809,159 +3.181133786,184 +3.192743764,145 +3.204353741,170 +3.215963718,155 +3.227573696,161 +3.239183673,164 +3.250793650,184 +3.262403628,175 +3.274013605,155 +3.285623582,164 +3.297233560,181 +3.308843537,182 +3.320453514,145 +3.332063492,177 +3.343673469,162 +3.355283446,153 +3.366893424,185 +3.378503401,174 +3.390113378,167 +3.401723356,187 +3.413333333,157 +3.424943310,170 +3.436553287,169 +3.448163265,166 +3.459773242,171 +3.471383219,165 +3.482993197,158 +3.494603174,181 +3.506213151,168 +3.517823129,175 +3.529433106,162 +3.541043083,167 +3.552653061,179 +3.564263038,167 +3.575873015,156 +3.587482993,209 +3.599092970,179 +3.610702947,159 +3.622312925,180 +3.633922902,152 +3.645532879,169 +3.657142857,189 +3.668752834,170 +3.680362811,156 +3.691972789,165 +3.703582766,179 +3.715192743,173 +3.726802721,163 +3.738412698,170 +3.750022675,181 +3.761632653,177 +3.773242630,181 +3.784852607,166 +3.796462585,153 +3.808072562,164 +3.819682539,209 +3.831292517,159 +3.842902494,194 +3.854512471,164 +3.866122448,184 +3.877732426,163 +3.889342403,173 +3.900952380,165 +3.912562358,164 +3.924172335,182 +3.935782312,170 +3.947392290,160 +3.959002267,173 +3.970612244,160 +3.982222222,174 +3.993832199,179 +4.005442176,179 +4.017052154,145 +4.028662131,196 +4.040272108,155 +4.051882086,170 +4.063492063,180 +4.075102040,156 +4.086712018,159 +4.098321995,182 +4.109931972,175 +4.121541950,173 +4.133151927,164 +4.144761904,186 +4.156371882,160 +4.167981859,175 +4.179591836,178 +4.191201814,159 +4.202811791,177 +4.214421768,181 +4.226031746,177 +4.237641723,163 +4.249251700,158 +4.260861678,188 +4.272471655,163 +4.284081632,158 +4.295691609,164 +4.307301587,164 +4.318911564,183 +4.330521541,160 +4.342131519,182 +4.353741496,172 +4.365351473,172 +4.376961451,179 +4.388571428,154 +4.400181405,166 +4.411791383,174 +4.423401360,156 +4.435011337,174 +4.446621315,169 +4.458231292,169 +4.469841269,178 +4.481451247,175 +4.493061224,193 +4.504671201,153 +4.516281179,160 +4.527891156,176 +4.539501133,167 +4.551111111,184 +4.562721088,163 +4.574331065,150 +4.585941043,156 +4.597551020,182 +4.609160997,168 +4.620770975,168 +4.632380952,152 +4.643990929,174 +4.655600907,186 +4.667210884,168 +4.678820861,173 +4.690430839,184 +4.702040816,169 +4.713650793,166 +4.725260770,164 +4.736870748,193 +4.748480725,155 +4.760090702,164 +4.771700680,181 +4.783310657,142 +4.794920634,183 +4.806530612,181 +4.818140589,185 +4.829750566,171 +4.841360544,184 +4.852970521,156 +4.864580498,162 +4.876190476,182 +4.887800453,161 +4.899410430,175 +4.911020408,168 +4.922630385,172 +4.934240362,151 +4.945850340,176 +4.957460317,171 +4.969070294,93 +4.980680272,0 +4.992290249,0 +5.003900226,0 +5.015510204,0 +5.027120181,0 +5.038730158,0 +5.050340136,0 +5.061950113,0 +5.073560090,0 +5.085170068,0 +5.096780045,0 +5.108390022,0 +5.120000000,0 +5.131609977,0 +5.143219954,0 +5.154829931,0 +5.166439909,0 +5.178049886,0 +5.189659863,0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-as-advertised.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,82 @@ +#!/bin/bash + +mypath=`dirname $0` +r=$mypath/../sonic-annotator + +infile=$mypath/audio/3clicks8.wav +testplug=vamp:vamp-example-plugins:percussiononsets +tmpdir=$mypath/tmp_1_$$.dir +tmpwav=$tmpdir/test.wav + +trap "rm -rf $tmpdir" 0 + +fail() { + echo "Test failed: $1" + exit 1 +} + +types=`\ + $r --help 2>&1 | \ + grep 'Supported writer types are:' | \ + sed -e 's/^.*://' -e 's/[,\.]//g' \ + ` +[ -n "$types" ] || \ + fail "Fails to report sensible list of writers in help text?" + +onsets=$mypath/transforms/transforms-as-advertised-percussiononsets-onsets.n3 +df=$mypath/transforms/transforms-as-advertised-percussiononsets-detectionfunction.n3 + +adbdir=$tmpdir/audiodb-test +mkdir -p $adbdir + +for type in $types; do + + mkdir -p $tmpdir + cp $infile $tmpwav + + # Some of these are special cases: + # + # * The "default" writer type always prints to stdout instead of + # to a file. + # + # * The "audiodb" writer will not print any output for features + # that have no values (but are only point events). I don't know + # how reasonable that is, but it's clearly intentional. It also + # writes to a subdirectory $basedir/$catid/$trackid.$output + + case $type in + audiodb) + $r -t $df -w $type $tmpwav --audiodb-basedir $tmpdir --audiodb-catid `basename $adbdir` 2>/dev/null || \ + fail "Fails to run with reader type \"$type\" and default options" + ;; + default) + $r -t $onsets -w $type $tmpwav > $tmpdir/test.out 2>/dev/null || \ + fail "Fails to run with reader type \"$type\" and default options" + ;; + *) + $r -t $onsets -w $type $tmpwav 2>/dev/null || \ + fail "Fails to run with reader type \"$type\" and default options" + ;; + esac + newfiles=`ls $tmpdir | fgrep -v .wav` + if [ "$type" = audiodb ]; then newfiles=`ls $adbdir`; fi + + [ -n "$newfiles" ] || \ + fail "Fails to create output file for reader \"$type\" with default options" + + case `echo $newfiles | wc -w` in + [2-9]) + if [ "$type" != audiodb ]; then + fail "Produces more than one output file for reader \"$type\" with default options" + fi + ;; + 1) + if [ "$type" = audiodb ]; then + fail "Produces only one output file for reader \"$type\" with default options (expected two)" + fi + ;; + esac + + rm -r $tmpdir +done +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-audioformat.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,49 @@ +#!/bin/bash + +mypath=`dirname $0` +r=$mypath/../sonic-annotator + +inbase=$mypath/audio/3clicks +testplug=vamp:vamp-example-plugins:percussiononsets +tmpfile1=$mypath/tmp_1_$$ +tmpfile2=$mypath/tmp_2_$$ + +trap "rm -f $tmpfile1 $tmpfile2" 0 + +fail() { + echo "Test failed: $1" + exit 1 +} + +for extension in wav ogg mp3 ; do + + transform=$mypath/transforms/transforms-audioformat-percussiononsets.n3 + expected=$mypath/expected/transforms-audioformat-percussiononsets-$extension.csv + + test -f $transform || \ + fail "Internal error: no transforms file for suffix $suffix" + + test -f $expected || \ + fail "Internal error: no expected output file for suffix $suffix" + + infile=$inbase.$extension + if [ "$extension" = "wav" ]; then infile=${inbase}8.$extension; fi + + test -f $infile || \ + fail "Internal error: no input audio file for extension $extension" + + $r -t $transform -w csv --csv-stdout $infile > $tmpfile2 2>/dev/null || \ + fail "Fails to run transform $transform against audio file $infile" + + if [ "$extension" = "wav" ]; then + cmp -s $tmpfile2 $expected || \ + fail "Output mismatch for transform $transform with audio file $infile" + else + cmp -s $tmpfile2 $expected || \ + ( echo "NOTE: Output mismatch for transform $transform with audio file $infile" ; \ + echo "This may be the result of differences in the audio file decoder, so I am not" ; \ + echo "failing the test, but I recommend that you check the results." ) + fi +done + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-helpfulflags.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,40 @@ +#!/bin/bash + +mypath=`dirname $0` +r=$mypath/../sonic-annotator + +testplug=vamp:vamp-example-plugins:percussiononsets + +fail() { + echo "Test failed: $1" + exit 1 +} + +$r >/dev/null 2>&1 && \ + fail "Return code 0 when run without args (should be a failure code)" + +$r 2>&1 >/dev/null | grep -q "for help" || \ + fail "Improper response when run without args" + +$r --help 2>&1 | grep -q Copy || \ + fail "Expected help not printed when run with --help" + +$r --list >/dev/null 2>&1 || \ + fail "Fails to run with --list" + +$r --list 2>/dev/null | grep -q $testplug || \ + fail "Fails to print $testplug in plugin list (if you haven't got it, install it -- it's needed for other tests)" + +$r --skeleton $testplug >/dev/null || \ + fail "Fails to run with --skeleton $testplug" + +$r -s $testplug >/dev/null || \ + fail "Fails to run with -s $testplug" + +$r --skeleton $testplug >/dev/null || \ + fail "Fails to run with --skeleton $testplug" + +$r --skeleton $testplug | rapper -i turtle - test >/dev/null 2>&1 || \ + fail "Invalid XML skeleton produced with --skeleton $testplug" + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rdf-destinations.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,144 @@ +#!/bin/bash + +mypath=`dirname $0` +r=$mypath/../sonic-annotator + +infile1=$mypath/audio/3clicks8.wav +infile2=$mypath/audio/6clicks8.wav + +outfile1=$mypath/audio/3clicks8.n3 +outfile2=$mypath/audio/6clicks8.n3 + +outfile3=$mypath/audio/3clicks8_vamp_vamp-example-plugins_percussiononsets_onsets.n3 +outfile4=$mypath/audio/3clicks8_vamp_vamp-example-plugins_percussiononsets_detectionfunction.n3 +outfile5=$mypath/audio/6clicks8_vamp_vamp-example-plugins_percussiononsets_onsets.n3 +outfile6=$mypath/audio/6clicks8_vamp_vamp-example-plugins_percussiononsets_detectionfunction.n3 + +testplug=vamp:vamp-example-plugins:percussiononsets +tmpttl=$mypath/tmp_1_$$.ttl + +trap "rm -f $tmpttl $outfile1 $outfile2 $outfile3 $outfile4 $outfile5 $outfile6" 0 + +fail() { + echo "Test failed: $1" + exit 1 +} + +transformpfx=$mypath/transforms/transforms-rdf-writer-percussiononsets + +check_rdf() { + test -f $1 || \ + fail "Fails to write output to expected location $1 for $2" + rapper -i turtle $1 >/dev/null 2>&1 || \ + fail "Fails to produce parseable RDF/TTL for $2" + rapper -i turtle -c $1 2>&1 | egrep -q 'Parsing returned [1-9][0-9]+ triples' || \ + fail "RDF output contains no triples (?) for $2" + rm -f $1 +} + + +ctx="onsets transform, one audio file, default RDF writer destination" + +rm -f $outfile1 + +$r -t $transformpfx-onsets.n3 -w rdf $infile1 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $outfile1 "$ctx" + + +ctx="onsets and df transforms, one audio file, default RDF writer destination" + +rm -f $outfile1 + +$r -t $transformpfx-onsets.n3 -t $transformpfx-detectionfunction.n3 -w rdf $infile1 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $outfile1 "$ctx" + + +ctx="onsets transform, two audio files, default RDF writer destination" + +rm -f $outfile1 +rm -f $outfile2 + +$r -t $transformpfx-onsets.n3 -w rdf $infile1 $infile2 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $outfile1 "$ctx" +check_rdf $outfile2 "$ctx" + + +ctx="onsets transform, two audio files, one-file RDF writer" + +$r -t $transformpfx-onsets.n3 -w rdf --rdf-one-file $tmpttl $infile1 $infile2 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $tmpttl "$ctx" + + +ctx="onsets transform, two audio files, stdout RDF writer" + +$r -t $transformpfx-onsets.n3 -w rdf --rdf-stdout $infile1 $infile2 2>/dev/null >$tmpttl || \ + fail "Fails to run with $ctx" + +check_rdf $tmpttl "$ctx" + + +ctx="onsets transform, one audio file, many-files RDF writer" + +rm -f $outfile3 + +$r -t $transformpfx-onsets.n3 -w rdf --rdf-many-files $infile1 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $outfile3 "$ctx" + + +ctx="onsets transform, two audio files, many-files RDF writer" + +rm -f $outfile3 +rm -f $outfile5 + +$r -t $transformpfx-onsets.n3 -w rdf --rdf-many-files $infile1 $infile2 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $outfile3 "$ctx" +check_rdf $outfile5 "$ctx" + + +ctx="onsets and df transforms, two audio files, many-files RDF writer" + +rm -f $outfile3 +rm -f $outfile4 +rm -f $outfile5 +rm -f $outfile6 + +$r -t $transformpfx-onsets.n3 -t $transformpfx-detectionfunction.n3 -w rdf --rdf-many-files $infile1 $infile2 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $outfile3 "$ctx" +check_rdf $outfile4 "$ctx" +check_rdf $outfile5 "$ctx" +check_rdf $outfile6 "$ctx" + + +ctx="existing output file and no --rdf-force" + +touch $outfile1 + +$r -t $transformpfx-onsets.n3 -w rdf $infile1 2>/dev/null && \ + fail "Fails by completing successfully when output file already exists (should refuse and bail out)" + + +ctx="existing output file and --rdf-force" + +touch $outfile1 + +$r -t $transformpfx-onsets.n3 -w rdf --rdf-force $infile1 2>/dev/null || \ + fail "Fails to run with $ctx" + +check_rdf $outfile1 "$ctx" + + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rdf-writer.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,59 @@ +#!/bin/bash + +mypath=`dirname $0` +r=$mypath/../sonic-annotator + +infile=$mypath/audio/3clicks8.wav +testplug=vamp:vamp-example-plugins:percussiononsets +tmpttl=$mypath/tmp_1_$$.ttl + +trap "rm -f $tmpttl" 0 + +fail() { + echo "Test failed: $1" + exit 1 +} + +transformpfx=$mypath/transforms/transforms-rdf-writer-percussiononsets + +for rdfarg in "" "--rdf-plain" ; do + + note="" + [ -n "$rdfarg" ] && note=" with $rdfarg" + + rm -f $tmpttl + + $r -t $transformpfx-onsets.n3 -w rdf $infile $rdfarg --rdf-one-file $tmpttl 2>/dev/null || \ + fail "Fails to run with onsets transform and RDF writer$note" + + rapper -i turtle $tmpttl >/dev/null 2>&1 || \ + fail "Fails to produce parseable RDF/TTL for onsets transform$note" + + rapper -i turtle -c $tmpttl 2>&1 | egrep -q 'Parsing returned [1-9][0-9]+ triples' || + fail "RDF output contains no triples (?) for onsets transform$note" + + rm -f $tmpttl + + $r -t $transformpfx-detectionfunction.n3 -w rdf $infile $rdfarg --rdf-one-file $tmpttl 2>/dev/null || \ + fail "Fails to run with detectionfunction transform and RDF writer$note" + + rapper -i turtle $tmpttl >/dev/null 2>&1 || \ + fail "Fails to produce parseable RDF/TTL for detectionfunction transform$note" + + rapper -i turtle -c $tmpttl 2>&1 | egrep -q 'Parsing returned [1-9][0-9]+ triples' || + fail "RDF output contains no triples (?) for detectionfunction transform$note" + + rm -f $tmpttl + + $r -t $transformpfx-onsets.n3 -t $transformpfx-detectionfunction.n3 -w rdf $infile $rdfarg --rdf-one-file $tmpttl 2>/dev/null || \ + fail "Fails to run with detectionfunction and onsets transforms together and RDF writer$note" + + rapper -i turtle $tmpttl >/dev/null 2>&1 || \ + fail "Fails to produce parseable RDF/TTL for detectionfunction and onsets transforms together$note" + + rapper -i turtle -c $tmpttl 2>&1 | egrep -q 'Parsing returned [1-9][0-9]+ triples' || + fail "RDF output contains no triples (?) for detectionfunction and onsets transforms together$note" + +done + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-summaries.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,72 @@ +#!/bin/bash + +mypath=`dirname $0` +r=$mypath/../sonic-annotator + +infile=$mypath/audio/3clicks8.wav +tmpfile=$mypath/tmp_1_$$ +tmpcanonical=$mypath/tmp_2_$$ + +trap "rm -f $tmpfile $tmpcanonical" 0 + +fail() { + echo "Test failed: $1" + if [ -n "$2" -a -n "$3" ]; then + echo "Output follows:" + echo "--" + cat $2 + echo "--" + echo "Expected output follows:" + echo "--" + cat $3 + echo "--" + echo "Diff:" + echo "--" + diff -u $2 $3 + echo "--" + fi + exit 1 +} + +# transform to which we have to add summarisation on command line +transform=$mypath/transforms/transforms-nosummaries-percussiononsets-detectionfunction.n3 +expected=$mypath/expected/transforms-summaries-percussiononsets + +stransform=$mypath/transforms/transforms-summaries-percussiononsets-detectionfunction.n3 +sexpected=$mypath/expected/transforms-summaries-percussiononsets-from-rdf + +$r -t $transform -w csv --csv-stdout $infile > $tmpfile 2>/dev/null || \ + fail "Fails to run transform $transform" + +cmp -s $tmpfile ${expected}.csv || \ + fail "Output mismatch for transform $transform" $tmpfile ${expected}.csv + +$r -t $transform -w csv --csv-stdout -S mean $infile > $tmpfile 2>/dev/null || \ + fail "Fails to run transform $transform with summary type mean" + +cmp -s $tmpfile ${expected}-with-mean.csv || \ + fail "Output mismatch for transform $transform with summary type mean" $tmpfile ${expected}-with-mean.csv + +$r -t $transform -w csv --csv-stdout -S min -S max -S mean -S median -S mode -S sum -S variance -S sd -S count --summary-only $infile > $tmpfile 2>/dev/null || \ + fail "Fails to run transform $transform with all summary types and summary-only" + +cmp -s $tmpfile ${expected}-all-summaries-only.csv || \ + fail "Output mismatch for transform $transform with all summary types and summary-only" $tmpfile ${expected}-all-summaries-only.csv + +$r -t $stransform -w csv --csv-stdout $infile > $tmpfile 2>/dev/null || \ + fail "Fails to run transform $stransform with CSV output" + +cmp -s $tmpfile ${sexpected}.csv || \ + fail "Output mismatch for transform $stransform" $tmpfile ${sexpected}.csv + +$r -t $stransform -w rdf --rdf-stdout $infile > $tmpfile 2>/dev/null || \ + fail "Fails to run transform $stransform with RDF output" + +rapper -i turtle $tmpfile -o turtle 2>/dev/null | grep -v '^@prefix :' > $tmpcanonical || + fail "Fails to produce parseable RDF/TTL for transform $stransform" + +cmp -s $tmpcanonical ${sexpected}.n3 || \ + fail "Output mismatch for canonicalised version of transform $stransform" $tmpcanonical ${sexpected}.n3 + +exit 0 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-supportprogs.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,15 @@ +#!/bin/bash + +fail() { + echo "Test failed: $1" + exit 1 +} + +xmllint --version 2>/dev/null || \ + fail "Can't find required xmllint program" + +rapper --version >/dev/null || \ + fail "Can't find required rapper program" + +exit 0 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-transforms-basic.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,56 @@ +#!/bin/bash + +mypath=`dirname $0` +r=$mypath/../sonic-annotator + +infile=$mypath/audio/3clicks8.wav +testplug=vamp:vamp-example-plugins:percussiononsets +tmpfile1=$mypath/tmp_1_$$ +tmpfile2=$mypath/tmp_2_$$ + +trap "rm -f $tmpfile1 $tmpfile2" 0 + +fail() { + echo "Test failed: $1" + exit 1 +} + +$r --skeleton $testplug > $tmpfile1 2>/dev/null || \ + fail "Fails to run with --skeleton $testplug" + +$r -t $tmpfile1 -w csv --csv-stdout $infile > $tmpfile2 2>/dev/null || \ + fail "Fails to run with -t $tmpfile -w csv --csv-stdout $infile" + +cmp -s $tmpfile2 $mypath/expected/transforms-basic-skeleton-1.csv || \ + fail "Output mismatch for transforms-basic-skeleton-1.csv" + +for suffix in \ + -no-parameters-default-output \ + -no-parameters \ + "" \ + -set-parameters \ + -set-step-and-block-size \ + -set-sample-rate \ + ; do + + for type in xml n3 ; do + + transform=$mypath/transforms/transforms-basic-percussiononsets$suffix.$type + expected=$mypath/expected/transforms-basic-percussiononsets$suffix.csv + + test -f $transform || \ + fail "Internal error: no transforms file for suffix $suffix" + + test -f $expected || \ + fail "Internal error: no expected output file for suffix $suffix" + + $r -t $transform -w csv --csv-stdout $infile > $tmpfile2 2>/dev/null || \ + fail "Fails to run transform $transform" + + cmp -s $tmpfile2 $expected || \ + fail "Output mismatch for transform $transform" + done +done + +exit 0 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test.sh Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,25 @@ +#!/bin/bash + +mypath=`dirname $0` + +for x in \ + supportprogs \ + helpfulflags \ + transforms-basic \ + audioformat \ + as-advertised \ + rdf-writer \ + rdf-destinations \ + summaries \ + ; do + + echo -n "$x: " + if bash $mypath/test-$x.sh; then + echo test succeeded + else + echo "*** Test FAILED" + exit 1 + fi + +done +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-as-advertised-percussiononsets-detectionfunction.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,11 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets; + vamp:output examples:percussiononsets_output_detectionfunction. + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-as-advertised-percussiononsets-onsets.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,10 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets. + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-audioformat-percussiononsets.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,10 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets. + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-no-parameters-default-output.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,10 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets. + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-no-parameters-default-output.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,2 @@ +<transform id="vamp:vamp-example-plugins:percussiononsets"/> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-no-parameters.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,11 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_onsets . + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-no-parameters.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,1 @@ +<transform id="vamp:vamp-example-plugins:percussiononsets:onsets"/>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-set-parameters.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,22 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_onsets ; + vamp:step_size "512"; + vamp:block_size "1024"; + vamp:parameter_binding :param0 ; + vamp:parameter_binding :param1 . + +:param0 a vamp:ParameterBinding; + vamp:parameter [ vamp:identifier "sensitivity" ]; + vamp:value "60". + +:param1 a vamp:ParameterBinding; + vamp:parameter examples:percussiononsets_param_threshold; + vamp:value "2.6". + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-set-parameters.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,7 @@ +<transform + id="vamp:vamp-example-plugins:percussiononsets:onsets" + stepSize="512" + blockSize="1024"> + <parameter name="sensitivity" value="60"/> + <parameter name="threshold" value="2.6"/> +</transform>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-set-sample-rate.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,11 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_onsets ; + vamp:sample_rate "22050" . + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-set-sample-rate.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,4 @@ +<transform + id="vamp:vamp-example-plugins:percussiononsets:onsets" + sampleRate="22050"> +</transform>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-set-step-and-block-size.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,11 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_onsets ; + vamp:step_size "345"; + vamp:block_size "512". +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets-set-step-and-block-size.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,5 @@ +<transform + id="vamp:vamp-example-plugins:percussiononsets:onsets" + stepSize="345" + blockSize="512" + />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,22 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_onsets ; + vamp:step_size "512"; + vamp:block_size "1024"; + vamp:parameter_binding :param0 ; + vamp:parameter_binding :param1 . + +:param0 a vamp:ParameterBinding; + vamp:parameter [ vamp:identifier "sensitivity" ]; + vamp:value "40". + +:param1 a vamp:ParameterBinding; + vamp:parameter examples:percussiononsets_param_threshold; + vamp:value "3". + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-basic-percussiononsets.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,13 @@ +<transform + id="vamp:vamp-example-plugins:percussiononsets:onsets" + pluginVersion="2" + program="" + stepSize="512" + blockSize="1024" + windowType="hanning" + startTime="0.000000000" + duration="0.000000000" + sampleRate="0"> + <parameter name="sensitivity" value="40"/> + <parameter name="threshold" value="3"/> +</transform>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-nosummaries-percussiononsets-detectionfunction.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,9 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_detectionfunction . +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-rdf-writer-percussiononsets-detectionfunction.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,11 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_detectionfunction . + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-rdf-writer-percussiononsets-onsets.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,10 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets. + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/transforms/transforms-summaries-percussiononsets-detectionfunction.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,32 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; # 8 + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_detectionfunction ; + vamp:summary_type "mean" . + +:transform1 a vamp:Transform; # 11 + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_detectionfunction ; + vamp:summary_type "median" . + +:transform2 a vamp:Transform; # 0 + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_onsets . + +:transform3 a vamp:Transform; # 14 + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_detectionfunction ; + vamp:summary_type "mode" . + +:transform4 a vamp:Transform; # 23 + vamp:plugin examples:percussiononsets ; + vamp:output examples:percussiononsets_output_detectionfunction ; + vamp:step_size 2048 ; + vamp:block_size 4096 ; + vamp:summary_type "mean" . + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transforms/chromagram.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,7 @@ +<transform id="vamp:qm-vamp-plugins:qm-chromagram" program="" stepSize="0" blockSize="0" windowType="hanning" startTime="0.000000000" duration="0.000000000" sampleRate="0" > + <parameter name="bpo" value="12"/> + <parameter name="maxpitch" value="96"/> + <parameter name="minpitch" value="12"/> + <parameter name="normalized" value="1"/> + <parameter name="tuning" value="440"/> +</transform>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transforms/percussiononsets-detectionfunction.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,23 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets; + vamp:output examples:percussiononsets_output_detectionfunction; +# vamp:step_size "256"; +# vamp:block_size "512"; + vamp:window_type "Hanning"; + vamp:parameter_binding :param0 ; + vamp:parameter_binding :param1 . + +:param0 a vamp:ParameterBinding; + vamp:parameter [ vamp:identifier "sensitivity" ]; + vamp:value "60". + +:param1 a vamp:ParameterBinding; + vamp:parameter examples:percussiononsets_param_threshold; + vamp:value "2". + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transforms/percussiononsets-detectionfunction.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,5 @@ +<transform id="vamp:vamp-example-plugins:percussiononsets:detectionfunction" program="" stepSize="512" blockSize="1024" windowType="hanning" startTime="0.000000000" duration="0.000000000" sampleRate="0" > + <parameter name="sensitivity" value="40"/> + <parameter name="threshold" value="3"/> +</transform> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transforms/percussiononsets.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,24 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix examples: <http://vamp-plugins.org/rdf/plugins/vamp-example-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin examples:percussiononsets; + vamp:output examples:percussiononsets_output_onsets; + vamp:step_size "256"; + vamp:block_size "512"; +# vamp:sample_rate "44100"; + vamp:window_type "Hanning"; + vamp:parameter_binding :param0 ; + vamp:parameter_binding :param1 . + +:param0 a vamp:ParameterBinding; + vamp:parameter [ vamp:identifier "sensitivity" ]; + vamp:value "40". + +:param1 a vamp:ParameterBinding; + vamp:parameter examples:percussiononsets_param_threshold; + vamp:value "3". + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transforms/percussiononsets.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,4 @@ +<transform id="vamp:vamp-example-plugins:percussiononsets" program="" stepSize="512" blockSize="1024" windowType="hanning" startTime="0.000000000" duration="0.000000000" sampleRate="0" > + <parameter name="sensitivity" value="40"/> + <parameter name="threshold" value="3"/> +</transform>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transforms/segmentation.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,13 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. +@prefix vamp: <http://purl.org/ontology/vamp/>. +@prefix qmp: <http://vamp-plugins.org/rdf/plugins/qm-vamp-plugins#>. +@prefix : <#>. + +:transform0 a vamp:Transform; + vamp:plugin qmp:qm-segmenter; + vamp:output qmp:qm-segmenter_output_segmentation; + vamp:step_size ""; + vamp:block_size ""; + vamp:window_type "". + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transforms/spectralcentroid.xml Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,1 @@ +<transform id="vamp:vamp-example-plugins:spectralcentroid" program="" stepSize="512" blockSize="1024" windowType="hanning" startTime="0.000000000" duration="0.000000000" sampleRate="22050" /> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-example-plugins:percussiononsets.n3 Thu Dec 11 10:22:33 2008 +0000 @@ -0,0 +1,70 @@ +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. +@prefix xsd: <http://www.w3.org/2001/XMLSchema#>. +@prefix vamp: <http://www.vamp-plugins.org/ontology/> . +@prefix vampex: <http://www.vamp-plugins.org/examples/> . +@prefix owl: <http://www.w3.org/2002/07/owl#> . +@prefix dc: <http://purl.org/dc/elements/1.1/> . +@prefix af: <http://purl.org/ontology/af/> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix cc: <http://web.resource.org/cc/> . +@prefix thisplug: <http://www.vamp-plugins.org/examples/percussiononsets#>. +@prefix : <> . + +<> a vamp:PluginDescription ; + foaf:maker <http://chrissutton.org/me> ; + foaf:primaryTopic vampex:percussiononsets . + +vampex:percussiononsets a vamp:Plugin ; + dc:title "Simple Percussion Onset Detector" ; + dc:description "Detect percussive note onsets by identifying broadband energy rises"; + foaf:maker <http://www.all-day-breakfast.com/cannam> ; #we'll pretend this is his URI + cc:license <http://creativecommons.org/licenses/BSD/> ; + vamp:identifier "percussiononsets" ; # The Vamp identifier for the plugin + vamp:vamp_API_version vamp:version_v1.1b ; # Made up - this plugin doesn't actually specify it + owl:versionInfo "2" ; + vamp:input_domain vamp:TimeDomain ; # Made up - this plugin doesn't actually specify it + + vamp:parameter_descriptor thisplug:pd1 ; + vamp:parameter_descriptor thisplug:pd2 ; + vamp:output_descriptor thisplug:od1 ; + vamp:output_descriptor thisplug:od2 . + + +thisplug:pd1 a vamp:ParameterDescriptor ; + vamp:identifier "threshold" ; + dc:title "Energy Rise threshold" ; + dc:description "Energy rise within a frequency bin necessary to count toward broadband total" ; + dc:format "dB" ; + vamp:minValue 0 ; #might be useful when interpreting plugin output + vamp:maxValue 20 ; + vamp:defaultValue 3 . + + +thisplug:pd2 a vamp:ParameterDescriptor ; + vamp:identifier "sensitivity" ; + dc:title "Sensitivity" ; + dc:description "Sensitivity of peak detector applied to broadband detection function" ; + dc:format "%" ; + vamp:minValue 0 ; #might be useful when interpreting plugin output + vamp:maxValue 100 ; + vamp:defaultValue 40 . + +thisplug:od1 a vamp:OutputDescriptor ; + vamp:identifier "onsets" ; + dc:title "Onsets" ; + dc:description "Percussive note onset locations" ; + dc:format "" ; + vamp:fixed_bin_count "true" ; + vamp:bin_count 0 ; + vamp:sample_type vamp:VariableSampleRate ; + vamp:computes_event_type af:Onset . # af:Onset is pending some thought + +thisplug:od2 a vamp:OutputDescriptor ; + vamp:identifier "detectionfunction" ; + dc:title "Detection Function" ; + dc:description "Broadband energy rise detection function"; + dc:format "" ; + vamp:fixed_bin_count "true" ; + vamp:bin_count 1 ; + vamp:sample_type vamp:OneSamplePerStep ; + vamp:computes_feature_type af:OnsetDetectionFunction .