changeset 7:b30fcffc5000

* Better organisation of action classes; support for AND-type rules
author cannam
date Mon, 27 Nov 2006 11:03:52 +0000
parents b046af03c719
children c1669af82d6e
files host/Action.h host/ImageAction.cpp host/ImageAction.h host/ImageWindow.cpp host/ImageWindow.h host/Processor.cpp host/Processor.h host/Rule.cpp host/Rule.h host/SimpleXMLRuleLoader.cpp host/SimpleXMLRuleLoader.h host/host.cpp test.xml vamp-live-host.pro
diffstat 14 files changed, 298 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host/Action.h	Mon Nov 27 11:03:52 2006 +0000
@@ -0,0 +1,21 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#ifndef _ACTION_H_
+#define _ACTION_H_
+
+#include <QObject>
+#include <QString>
+
+class Action : public QObject
+{
+public:
+    virtual ~Action() { }
+
+    virtual QString getName() const = 0;
+    virtual void fire() = 0;
+
+protected:
+    Action() { } 
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host/ImageAction.cpp	Mon Nov 27 11:03:52 2006 +0000
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#include "ImageAction.h"
+#include "ImageWindow.h"
+
+#include <iostream>
+
+ImageAction::ImageAction(QString imageName) :
+    m_imageName(imageName)
+{
+    connect(this, SIGNAL(showImage(QString)),
+            ImageWindow::getInstance(), SLOT(showImage(QString)));
+}
+
+ImageAction::~ImageAction()
+{
+}
+
+QString
+ImageAction::getName() const
+{
+    return QString("image: %1").arg(m_imageName);
+}
+
+void
+ImageAction::fire()
+{
+    std::cerr << "ImageAction(\"" << getName().toStdString() << "\"::fire"
+              << std::endl;
+    emit showImage(m_imageName);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host/ImageAction.h	Mon Nov 27 11:03:52 2006 +0000
@@ -0,0 +1,26 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#ifndef _IMAGE_ACTION_H_
+#define _IMAGE_ACTION_H_
+
+#include "Action.h"
+
+class ImageAction : public Action    
+{
+    Q_OBJECT
+
+public:
+    ImageAction(QString imageName);
+    virtual ~ImageAction();
+
+    virtual QString getName() const;
+    virtual void fire();
+
+signals:
+    void showImage(QString image);
+
+protected:
+    QString m_imageName;
+};
+
+#endif
--- a/host/ImageWindow.cpp	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/ImageWindow.cpp	Mon Nov 27 11:03:52 2006 +0000
@@ -8,6 +8,8 @@
 
 #include <iostream>
 
+ImageWindow *ImageWindow::m_instance = 0;
+
 ImageWindow::ImageWindow(QWidget *parent) :
     QDialog(parent),
     m_pixmap(0)
@@ -23,6 +25,15 @@
     delete m_pixmap;
 }
 
+ImageWindow *
+ImageWindow::getInstance()
+{
+    if (m_instance) return m_instance;
+    m_instance = new ImageWindow();
+    m_instance->show();
+    return m_instance;
+}
+
 void
 ImageWindow::showImage(QString image)
 {
--- a/host/ImageWindow.h	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/ImageWindow.h	Mon Nov 27 11:03:52 2006 +0000
@@ -14,16 +14,21 @@
     Q_OBJECT
 
 public:
-    ImageWindow(QWidget *parent = 0);
     virtual ~ImageWindow();
 
+    static ImageWindow *getInstance();
+
 public slots:
     void showImage(QString image);
 
 protected:
+    ImageWindow(QWidget *parent = 0);
+
     QString m_imageName;
     QLabel *m_label;
     QPixmap *m_pixmap;
+
+    static ImageWindow *m_instance;
 };
 
 #endif
--- a/host/Processor.cpp	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/Processor.cpp	Mon Nov 27 11:03:52 2006 +0000
@@ -31,6 +31,9 @@
 {
     m_exiting = true;
     wait();
+    while (!m_rules.empty()) {
+        delete *m_rules.begin();
+    }
 }
 
 void
@@ -420,73 +423,84 @@
 }
 
 void
-Processor::addImageRule(Rule rule, QString image)
+Processor::addRule(Rule *rule)
 {
-    m_imageRules.insert(RuleImageMap::value_type(rule, image));
+    m_rules.insert(rule);
 }
 
 bool
 Processor::processRules()
 {
-    for (RuleImageMap::iterator i = m_imageRules.begin();
-         i != m_imageRules.end(); ++i) {
+    for (RuleSet::iterator i = m_rules.begin(); i != m_rules.end(); ++i) {
 
-        Rule rule(i->first);
-        QString image(i->second);
+        Rule *rule(*i);
 
-        int pluginIndex = rule.getPluginIndex();
-        int outputNumber = rule.getOutputNumber();
-        Rule::Condition condition = rule.getCondition();
-        float argument = rule.getArgument();
+        bool passed = false;
 
-        OutputState state = m_pluginStates[pluginIndex][outputNumber];
+        for (Rule::ConditionList::const_iterator j = rule->getConditions().begin();
+             j != rule->getConditions().end(); ++j) {
+
+            Condition condition(*j);
+
+            int pluginIndex = condition.getPluginIndex();
+            int outputNumber = condition.getOutputNumber();
+            Condition::Type type = condition.getType();
+            float argument = condition.getArgument();
+
+            OutputState state = m_pluginStates[pluginIndex][outputNumber];
         
 #ifdef DEBUG_RUN_PROCESSOR
-        std::cerr << "Present = " << state.present << ", changed = " << state.changed << ", value = " << state.value << std::endl;
+            std::cerr << "Present = " << state.present << ", changed = " << state.changed << ", value = " << state.value << std::endl;
 #endif
 
-        if (!state.changed) continue;
+            passed = false;
 
-        bool fire = false;
+            if (!state.changed) break; //!!!???
 
-        switch (condition) {
+            switch (type) {
 
-        case Rule::GreaterThan:
-            fire = (state.value > argument);
-            break;
+            case Condition::GreaterThan:
+                passed = (state.value > argument);
+                break;
+                
+            case Condition::LessThan:
+                passed = (state.value < argument);
+                break;
+                
+            case Condition::EqualTo:
+                passed = fabsf(state.value - argument) < 0.000001;
+                break;
+                
+            case Condition::NotEqualTo:
+                passed = fabsf(state.value - argument) > 0.000001;
+                break;
+                
+            case Condition::Present:
+                passed = state.present;
+                break;
+                
+            case Condition::Changed:
+                passed = true;
+                break;
+                
+            case Condition::GapGreaterThan:
+                passed = (state.gap > Vamp::RealTime::fromSeconds(argument));
+                break;
+                
+            case Condition::GapLessThan:
+                passed = (state.gap < Vamp::RealTime::fromSeconds(argument));
+                break;
+            }
 
-        case Rule::LessThan:
-            fire = (state.value < argument);
-            break;
-
-        case Rule::EqualTo:
-            fire = fabsf(state.value - argument) < 0.000001;
-            break;
-
-        case Rule::NotEqualTo:
-            fire = fabsf(state.value - argument) > 0.000001;
-            break;
-
-        case Rule::Present:
-            fire = state.present;
-            break;
-
-        case Rule::Changed:
-            fire = true;
-            break;
-
-        case Rule::GapGreaterThan:
-            fire = (state.gap > Vamp::RealTime::fromSeconds(argument));
-            break;
-
-        case Rule::GapLessThan:
-            fire = (state.gap < Vamp::RealTime::fromSeconds(argument));
-            break;
+            if (!passed) break;
         }
 
-        if (fire) {
-            std::cerr << "FIRING RULE: " << image.toStdString() << "!" << std::endl;
-            emit showImage(image);
+        if (passed) {
+            Action *action = rule->getAction();
+            if (action) {
+                std::cerr << "FIRING RULE: " << action->getName().toStdString() << "!" << std::endl;
+                action->fire();
+            }
         }
     }
 
--- a/host/Processor.h	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/Processor.h	Mon Nov 27 11:03:52 2006 +0000
@@ -27,10 +27,7 @@
     int addPlugin(QString pluginId); // returns reference number, 0 for failure
     void removePlugin(int number);
 
-    void addImageRule(Rule rule, QString image);
-
-signals:
-    void showImage(QString image);
+    void addRule(Rule *rule); // I take ownership of rule
 
 protected:
     virtual void run();
@@ -61,9 +58,8 @@
     StepSizeReaderMap m_stepSizeReaderMap;
     ReaderSet m_unusedReaders;
 
-    // Map from rule to image name
-    typedef std::multimap<Rule, QString> RuleImageMap;
-    RuleImageMap m_imageRules;
+    typedef std::multiset<Rule *> RuleSet;
+    RuleSet m_rules;
 
     class OutputState {
     public:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host/Rule.cpp	Mon Nov 27 11:03:52 2006 +0000
@@ -0,0 +1,22 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#include "Rule.h"
+
+Rule::~Rule()
+{
+    delete m_action;
+}
+
+void
+Rule::addCondition(Condition condition)
+{
+    m_conditions.push_back(condition);
+}
+
+void
+Rule::setAction(Action *action)
+{
+    delete m_action;
+    m_action = action;
+}
+
--- a/host/Rule.h	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/Rule.h	Mon Nov 27 11:03:52 2006 +0000
@@ -3,10 +3,14 @@
 #ifndef _RULE_H_
 #define _RULE_H_
 
-class Rule
+#include <vector>
+
+#include "Action.h"
+
+class Condition
 {
 public:
-    enum Condition {
+    enum Type {
         EqualTo,
         GreaterThan,
         LessThan,
@@ -17,34 +21,55 @@
         GapLessThan
     };
 
-    Rule(int pluginIndex, int outputNumber,
-         Condition condition, float argument = 0.f) :
+    Condition(int pluginIndex, int outputNumber,
+              Type type, float argument = 0.f) :
         m_pluginIndex(pluginIndex),
         m_outputNumber(outputNumber),
-        m_condition(condition),
+        m_type(type),
         m_argument(argument)
     { }
 
     int getPluginIndex() const { return m_pluginIndex; }
     int getOutputNumber() const { return m_outputNumber; }
-    Condition getCondition() const { return m_condition; }
+    Type getType() const { return m_type; }
     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;
+/*
+    bool operator<(const Condition &c) const {
+        if (m_pluginIndex < c.m_pluginIndex) return true;
+        else if (m_pluginIndex > c.m_pluginIndex) return false;
+        if (m_outputNumber < c.m_outputNumber) return true;
+        else if (m_outputNumber > c.m_outputNumber) return false;
+        if (int(m_type) < int(c.m_type)) return true;
+        else if (int(m_type) > int(c.m_type)) return true;
+        return m_argument < c.m_argument;
     }
+*/
 
 protected:
     int m_pluginIndex;
     int m_outputNumber;
-    Condition m_condition;
+    Type m_type;
     float m_argument;
 };
 
+class Rule
+{
+public:
+    Rule() : m_action(0) { }
+    virtual ~Rule();
+
+    void addCondition(Condition condition);
+    void setAction(Action *action); // I take ownership of action
+
+    typedef std::vector<Condition> ConditionList;
+    const ConditionList &getConditions() const { return m_conditions; }
+
+    Action *getAction() { return m_action; }
+
+protected:
+    std::vector<Condition> m_conditions;
+    Action *m_action;
+};
+
 #endif
--- a/host/SimpleXMLRuleLoader.cpp	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/SimpleXMLRuleLoader.cpp	Mon Nov 27 11:03:52 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "SimpleXMLRuleLoader.h"
 #include "Rule.h"
+#include "ImageAction.h"
 
 #include <QFile>
 #include <QIODevice>
@@ -10,7 +11,9 @@
 SimpleXMLRuleLoader::SimpleXMLRuleLoader() :
     m_processor(0),
     m_inPlugins(false),
-    m_inRules(false)
+    m_inRules(false),
+    m_inRule(false),
+    m_rule(0)
 {
 }
 
@@ -98,7 +101,21 @@
             std::cerr << "ERROR: SimpleXMLRuleLoader: Rule outside rules element" << std::endl;
             return false;
         }
+        if (m_inRule) {
+            std::cerr << "ERROR: SimpleXMLRuleLoader: Nested output rules" << std::endl;
+            return false;
+        }
 
+        m_inRule = true;
+        m_rule = new Rule();
+
+    } else if (name == "condition") {
+
+        if (!m_inRule) {
+            std::cerr << "ERROR: SimpleXMLRuleLoader: Condition outside rule" << std::endl;
+            return false;
+        }
+        
         int extIndex = atts.value("pluginIndex").toInt();
 
         if (m_externalInternalIndexMap.find(extIndex) ==
@@ -115,31 +132,41 @@
         if (!ok) outputNumber = 0;
 
         QString condStr = atts.value("condition").toLower();
-        Rule::Condition condition(Rule::Present);
+        Condition::Type type(Condition::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;
+        if (condStr == "present") type = Condition::Present;
+        else if (condStr == "equalto") type = Condition::EqualTo;
+        else if (condStr == "greaterthan") type = Condition::GreaterThan;
+        else if (condStr == "lessthan") type = Condition::LessThan;
+        else if (condStr == "gapgreaterthan") type = Condition::GapGreaterThan;
+        else if (condStr == "gaplessthan") type = Condition::GapLessThan;
+        else if (condStr == "notequalto") type = Condition::NotEqualTo;
+        else if (condStr == "changed") type = Condition::Changed;
 
         float arg = atts.value("argument").toFloat(&ok);
         if (!ok) arg = 0.f;
 
-        Rule rule(intIndex, outputNumber, condition, arg);
+        Condition condition(intIndex, outputNumber, type, arg);
 
-        QString action = atts.value("action").toLower();
+        m_rule->addCondition(condition);
 
-        if (action == "image") {
+    } else if (name == "action") {
+
+        if (!m_inRule) {
+            std::cerr << "ERROR: SimpleXMLRuleLoader: Action outside rule" << std::endl;
+            return false;
+        }
+
+        QString type = atts.value("type").toLower();
+
+        if (type == "image") {
             QString image = atts.value("image").toLower();
-            m_processor->addImageRule(rule, image);
-            std::cerr << "INFO: SimpleXMLRuleLoader: Added image rule" << std::endl;
+            Action *action = new ImageAction(image);
+            m_rule->setAction(action);
+            std::cerr << "INFO: SimpleXMLRuleLoader: Added image action" << std::endl;
         } else {
-            std::cerr << "WARNING: SimpleXMLRuleLoader: Unknown action \""
-                      << action.toStdString() << "\"" << std::endl;
+            std::cerr << "WARNING: SimpleXMLRuleLoader: Unknown action type \""
+                      << type.toStdString() << "\"" << std::endl;
         }
     }
 
@@ -172,7 +199,18 @@
             std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of rules element (trying to continue)" << std::endl;
         }
         m_inRules = false;
+
+    } else if (name == "outputrule") {
+        
+        if (!m_inRule) {
+            std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of outputRule element" << std::endl;
+            return false;
+        } else {
+            m_processor->addRule(m_rule);
+        }
+        m_inRule = false;
     }
+
     return true;
 }
 
--- a/host/SimpleXMLRuleLoader.h	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/SimpleXMLRuleLoader.h	Mon Nov 27 11:03:52 2006 +0000
@@ -42,10 +42,11 @@
 
     bool m_inPlugins;
     bool m_inRules;
+    bool m_inRule;
+
+    Rule *m_rule;
 
     std::map<int, int> m_externalInternalIndexMap;
-
-//    Rule m_currentRule;
 };
 
 #endif
--- a/host/host.cpp	Fri Nov 10 17:46:44 2006 +0000
+++ b/host/host.cpp	Mon Nov 27 11:03:52 2006 +0000
@@ -52,14 +52,14 @@
         return 1;
     }
 
-    ImageWindow window;
-    window.show();
+//    ImageWindow window;
+//    window.show();
 
     Processor processor(target);
-
+/*
     QObject::connect(&processor, SIGNAL(showImage(QString)),
                      &window, SLOT(showImage(QString)));
-
+*/
     SimpleXMLRuleLoader loader;
     if (!loader.loadFile(processor, "test.xml")) {
         std::cerr << "ERROR: Failed to load test XML file" << std::endl;
--- a/test.xml	Fri Nov 10 17:46:44 2006 +0000
+++ b/test.xml	Mon Nov 27 11:03:52 2006 +0000
@@ -4,8 +4,14 @@
 <!--  <plugin index="2" id="vamp:vamp-example-plugins:zerocrossing"/> -->
 </plugins>
 <rules>
-<outputRule pluginIndex="1" condition="GapLessThan" argument="0.49" action="image" image="trees-green.jpg"/>
-<outputRule pluginIndex="1" condition="GapGreaterThan" argument="0.51" action="image" image="trees-mono.jpg"/>
+<outputRule>
+  <condition pluginIndex="1" condition="GapLessThan" argument="0.49"/>
+  <action type="image" image="trees-green.jpg"/>
+</outputRule>
+<outputRule>
+  <condition pluginIndex="1" condition="GapGreaterThan" argument="0.51"/>
+  <action type="image" image="trees-mono.jpg"/>
+</outputRule>
 <!-- <outputRule pluginIndex="1" outputNumber="0" condition="Present" action="image" image="ping"/> -->
 </rules>
 </vlh>
--- a/vamp-live-host.pro	Fri Nov 10 17:46:44 2006 +0000
+++ b/vamp-live-host.pro	Mon Nov 27 11:03:52 2006 +0000
@@ -23,8 +23,11 @@
            audioio/AudioPortAudioSource.h \
            audioio/AudioRecordSourceFactory.h \
            audioio/BufferingAudioCallbackRecordTarget.h \
+           host/Action.h \
+           host/ImageAction.h \
            host/ImageWindow.h \
            host/Processor.h \
+           host/Rule.h \
            host/SimpleXMLRuleLoader.h
 SOURCES += audioio/AudioCallbackRecordSource.cpp \
            audioio/AudioJACKSource.cpp \
@@ -32,6 +35,8 @@
            audioio/AudioRecordSourceFactory.cpp \
            audioio/BufferingAudioCallbackRecordTarget.cpp \
            host/host.cpp \
+           host/ImageAction.cpp \
            host/ImageWindow.cpp \
            host/Processor.cpp \
+           host/Rule.cpp \
            host/SimpleXMLRuleLoader.cpp