Mercurial > hg > vamp-live-host
changeset 4:f0e9092bd3e4
...
author | cannam |
---|---|
date | Mon, 06 Nov 2006 14:41:46 +0000 |
parents | 86914ea77b7b |
children | 7fc28f7a935a |
files | host/Processor.cpp host/Processor.h host/Rule.h host/SimpleXMLRuleLoader.cpp test.xml |
diffstat | 5 files changed, 256 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/host/Processor.cpp Fri Nov 03 16:40:46 2006 +0000 +++ b/host/Processor.cpp Mon Nov 06 14:41:46 2006 +0000 @@ -4,6 +4,8 @@ #include "plugin/FeatureExtractionPluginFactory.h" +//#define DEBUG_RUN_PROCESSOR 1 + using std::cout; using std::cerr; using std::endl; @@ -118,8 +120,10 @@ // ++counter; -// cerr << "enough samples for max block " << maxBlock -// << " for step " << step << endl; +#ifdef DEBUG_RUN_PROCESSOR + cerr << "enough samples for max block " << maxBlock + << " for step " << step << endl; +#endif for (size_t c = 0; c < ch; ++c) { m_audioRecordTarget->peekSamples(c, maxBlock, buffers[c], reader); @@ -140,8 +144,10 @@ for (PluginSet::iterator k = j->second.begin(); k != j->second.end(); ++k) { -// cerr << "block inner loop for block " << block -// << " (toUse = " << toUse << ")" << endl; +#ifdef DEBUG_RUN_PROCESSOR + cerr << "block inner loop for block " << block + << " (toUse = " << toUse << ")" << endl; +#endif Vamp::Plugin *plugin = *k; Vamp::Plugin::FeatureSet fs; @@ -158,10 +164,14 @@ } haveTransformed = true; } -// cerr << "running " << plugin->getName() << " (transformed) frame = " << frame[reader] << endl; +#ifdef DEBUG_RUN_PROCESSOR + cerr << "running " << plugin->getName() << " (transformed) frame = " << frame[reader] << endl; +#endif fs = plugin->process(transformed, timestamp); } else { -// cerr << "running " << plugin->getName() << " frame = " << frame[reader] << endl; +#ifdef DEBUG_RUN_PROCESSOR + cerr << "running " << plugin->getName() << " frame = " << frame[reader] << endl; +#endif float *tmp[10]; for (size_t c = 0; c < ch; ++c) { tmp[c] = buffers[c] + off; @@ -171,9 +181,57 @@ for (Vamp::Plugin::FeatureSet::iterator fi = fs.begin(); fi != fs.end(); ++fi) { - printFeatures(int(plugin), frame[reader], sr, fi->first, fs); + + int output = fi->first; + + //!!! For each output, we need to step + //through the returned features one by one + //and update the plugin state for each, + //then run the rules each time a timestamp + //changes. But it has to do this with the + //features in the order of their + //timestamps, not in order of + //plugin/output enumeration. + // + // But we don't do that yet, we just use + // the first feature in the block (if any) + + Vamp::RealTime rt = + Vamp::RealTime::frame2RealTime(frame[reader], sr); + + Vamp::Plugin::FeatureList fl(fi->second); + + //!!! need rmap set up + int pluginIndex = m_pluginRMap[plugin]; + + OutputState currentState = + m_pluginStates[pluginIndex][output]; + + if (fl.empty()) { + bool changed = currentState.present; + Vamp::RealTime gap = rt - currentState.laststamp; + m_pluginStates[pluginIndex][output] = + OutputState(false, changed, currentState.value, rt, gap); + } else { + + if (fl[0].hasTimestamp) { + rt = fl[0].timestamp; + } + float value = 0.f; + if (!fl[0].values.empty()) { + value = fl[0].values[0]; + } + bool changed = (currentState.value != value); + Vamp::RealTime gap = rt - currentState.laststamp; + m_pluginStates[pluginIndex][output] = + OutputState(true, changed, value, rt, gap); + } + + printFeatures(int(plugin), frame[reader], sr, output, fs); } + processRules(); + doneWork = true; } @@ -259,6 +317,7 @@ int number = m_nextNumber++; m_plugins[number] = plugin; + m_pluginRMap[plugin] = number; m_processingMap[step][block].insert(plugin); m_havePlugins = true; @@ -315,10 +374,43 @@ } m_plugins.erase(number); + m_pluginRMap.erase(plugin); if (m_plugins.empty()) m_havePlugins = false; delete plugin; } +void +Processor::addImageRule(Rule rule, QString image) +{ + m_imageRules.insert(RuleImageMap::value_type(rule, image)); +} + +bool +Processor::processRules() +{ + for (RuleImageMap::iterator i = m_imageRules.begin(); + i != m_imageRules.end(); ++i) { + + Rule rule(i->first); + QString image(i->second); + + int pluginIndex = rule.getPluginIndex(); + int outputNumber = rule.getOutputNumber(); + Rule::Condition condition = rule.getCondition(); + float argument = rule.getArgument(); + + OutputState state = m_pluginStates[pluginIndex][outputNumber]; + + //!!! + if (condition == Rule::GreaterThan) { + if (state.value > argument) { + std::cerr << "FIRING RULE: " << state.value << " > " << argument << std::endl; + } + } + } + + return true; +} void printFeatures(int plugno, int frame, int sr, int output, Vamp::Plugin::FeatureSet &features)
--- a/host/Processor.h Fri Nov 03 16:40:46 2006 +0000 +++ b/host/Processor.h Mon Nov 06 14:41:46 2006 +0000 @@ -11,6 +11,8 @@ #include <vamp-sdk/Plugin.h> +#include "Rule.h" + #include <map> #include <set> @@ -23,9 +25,12 @@ int addPlugin(QString pluginId); // returns reference number, 0 for failure void removePlugin(int number); + void addImageRule(Rule rule, QString image); + protected: virtual void run(); bool runPlugins(); + bool processRules(); bool m_exiting; BufferingAudioCallbackRecordTarget *m_audioRecordTarget; @@ -35,6 +40,10 @@ PluginMap m_plugins; int m_nextNumber; + // Map back from plugin to index + typedef std::map<Vamp::Plugin *, int> PluginRMap; + PluginRMap m_pluginRMap; + // The same plugins, indexed by step and block sizes typedef std::set<Vamp::Plugin *> PluginSet; typedef std::map<size_t, PluginSet> BlockSizePluginMap; @@ -46,6 +55,27 @@ StepSizeReaderMap m_stepSizeReaderMap; int m_nextReader; + // Map from rule to image name + typedef std::multimap<Rule, QString> RuleImageMap; + RuleImageMap m_imageRules; + + class OutputState { + public: + OutputState() : + present(false), changed(false), value(0.f) { } + OutputState(bool p, bool c, float v, Vamp::RealTime s, Vamp::RealTime g) : + present(p), changed(c), value(v), laststamp(s), gap(g) { } + bool present; + bool changed; + float value; + Vamp::RealTime laststamp; + Vamp::RealTime gap; + }; + + // Map from plugin index to output index to state + typedef std::map<int, std::map<int, OutputState> > PluginStateMap; + PluginStateMap m_pluginStates; + bool m_havePlugins; size_t m_minBlockSize; size_t m_maxBlockSize;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/Rule.h Mon Nov 06 14:41:46 2006 +0000 @@ -0,0 +1,50 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +#ifndef _RULE_H_ +#define _RULE_H_ + +class Rule +{ +public: + enum Condition { + EqualTo, + GreaterThan, + LessThan, + NotEqualTo, + Present, + Changed, + GapGreaterThan, + GapLessThan + }; + + Rule(int pluginIndex, int outputNumber, + Condition condition, float argument = 0.f) : + m_pluginIndex(pluginIndex), + m_outputNumber(outputNumber), + m_condition(condition), + m_argument(argument) + { } + + int getPluginIndex() const { return m_pluginIndex; } + int getOutputNumber() const { return m_outputNumber; } + Condition getCondition() const { return m_condition; } + float getArgument() const { return m_argument; } + + bool operator<(const Rule &r) const { + if (m_pluginIndex < r.m_pluginIndex) return true; + else if (m_pluginIndex > r.m_pluginIndex) return false; + if (m_outputNumber < r.m_outputNumber) return true; + else if (m_outputNumber > r.m_outputNumber) return false; + if (int(m_condition) < int(r.m_condition)) return true; + else if (int(m_condition) > int(r.m_condition)) return true; + return m_argument < r.m_argument; + } + +protected: + int m_pluginIndex; + int m_outputNumber; + Condition m_condition; + float m_argument; +}; + +#endif
--- a/host/SimpleXMLRuleLoader.cpp Fri Nov 03 16:40:46 2006 +0000 +++ b/host/SimpleXMLRuleLoader.cpp Mon Nov 06 14:41:46 2006 +0000 @@ -1,6 +1,7 @@ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ #include "SimpleXMLRuleLoader.h" +#include "Rule.h" #include <QFile> #include <QIODevice> @@ -64,7 +65,17 @@ m_inPlugins = true; } } else if (name == "plugin") { + if (!m_inPlugins) { + std::cerr << "ERROR: SimpleXMLRuleLoader: Plugin outside plugins element" << std::endl; + return false; + } int extIndex = atts.value("index").toInt(); + if (m_externalInternalIndexMap.find(extIndex) != + m_externalInternalIndexMap.end()) { + std::cerr << "ERROR: SimpleXMLRuleLoader: Duplicate plugin index " + << extIndex << std::endl; + return false; + } QString id = atts.value("id"); int intIndex = m_processor->addPlugin(id); if (!intIndex) { @@ -81,7 +92,56 @@ } else { m_inRules = true; } - } + } else if (name == "outputrule") { + + if (!m_inRules) { + std::cerr << "ERROR: SimpleXMLRuleLoader: Rule outside rules element" << std::endl; + return false; + } + + int extIndex = atts.value("pluginIndex").toInt(); + + if (m_externalInternalIndexMap.find(extIndex) == + m_externalInternalIndexMap.end()) { + std::cerr << "ERROR: SimpleXMLRuleLoader: Unknown plugin index \"" + << extIndex << "\" in rule" << std::endl; + return false; + } + + int intIndex = m_externalInternalIndexMap[extIndex]; + + bool ok = false; + int outputNumber = atts.value("outputNumber").toInt(&ok); + if (!ok) outputNumber = 0; + + QString condStr = atts.value("condition").toLower(); + Rule::Condition condition(Rule::Present); + + if (condStr == "present") condition = Rule::Present; + else if (condStr == "equalto") condition = Rule::EqualTo; + else if (condStr == "greaterthan") condition = Rule::GreaterThan; + else if (condStr == "lessthan") condition = Rule::LessThan; + else if (condStr == "gapgreaterthan") condition = Rule::GapGreaterThan; + else if (condStr == "gaplessthan") condition = Rule::GapLessThan; + else if (condStr == "notequalto") condition = Rule::NotEqualTo; + else if (condStr == "changed") condition = Rule::Changed; + + float arg = atts.value("argument").toFloat(&ok); + if (!ok) arg = 0.f; + + Rule rule(intIndex, outputNumber, condition, arg); + + QString action = atts.value("action").toLower(); + + if (action == "image") { + QString image = atts.value("image").toLower(); + m_processor->addImageRule(rule, image); + std::cerr << "INFO: SimpleXMLRuleLoader: Added image rule" << std::endl; + } else { + std::cerr << "WARNING: SimpleXMLRuleLoader: Unknown action \"" + << action.toStdString() << "\"" << std::endl; + } + } return true; } @@ -99,8 +159,20 @@ { QString name = qName.toLower(); - if (name == "plugins") m_inPlugins = false; - else if (name == "rules") m_inRules = false; + if (name == "plugins") { + + if (!m_inPlugins) { + std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of plugins element (trying to continue)" << std::endl; + } + m_inPlugins = false; + + } else if (name == "rules") { + + if (!m_inRules) { + std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of rules element (trying to continue)" << std::endl; + } + m_inRules = false; + } return true; }
--- a/test.xml Fri Nov 03 16:40:46 2006 +0000 +++ b/test.xml Mon Nov 06 14:41:46 2006 +0000 @@ -1,11 +1,9 @@ <vlh> <plugins> <plugin index="1" id="vamp:vamp-aubio:aubiotempo"/> + <plugin index="2" id="vamp:vamp-example-plugins:zerocrossing"/> </plugins> <rules> - <rule> - <compareOutput pluginIndex="1" greaterThan="2"/> - <show image="blah"/> - </rule> + <outputRule pluginIndex="2" condition="GreaterThan" argument="120" action="image" image="blah"/> </rules> </vlh>