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>