diff --git a/dependencies/Maximilian b/dependencies/Maximilian
index fec9e22f85cb2e9a60d007319fbc06190ed71e55..3a5431836b7c8ad98459f3d6ff50e5bac1d2c297 160000
--- a/dependencies/Maximilian
+++ b/dependencies/Maximilian
@@ -1 +1 @@
-Subproject commit fec9e22f85cb2e9a60d007319fbc06190ed71e55
+Subproject commit 3a5431836b7c8ad98459f3d6ff50e5bac1d2c297
diff --git a/dependencies/RapidLib b/dependencies/RapidLib
index 5f5d57978fa5d9511e90a91a268270a1803484b2..839880dd3b3e3ea3caa3f800f513f7fc2a8cf679 160000
--- a/dependencies/RapidLib
+++ b/dependencies/RapidLib
@@ -1 +1 @@
-Subproject commit 5f5d57978fa5d9511e90a91a268270a1803484b2
+Subproject commit 839880dd3b3e3ea3caa3f800f513f7fc2a8cf679
diff --git a/tools/RapidVisualizerOSC/bin/RapidVisualizerOSC.app.zip b/tools/RapidVisualizerOSC/bin/RapidVisualizerOSC.app.zip
new file mode 100644
index 0000000000000000000000000000000000000000..e45213e87795cafd42f902ae4783fc2d7fc8d48e
Binary files /dev/null and b/tools/RapidVisualizerOSC/bin/RapidVisualizerOSC.app.zip differ
diff --git a/tools/RapidVisualizerOSC/src/BarChart.cpp b/tools/RapidVisualizerOSC/src/BarChart.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3efb58d57be28241bd5f63bbb0e6c7b528cc1e53
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/BarChart.cpp
@@ -0,0 +1,19 @@
+//
+//  BarChart.cpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#include "BarChart.hpp"
+
+BarChart::BarChart ( GraphState* state ) : RealTimeGraph (state)
+{
+    //
+}
+
+BarChart::~BarChart ( void )
+{
+    
+}
diff --git a/tools/RapidVisualizerOSC/src/BarChart.hpp b/tools/RapidVisualizerOSC/src/BarChart.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..379b2df0a7c287c582dc0f1175c0b794dc3c1d77
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/BarChart.hpp
@@ -0,0 +1,72 @@
+//
+//  BarChart.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#ifndef BarChart_hpp
+#define BarChart_hpp
+
+#include <stdio.h>
+#include "RealTimeGraph.hpp"
+
+class BarChart : public RealTimeGraph
+{
+public:
+    BarChart ( GraphState* state ) : RealTimeGraph (state)
+    {
+        //
+    }
+    ~BarChart ( void )
+    {
+        //
+    }
+    void updateRep ( void )
+    {
+        //
+    }
+    void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelRect )
+    {
+        double
+        minIn = 0,
+        minOut = 0,
+        maxOut = -subLabelRect.height,
+        startPosY = subLabelRect.height,
+        barSize = subLabelRect.width/data.labelData.size(),
+        separation = barSize/16,
+        halfSeparation = separation/2;
+        bool drawZeroSep = false;
+        
+        if (data.minValue < 0)
+        { // Add negative part
+            startPosY = subLabelRect.height/2;
+            minIn = -data.maxValue;
+            minOut = subLabelRect.height/2;
+            maxOut /= 2;
+            drawZeroSep = true;
+        }
+        for (uint32_t i = 0; i < data.labelData.size(); ++i)
+        {
+            double output = mapVals(data.labelData[i], minIn, data.maxValue, minOut, maxOut );
+            ofSetColor (graphColor);
+            ofFill();
+            ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output );
+            
+        }
+        if (drawZeroSep)
+        {
+            ofSetLineWidth(1.25);
+            ofSetColor (175,150,150);
+            ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY,
+                       subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY);
+        }
+    }
+    void update ( void )
+    {
+        //
+    }
+};
+
+#endif /* BarChart_hpp */
diff --git a/tools/RapidVisualizerOSC/src/Graph.hpp b/tools/RapidVisualizerOSC/src/Graph.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..546785f60e37aef49c1da60706e6bb9150946121
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/Graph.hpp
@@ -0,0 +1,122 @@
+//
+//  Graph.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#ifndef Graph_h
+#define Graph_h
+
+#include <string>
+#include <vector>
+#include <list>
+#include "ofMain.h"
+#include "ofxGui.h"
+
+// TODO: add namespace, move funcs and struct to other header(s)
+enum class TextAlignment {
+    LEFT,
+    CENTER,
+    RIGHT
+};
+
+static inline void drawTextLabel ( std::string label, ofVec2f position, ofColor labelBackgroundColor, ofColor stringColor, TextAlignment alignment, bool drawAbove )
+{
+    uint32_t strLenPix = label.length()*8;
+    
+    switch (alignment) {
+        case TextAlignment::LEFT:
+            // No exception
+            break;
+        case TextAlignment::CENTER:
+            position.x -= strLenPix / 2;
+            break;
+        case TextAlignment::RIGHT:
+            position.x -= strLenPix;
+            break;
+        default:
+            break;
+    }
+    
+    ofSetColor (labelBackgroundColor);
+    ofRectangle bmpStringRect(position.x - 2,
+                              position.y + ((drawAbove) ? -4 : 12) + 2,
+                              strLenPix + 4, -12);
+    ofDrawRectangle(bmpStringRect);
+    
+    ofSetColor (stringColor);
+    ofDrawBitmapString(label, position.x, position.y + ((drawAbove) ? -4 : 12));
+}
+
+static inline double mapVals ( double x, double in_min, double in_max, double out_min, double out_max )
+{
+    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+template <typename T>
+struct DataContainer {
+    T labelData;
+    double minValue = 0.0;
+    double maxValue = 1.0;
+    uint32_t iteratorPos = 0;
+    //ofColor graphColor;
+    
+    void updateMinMax ( void )
+    {
+        auto mm = std::minmax_element(labelData.begin(), labelData.end());
+        double min = labelData[std::distance(labelData.begin(), mm.first)];
+        double max = labelData[std::distance(labelData.begin(), mm.second)];
+        
+        if (min < minValue)
+            minValue = min;
+        if (max > maxValue)
+            maxValue = max;
+        if (fabs(min) > maxValue)
+            maxValue = fabs(min);
+    
+    }
+};
+
+class Graph {
+public:
+    enum graphLayout {
+        GRAPHS_STACKED,
+        GRAPHS_VERTICAL
+    };
+    struct GraphState {
+        std::string label;
+        graphLayout layout = graphLayout::GRAPHS_STACKED;
+        bool hasHistory = false;
+        ofRectangle positionAndSize;
+        uint32_t historySize;
+    };
+    
+    Graph ( GraphState* state )
+    : state(state)
+    {
+        graphColor = ofColor(24, 219, 92);
+        textColor = ofColor(255, 157, 117);
+    }
+    
+    virtual ~Graph ( void )
+    {
+        
+    }
+    
+    virtual void updateRep ( void ) = 0; // update representation
+    virtual void addData ( std::string subLabel, std::vector<double>& data ) = 0;
+    virtual void reset ( void ) = 0;
+    
+    virtual void update ( void ) = 0;
+    virtual void draw ( void ) = 0;
+
+    virtual uint32_t getNumSubGraphs ( void ) const = 0;
+protected:
+    GraphState *state = nullptr;
+    ofColor graphColor;
+    ofColor textColor;
+};
+
+#endif /* Graph_h */
diff --git a/tools/RapidVisualizerOSC/src/HistoryGraph.hpp b/tools/RapidVisualizerOSC/src/HistoryGraph.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3468cacb57491f984b57344430fe97220a542ad0
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/HistoryGraph.hpp
@@ -0,0 +1,125 @@
+//
+//  HistoryGraph.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#ifndef HistoryGraph_h
+#define HistoryGraph_h
+
+#include "Graph.hpp"
+#include <list>
+
+class HistoryGraph : public Graph
+{
+public:
+    HistoryGraph ( GraphState* state )
+    : Graph(state)
+    {
+        
+    }
+    ~HistoryGraph ( void )
+    {
+    }
+    
+    virtual void updateRep ( void ) = 0; // update representation
+    virtual void drawSubGraph ( std::string subLabel, DataContainer<std::list<double>>& data, ofRectangle subLabelrect ) = 0;
+    virtual void update ( void ) = 0;
+    
+    void addData ( std::string subLabel, std::vector<double>& data )
+    {
+        if (data.size() < state->historySize)
+        {
+            //FIXME: can be sped up by using the result of this search instead of accessing by[] again
+            if ( subLabelData.find(subLabel) == subLabelData.end() ) {
+                // not found
+                DataContainer<std::list<double>> container;
+                container.labelData.resize(state->historySize);
+                std::fill(container.labelData.begin(), container.labelData.end(), 0.0);
+                subLabelData[subLabel] = container;
+                
+            }
+            DataContainer<std::list<double>>&  dataRef = subLabelData[subLabel];
+            list<double>& referencedList = dataRef.labelData;
+            while (referencedList.size() + data.size() >= state->historySize)
+            {
+                referencedList.pop_front();
+            }
+            for (int32_t i = data.size()-1; i >= 0; --i)
+            {
+                double val = data[i];
+                if (val < dataRef.minValue)
+                    dataRef.minValue = val;
+                if (val > dataRef.maxValue)
+                    dataRef.maxValue = val;
+                if (fabs(val) > dataRef.maxValue)
+                    dataRef.maxValue = fabs(val);
+                referencedList.push_back(val);
+            }
+        }
+    }
+    
+    void reset ( void )
+    {
+        subLabelData.clear();
+    }
+    
+    void draw ( void )
+    {
+        uint32_t numElements = subLabelData.size();
+        uint16_t heightBetweenSubLabels = state->positionAndSize.height/numElements;
+        uint16_t subLabelY = 0;
+        
+        ofSetColor (graphColor);
+        ofDrawLine(state->positionAndSize.x, state->positionAndSize.y,
+                   state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y);
+        
+        std::map<std::string, DataContainer<std::list<double>>>::iterator it;
+        for(it = subLabelData.begin(); it != subLabelData.end(); ++it)
+        {
+            std::string subLabel = it->first;
+            DataContainer<std::list<double>>& data = it->second;
+            
+            drawSubGraph (subLabel, data, ofRectangle(state->positionAndSize.x,
+                                                      state->positionAndSize.y + subLabelY,
+                                                      state->positionAndSize.width,
+                                                      heightBetweenSubLabels));
+            // Draw label and background
+            drawTextLabel(subLabel, ofVec2f(state->positionAndSize.x + state->positionAndSize.width,
+                                            state->positionAndSize.y + subLabelY),
+                          ofColor(100, 100, 100), ofColor(textColor), TextAlignment::RIGHT, false);
+            
+            
+            // Draw max value
+            drawTextLabel(ofToString(data.maxValue),
+                          ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2,
+                                  state->positionAndSize.y + subLabelY),
+                          ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, false);
+            
+            // Increment Y position
+            subLabelY += heightBetweenSubLabels;
+            
+            // Draw min value
+            // Show actual min value?
+            drawTextLabel(ofToString((data.minValue < 0) ? -data.maxValue : 0),
+                          ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2,
+                                  state->positionAndSize.y + subLabelY),
+                          ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, true);
+            
+            // Draw Line at bottom of graph
+            ofSetLineWidth(2.0);
+            ofSetColor (180,180,180);
+            ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + subLabelY,
+                       state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + subLabelY);
+        }
+    }
+    uint32_t getNumSubGraphs ( void ) const
+    {
+        return subLabelData.size();
+    }
+protected:
+    std::map <std::string, DataContainer<std::list<double>>> subLabelData;
+};
+#endif /* HistoryGraph_h */
diff --git a/tools/RapidVisualizerOSC/src/LineGraph.hpp b/tools/RapidVisualizerOSC/src/LineGraph.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..88669d91cbbb4f167f58b30f77c7a3db9b5b2713
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/LineGraph.hpp
@@ -0,0 +1,85 @@
+//
+//  LineGraph.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#ifndef LineGraph_h
+#define LineGraph_h
+
+#include <stdio.h>
+#include "RealTimeGraph.hpp"
+
+class LineGraph : public RealTimeGraph
+{
+public:
+    LineGraph ( GraphState* state ) : RealTimeGraph (state)
+    {
+        //
+    }
+    ~LineGraph ( void )
+    {
+        //
+    }
+    void updateRep ( void )
+    {
+        //
+    }
+    void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelRect )
+    {
+        double
+        minIn = 0,
+        minOut = 0,
+        maxOut = -subLabelRect.height,
+        startPosY = subLabelRect.height,
+        pointDistance = subLabelRect.width/data.labelData.size(),
+        separation = pointDistance/2;
+        //halfSeparation = separation/2;
+        bool drawZeroSep = false;
+        
+        if (data.minValue < 0)
+        { // Add negative part
+            startPosY = subLabelRect.height/2;
+            minIn = -data.maxValue;
+            minOut = subLabelRect.height/2;
+            maxOut /= 2;
+            drawZeroSep = true;
+        }
+        
+        ofBeginShape();
+        ofFill();
+        ofVertex(subLabelRect.x, subLabelRect.y + startPosY);
+        double output = mapVals(data.labelData[0], minIn, data.maxValue, minOut, maxOut );
+        ofVertex(subLabelRect.x, subLabelRect.y + startPosY + output);
+        for (uint32_t i = 0; i < data.labelData.size(); ++i)
+        {
+            output = mapVals(data.labelData[i], minIn, data.maxValue, minOut, maxOut );
+            ofSetColor (graphColor);
+            
+            ofVertex(subLabelRect.x + pointDistance * i + separation, subLabelRect.y + startPosY + output);
+            //ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output );
+            
+        }
+        output = mapVals(data.labelData[data.labelData.size()-1], minIn, data.maxValue, minOut, maxOut );
+        ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY + output);
+        ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY);
+        ofEndShape();
+        
+        if (drawZeroSep)
+        {
+            ofSetLineWidth(1.25);
+            ofSetColor (175,150,150);
+            ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY,
+                       subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY);
+        }
+    }
+    void update ( void )
+    {
+        //
+    }
+};
+
+
+#endif /* LineGraph_h */
diff --git a/tools/RapidVisualizerOSC/src/LineGraphHistory.hpp b/tools/RapidVisualizerOSC/src/LineGraphHistory.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e3b32f887a93192d341efff9fced03f316649e0f
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/LineGraphHistory.hpp
@@ -0,0 +1,87 @@
+//
+//  LineGraphHistory.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 10/11/2017.
+//
+//
+
+#ifndef LineGraphHistory_h
+#define LineGraphHistory_h
+
+#include <stdio.h>
+#include "HistoryGraph.hpp"
+
+class LineGraphHistory : public HistoryGraph
+{
+public:
+    LineGraphHistory ( GraphState* state ) : HistoryGraph (state)
+    {
+        //
+    }
+    ~LineGraphHistory ( void )
+    {
+        //
+    }
+    void updateRep ( void )
+    {
+        //
+    }
+    void drawSubGraph ( std::string subLabel, DataContainer<std::list<double>>& data, ofRectangle subLabelRect )
+    {
+        double
+        minIn = 0,
+        minOut = 0,
+        maxOut = -subLabelRect.height,
+        startPosY = subLabelRect.height,
+        pointDistance = subLabelRect.width/data.labelData.size(),
+        separation = pointDistance/2;
+        //halfSeparation = separation/2;
+        bool drawZeroSep = false;
+        
+        if (data.minValue < 0)
+        { // Add negative part
+            startPosY = subLabelRect.height/2;
+            minIn = -data.maxValue;
+            minOut = subLabelRect.height/2;
+            maxOut /= 2;
+            drawZeroSep = true;
+        }
+        
+        ofBeginShape();
+        ofFill();
+        ofVertex(subLabelRect.x, subLabelRect.y + startPosY);
+        double output = mapVals(data.labelData.front(), minIn, data.maxValue, minOut, maxOut );
+        ofVertex(subLabelRect.x, subLabelRect.y + startPosY + output);
+        uint32_t i = 0;
+        for (double d : data.labelData)
+        {
+            output = mapVals(d, minIn, data.maxValue, minOut, maxOut );
+            ofSetColor (graphColor);
+            
+            ofVertex(subLabelRect.x + pointDistance * i + separation, subLabelRect.y + startPosY + output);
+            //ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output );
+            ++i;
+            
+        }
+        output = mapVals(data.labelData.back(), minIn, data.maxValue, minOut, maxOut );
+        ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY + output);
+        ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY);
+        ofEndShape();
+        
+        if (drawZeroSep)
+        {
+            ofSetLineWidth(1.25);
+            ofSetColor (175,150,150);
+            ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY,
+                       subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY);
+        }
+    }
+    void update ( void )
+    {
+        //
+    }
+};
+
+
+#endif /* LineGraphHistory_h */
diff --git a/tools/RapidVisualizerOSC/src/RapidVisualization.cpp b/tools/RapidVisualizerOSC/src/RapidVisualization.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7fbf671dff5b8ad5681853fdbd6f65a8ee214beb
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/RapidVisualization.cpp
@@ -0,0 +1,168 @@
+//
+//  RapidVisualization.cpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 13/11/2017.
+//
+//
+
+#include <stdio.h>
+#include "RapidVisualization.hpp"
+
+RapidVisualization::RapidVisualization ( void )
+{
+    
+}
+
+RapidVisualization::~RapidVisualization ( void )
+{
+    std::map<std::string, RapidVisualizer*>::iterator it;
+    for(it = visualizers.begin(); it != visualizers.end(); ++it)
+    {
+        if (it->second)
+            delete it->second;
+    }
+}
+
+void RapidVisualization::setup ( ofRectangle posAndSize, uint32_t defaultHistorySize )
+{
+    this->posAndSize = posAndSize;
+    this->defaultHistorySize = defaultHistorySize;
+}
+
+std::pair<std::string, std::string> RapidVisualization::getRoute(std::string& address)
+{
+    std::pair<std::string, std::string> ret;
+    size_t delimPos = address.substr(1).find("/");
+    if (delimPos != std::string::npos)
+    {
+        delimPos += 1;
+        ret.first = address.substr(0, delimPos);
+        ret.second = address.substr(delimPos);
+    }
+    else
+    {
+        ret.first = address.substr(0, address.length());
+        ret.second = "/";
+    }
+    return ret;
+}
+
+void RapidVisualization::addData ( std::string& address, std::vector<double>& data )
+{
+    std::pair<std::string, std::string> route = getRoute(address);
+    if ( visualizers.find(route.first) == visualizers.end() ) {
+        RapidVisualizer* ptr = visualizers[route.first] = new RapidVisualizer(); // Add new graph
+        ptr->setup(route.first, RapidVisualizer::LINE_GRAPH_WITH_HISTORY, defaultHistorySize, Graph::GRAPHS_STACKED, false, ofRectangle(0,0,100,100));
+        updateRep();
+    }
+    
+    RapidVisualizer* rapidVizPtr = visualizers[route.first];
+    rapidVizPtr->addData(address, data);
+}
+
+void RapidVisualization::addData ( std::string& graphName, std::string& subGraphName, std::vector<double>& data )
+{
+    if ( visualizers.find(graphName) == visualizers.end() ) {
+        RapidVisualizer* ptr = visualizers[graphName] = new RapidVisualizer(); // Add new graph
+        ptr->setup(graphName, RapidVisualizer::LINE_GRAPH_WITH_HISTORY, defaultHistorySize, Graph::GRAPHS_STACKED, false, ofRectangle(0,0,100,100));
+        updateRep();
+    }
+    
+    RapidVisualizer* rapidVizPtr = visualizers[graphName];
+    rapidVizPtr->addData(subGraphName, data);
+}
+
+void RapidVisualization::reset ( void )
+{
+    std::map<std::string, RapidVisualizer*>::iterator it;
+    for(it = visualizers.begin(); it != visualizers.end(); ++it)
+    {
+        if (it->second)
+            delete it->second;
+    }
+    visualizers.clear();
+}
+
+void RapidVisualization::update ( void )
+{
+    uint32_t tempNumGraphs = 0;
+    bool resetCase = false; // This is terrible  (stops jitter when selecting new graph type)
+    std::map<std::string, RapidVisualizer*>::iterator it;
+    for(it = visualizers.begin(); it != visualizers.end(); ++it)
+    {
+        it->second->update();
+        uint32_t tGraph = it->second->getNumGraphs();
+        if (tGraph == 0)
+        {
+            resetCase = true;
+            break;
+        }
+        tempNumGraphs += tGraph;
+    }
+    if (tempNumGraphs != numGraphs && !resetCase)
+    {
+        numGraphs = tempNumGraphs;
+        updateRep();
+    }
+}
+
+void RapidVisualization::draw ( void )
+{
+    std::map<std::string, RapidVisualizer*>::iterator it;
+    for(it = visualizers.begin(); it != visualizers.end(); ++it)
+    {
+        it->second->draw();
+    }
+    if (!guiHidden)
+    for(it = visualizers.begin(); it != visualizers.end(); ++it)
+    {
+        it->second->drawMenu(posAndSize); // Stop menu being behind next graph
+    }
+    if (numGraphs == 0)
+    {
+        drawTextLabel("Waiting for OSC messages on port 8338", ofVec2f(posAndSize.x+posAndSize.width/2, posAndSize.y), ofColor(24, 219, 92), ofColor(255, 157, 117), TextAlignment::CENTER, false );
+    }
+}
+
+void RapidVisualization::setPos ( ofVec2f pos )
+{
+    posAndSize.x = pos.x;
+    posAndSize.y = pos.y;
+    updateRep();
+}
+void RapidVisualization::setSize ( ofVec2f size )
+{
+    posAndSize.width = size.x;
+    posAndSize.height = size.y;
+    updateRep();
+}
+
+void RapidVisualization::setPosAndSize ( ofRectangle posAndSize )
+{
+    this->posAndSize = posAndSize;
+    updateRep();
+}
+
+void RapidVisualization::updateRep ( void )
+{
+    double graphHeight = posAndSize.height/numGraphs; // Height of single graph
+    std::map<std::string, RapidVisualizer*>::iterator it;
+    double drawHeight = posAndSize.y;
+    double height;
+    for(it = visualizers.begin(); it != visualizers.end(); ++it)
+    {
+        height = it->second->getNumGraphs()*graphHeight;
+        it->second->setRect(ofRectangle(posAndSize.x,
+                                       drawHeight,
+                                       posAndSize.width,
+                                       height));
+        
+        drawHeight += height;
+    }
+}
+
+void RapidVisualization::setGuiHidden ( bool guiHidden )
+{
+    this->guiHidden = guiHidden;
+}
diff --git a/tools/RapidVisualizerOSC/src/RapidVisualization.hpp b/tools/RapidVisualizerOSC/src/RapidVisualization.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..58f459da79764c8fcc901f236e3dc320f0bfb090
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/RapidVisualization.hpp
@@ -0,0 +1,52 @@
+//
+//  RapidVisualization.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 10/11/2017.
+//
+//
+
+#ifndef RapidVisualization_h
+#define RapidVisualization_h
+
+#include "RapidVisualizer.hpp"
+
+class RapidVisualization
+{
+public:
+    RapidVisualization ( void );
+    ~RapidVisualization ( void );
+    
+    void setup ( ofRectangle posAndSize, uint32_t defaultHistorySize=256 );
+    
+    // Append multiple types of graphs to cycle through as new entry addresses are added
+    // Implement?
+    //RapidVisualizer* addGraphType ( RapidVisualizer::graphTypeRealtime graphType );
+    //RapidVisualizer* addGraphType ( RapidVisualizer::graphTypeWithHistory graphType, uint32_t historySize );
+    
+    void addData ( std::string& address, std::vector<double>& data );
+    void addData ( std::string& graphName, std::string& subGraphName, std::vector<double>& data );
+    void reset ( void );
+    
+    void update ( void );
+    void draw ( void );
+    
+    void setPos ( ofVec2f pos );
+    void setSize ( ofVec2f size );
+    void setPosAndSize ( ofRectangle posAndSize );
+    
+    void setGuiHidden ( bool guiHidden );
+    
+private:
+    bool guiHidden = false;
+    uint32_t numGraphs = 0;
+    std::map<std::string, RapidVisualizer*> visualizers;
+    ofRectangle posAndSize;
+    
+    uint32_t defaultHistorySize;
+    
+    std::pair<std::string, std::string> getRoute ( std::string& address );
+    void updateRep ( void );
+};
+
+#endif /* RapidVisualization_h */
diff --git a/tools/RapidVisualizerOSC/src/RapidVisualizer.cpp b/tools/RapidVisualizerOSC/src/RapidVisualizer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1fe723fe51e5a1558daa71618f6034983d4d748e
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/RapidVisualizer.cpp
@@ -0,0 +1,259 @@
+//
+//  RapidVisualizer.cpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#include "RapidVisualizer.hpp"
+
+RapidVisualizer::RapidVisualizer ( void )
+{
+    uint32 initialHistorySize = 256;
+    minimumGui.setup();
+    expandedGui.setBackgroundColor(ofColor(0,0,0,127));
+    expandedGui.setup();
+    
+    historySizeSlider.addListener(this, &RapidVisualizer::historySizeSliderChanged);
+    
+    auto gNameRef = expandButton.setup(graphState.label, false);
+    expandButton.setBackgroundColor(ofColor(0, 0, 0, 127));
+    minimumGui.add(gNameRef);
+
+    expandedGui.add(graphTypesLabel.setup("Graph Type",""));
+    expandedGui.add(viewTypes[0].setup("Bar Chart", false));
+    expandedGui.add(viewTypes[1].setup("Line Graph", false));
+    expandedGui.add(viewTypes[2].setup("Line Graph History", false));
+    expandedGui.add(viewTypes[3].setup("Scope", false));
+    expandedGui.add(prefLabel.setup("Preferences",""));
+    expandedGui.add(splitArrayIntoGraphs.setup("Split Multiple Input", false));
+    expandedGui.add(historySizeSlider.setup("History Size", initialHistorySize, 4, 4096));
+    
+    setHistory(initialHistorySize);
+    setLayout (Graph::GRAPHS_STACKED);
+    setSplitEachArgument (false);
+    setRect (ofRectangle(0,0,200,200));
+}
+
+RapidVisualizer::~RapidVisualizer ( void )
+{
+    if (currentGraph)
+    {
+        delete currentGraph;
+    }
+}
+
+void RapidVisualizer::setup ( std::string label, graphTypeT graphType, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize )
+{
+    
+    setLabel (label);
+    setLayout (layout);
+    setSplitEachArgument (splitEachArgument);
+    setRect (positionAndSize);
+    setGraphType (graphType); // FIXME: Check if successfully initialized
+}
+
+void RapidVisualizer::setup ( std::string label, graphTypeT graphType, uint32_t historySize, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize )
+{
+    setLabel (label);
+    setLayout (layout);
+    setSplitEachArgument (splitEachArgument);
+    setRect (positionAndSize);
+    setGraphType (graphType, historySize); // FIXME: Check if successfully initialized
+}
+
+void RapidVisualizer::setLabel ( std::string label )
+{
+    graphState.label = label;
+    expandButton.setName(label);
+    if (currentGraph)
+        currentGraph->updateRep();
+}
+
+void RapidVisualizer::setGraphType ( graphTypeT graphType )
+{
+    if (currentGraphType != graphType)
+    {
+        if (currentGraph)
+        {
+            // TODO: add lock for when doing this, or have all types loaded?
+            delete currentGraph;
+        }
+        switch (graphType) {
+            case BAR_CHART:
+                currentGraph = new BarChart ( &graphState );
+                graphState.hasHistory = false;
+                break;
+            case LINE_GRAPH:
+                currentGraph = new LineGraph ( &graphState );
+                graphState.hasHistory = false;
+                break;
+            case LINE_GRAPH_WITH_HISTORY:
+                currentGraph = new LineGraphHistory ( &graphState );
+                graphState.hasHistory = true;
+                break;
+            case SCOPE:
+                currentGraph = new ScopeWithHistory ( &graphState );
+                graphState.hasHistory = true;
+                break;
+            default:
+                break;
+        }
+        currentGraphType = graphType;
+    }
+}
+
+void RapidVisualizer::setGraphType ( graphTypeT graphType, uint32_t historySize )
+{
+    setHistory(historySize);
+    setGraphType(graphType);
+}
+
+void RapidVisualizer::setLayout ( Graph::graphLayout layout )
+{
+    graphState.layout = layout;
+    if (currentGraph)
+        currentGraph->updateRep();
+}
+
+void RapidVisualizer::setSplitEachArgument ( bool splitEachArgument )
+{
+    this->splitEachArgument = splitEachArgument;
+    splitArrayIntoGraphs = splitEachArgument;
+}
+
+void RapidVisualizer::setPos ( ofVec2f pos )
+{
+    graphState.positionAndSize.x = pos.x;
+    graphState.positionAndSize.y = pos.y;
+    if (currentGraph)
+        currentGraph->updateRep();
+}
+
+void RapidVisualizer::setSize ( ofVec2f size )
+{
+    graphState.positionAndSize.width = size.x;
+    graphState.positionAndSize.height = size.y;
+    if (currentGraph)
+        currentGraph->updateRep();
+}
+
+void RapidVisualizer::setRect ( ofRectangle positionAndSize )
+{
+    graphState.positionAndSize = positionAndSize;
+    if (currentGraph)
+        currentGraph->updateRep();
+}
+
+void RapidVisualizer::setHistory( uint32_t historySize )
+{
+    graphState.historySize = historySize;
+    historySizeSlider = historySize;
+    if (currentGraph)
+        currentGraph->updateRep();
+}
+
+void RapidVisualizer::historySizeSliderChanged (int32_t &val)
+{
+    setHistory(val);
+}
+
+void RapidVisualizer::addData ( std::string subLabel, std::vector<double>& data )
+{
+    if (currentGraph)
+    {
+        if (splitEachArgument && data.size() > 1)
+        {
+            int16_t currentIndex = 0;
+            std::vector<double> splitData;
+            for (double d : data)
+            {
+                splitData = {d};
+                currentGraph->addData (subLabel + ofToString(currentIndex), splitData);
+                ++currentIndex;
+            }
+        }
+        else
+            currentGraph->addData (subLabel, data);
+    }
+}
+
+void RapidVisualizer::update ( void )
+{
+    if (currentGraph)
+    {
+        currentGraph->update();
+    }
+}
+
+void RapidVisualizer::drawMenu ( ofRectangle mainPosAndSize )
+{
+    minimumGui.setPosition(graphState.positionAndSize.x, graphState.positionAndSize.y);
+    minimumGui.draw();
+    if (menuActive)
+    {
+        double expandedGuiXPos = graphState.positionAndSize.x + minimumGui.getWidth();
+        double expandedGuiYPos = graphState.positionAndSize.y;
+        double mainYPlusHeight = mainPosAndSize.y + mainPosAndSize.height;
+        double check = expandedGuiYPos + expandedGui.getHeight() - mainYPlusHeight;
+        
+        if (check > 0)
+        {
+            expandedGuiYPos -= check;
+        }
+        
+        expandedGui.setPosition(expandedGuiXPos, expandedGuiYPos);
+        expandedGui.draw();
+    }
+}
+
+void RapidVisualizer::draw ( void )
+{
+    
+    if (currentGraph)
+    {
+        currentGraph->draw();
+    }
+    //drawMenu();
+    menuActive = expandButton;
+    if (menuActive)
+    {
+        bool noneActive = true;
+        for (uint8_t i = 0; i < NUMVIEWTYPES; ++i)
+        {
+            if (viewTypes[i] && !oldTypeToggles[i])
+            {
+                std::fill(viewTypes, viewTypes + NUMVIEWTYPES, false);
+                viewTypes[i] = true;
+                setGraphType(static_cast<graphTypeT>(i));
+            }
+            if (viewTypes[i])
+                noneActive = false;
+            oldTypeToggles[i] = viewTypes[i];
+        }
+        if (noneActive && currentGraphType != NOT_INITIALIZED)
+        {
+            viewTypes[currentGraphType] = true;
+        }
+        if (splitEachArgument != splitArrayIntoGraphs)
+        {
+            // Dirty, solution for now
+            if (currentGraph)
+                currentGraph->reset();
+            splitEachArgument = splitArrayIntoGraphs;
+        }
+    }
+}
+
+uint32_t RapidVisualizer::getNumGraphs ( void ) const
+{
+    if (currentGraph)
+    {
+        return currentGraph->getNumSubGraphs();
+    } else {
+        return 0;
+    }
+}
+
+#undef NUMVIEWTYPES
diff --git a/tools/RapidVisualizerOSC/src/RapidVisualizer.hpp b/tools/RapidVisualizerOSC/src/RapidVisualizer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0e4a9f2c402fda3d9f78a426c39aa8055f5ec4be
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/RapidVisualizer.hpp
@@ -0,0 +1,79 @@
+//
+//  RapidVisualizer.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#ifndef RapidVisualizer_hpp
+#define RapidVisualizer_hpp
+
+#include <stdio.h>
+#include <map>
+#include "ofMain.h"
+#include "Graph.hpp"
+#include "BarChart.hpp"
+#include "LineGraph.hpp"
+#include "LineGraphHistory.hpp"
+#include "ScopeWithHistory.hpp"
+
+#define NUMVIEWTYPES 4
+
+// TODO add historySize slider and init with default 256 or so
+
+class RapidVisualizer {
+public:
+    enum graphTypeT {
+        BAR_CHART,
+        LINE_GRAPH,
+        LINE_GRAPH_WITH_HISTORY,
+        SCOPE,
+        NOT_INITIALIZED
+    };
+    
+    RapidVisualizer ( void );
+    ~RapidVisualizer ( void );
+    
+    void setup ( std::string label, graphTypeT graphType, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize );
+    void setup ( std::string label, graphTypeT graphType, uint32_t historySize, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize );
+    
+    void setLabel ( std::string label );
+    void setGraphType ( graphTypeT graphType );
+    void setGraphType ( graphTypeT graphType, uint32_t historySize );
+    void setLayout ( Graph::graphLayout layout );
+    void setSplitEachArgument ( bool splitEachArgument );
+    void setPos ( ofVec2f pos );
+    void setSize ( ofVec2f size );
+    void setRect ( ofRectangle rect );
+    void setHistory ( uint32_t historySize );
+    void historySizeSliderChanged (int32_t &val);
+    
+    void addData ( std::string subLabel, std::vector<double>& data );
+    void update ( void );
+    void drawMenu ( ofRectangle mainPosAndSize );
+    void draw ( void );
+    
+    uint32_t getNumGraphs ( void ) const;
+    
+private:
+    graphTypeT currentGraphType = NOT_INITIALIZED;
+    Graph::GraphState graphState;
+    Graph* currentGraph = nullptr;
+    bool splitEachArgument = false;
+    bool menuActive = false;
+    
+    ofxLabel graphName;
+    ofxLabel graphTypesLabel;
+    ofxLabel prefLabel;
+    ofxPanel minimumGui;
+    ofxToggle expandButton;
+    ofxPanel expandedGui;
+    ofxIntSlider historySizeSlider;
+    ofxToggle splitArrayIntoGraphs;
+    
+    bool oldTypeToggles[NUMVIEWTYPES];
+    ofxToggle viewTypes[NUMVIEWTYPES];
+};
+
+#endif /* RapidVisualizer_hpp */
diff --git a/tools/RapidVisualizerOSC/src/RealTimeGraph.hpp b/tools/RapidVisualizerOSC/src/RealTimeGraph.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..99e928e2bfca55c44fd94c9056b4e1adbe67d1ea
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/RealTimeGraph.hpp
@@ -0,0 +1,107 @@
+//
+//  RealTimeGraph.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 09/11/2017.
+//
+//
+
+#ifndef RealTimeGraph_h
+#define RealTimeGraph_h
+
+#include <map>
+#include <vector>
+#include <string>
+#include "Graph.hpp"
+
+class RealTimeGraph : public Graph
+{
+public:
+    RealTimeGraph ( GraphState* state )
+    : Graph(state)
+    {
+    }
+    ~RealTimeGraph ( void )
+    {
+    }
+    
+    void addData ( std::string subLabel, std::vector<double>& data )
+    {
+        if ( subLabelData.find(subLabel) == subLabelData.end() ) {
+            // not found
+            subLabelData[subLabel] = DataContainer<std::vector<double>>();
+        }
+        
+        subLabelData[subLabel].labelData = data;
+        subLabelData[subLabel].updateMinMax();
+    }
+    
+    virtual void reset ( void )
+    {
+        subLabelData.clear();
+    }
+    
+    virtual void updateRep ( void ) = 0; // update representation
+    virtual void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelrect ) = 0;
+    
+    virtual void update ( void ) = 0;
+    
+    void draw ( void )
+    {
+        uint32_t numElements = subLabelData.size();
+        uint16_t heightBetweenSubLabels = state->positionAndSize.height/numElements;
+        uint16_t subLabelY = 0;
+        
+        ofSetColor (255,255,255);
+        ofDrawLine(state->positionAndSize.x, state->positionAndSize.y,
+                   state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y);
+        
+        std::map<std::string, DataContainer<std::vector<double>>>::iterator it;
+        for(it = subLabelData.begin(); it != subLabelData.end(); ++it)
+        {
+            std::string subLabel = it->first;
+            DataContainer<std::vector<double>>& data = it->second;
+            
+            drawSubGraph (subLabel, data, ofRectangle(state->positionAndSize.x,
+                                                           state->positionAndSize.y + subLabelY,
+                                                           state->positionAndSize.width,
+                                                           heightBetweenSubLabels));
+            // Draw label and background
+            drawTextLabel(subLabel, ofVec2f(state->positionAndSize.x + state->positionAndSize.width,
+                                            state->positionAndSize.y + subLabelY),
+                          ofColor(100, 100, 100), ofColor(textColor), TextAlignment::RIGHT, false);
+            
+            
+            // Draw max value
+            drawTextLabel(ofToString(data.maxValue),
+                          ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2,
+                                            state->positionAndSize.y + subLabelY),
+                          ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, false);
+
+            // Increment Y position
+            subLabelY += heightBetweenSubLabels;
+            
+            // Draw min value
+            // Could show actually found min value
+            drawTextLabel(ofToString((data.minValue < 0) ? -data.maxValue : 0),
+                          ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2,
+                                  state->positionAndSize.y + subLabelY),
+                          ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, true);
+            
+            // Draw Line at bottom of graph
+            ofSetLineWidth(2.0);
+            ofSetColor (180,180,180);
+            ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + subLabelY,
+                       state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + subLabelY);
+        }
+    }
+    
+    uint32_t getNumSubGraphs ( void ) const
+    {
+        return subLabelData.size();
+    }
+protected:
+    std::map <std::string, DataContainer<std::vector<double>>> subLabelData;
+};
+
+#endif /* RealTimeGraph_h */
diff --git a/tools/RapidVisualizerOSC/src/ScopeWithHistory.hpp b/tools/RapidVisualizerOSC/src/ScopeWithHistory.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..60ab23e17e9b8d023ffb3ddb8c743e3bee94dd30
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/ScopeWithHistory.hpp
@@ -0,0 +1,184 @@
+//
+//  ScopeWithHistory.hpp
+//  RapidVisualizerOSC
+//
+//  Created by James on 12/11/2017.
+//
+//
+
+#ifndef ScopeWithHistory_h
+#define ScopeWithHistory_h
+
+#include <stdio.h>
+#include "Graph.hpp"
+
+class ScopeWithHistory : public Graph
+{
+public:
+    ScopeWithHistory ( GraphState* state ) : Graph (state)
+    {
+        //
+    }
+    ~ScopeWithHistory ( void )
+    {
+        //
+    }
+    void addData ( std::string subLabel, std::vector<double>& data )
+    {
+        if (data.size() < state->historySize)
+        {
+            //FIXME: can be sped up by using the result of this search instead of accessing by[] again
+            if ( subLabelData.find(subLabel) == subLabelData.end() ) {
+                // not found
+                DataContainer<std::vector<double>> container;
+                container.labelData.resize(state->historySize);
+                std::fill(container.labelData.begin(), container.labelData.end(), 0.0);
+                subLabelData[subLabel] = container;
+            }
+            DataContainer<std::vector<double>>&  dataRef = subLabelData[subLabel];
+            std::vector<double>& referencedList = dataRef.labelData;
+            while (referencedList.size() >= state->historySize)
+            {
+                referencedList.pop_back();
+            }
+            for (int32_t i = data.size()-1; i >= 0; --i)
+            {
+                double val = data[i];
+                if (val < dataRef.minValue)
+                    dataRef.minValue = val;
+                if (val > dataRef.maxValue)
+                    dataRef.maxValue = val;
+                if (fabs(val) > dataRef.maxValue)
+                    dataRef.maxValue = fabs(val);
+                if (referencedList.size() + data.size() >= state->historySize)
+                {
+                    referencedList[dataRef.iteratorPos] = val;
+                    dataRef.iteratorPos = (dataRef.iteratorPos + data.size()) % state->historySize;
+                } else {
+                    referencedList.insert(referencedList.begin(), val);
+                }
+            }
+        }
+    }
+    void updateRep ( void )
+    {
+        //
+    }
+    void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelRect )
+    {
+        double
+        minIn = 0,
+        minOut = 0,
+        maxOut = -subLabelRect.height,
+        startPosY = subLabelRect.height,
+        pointDistance = subLabelRect.width/data.labelData.size(),
+        separation = pointDistance/2;
+        //halfSeparation = separation/2;
+        bool drawZeroSep = false;
+        
+        if (data.minValue < 0)
+        { // Add negative part
+            startPosY = subLabelRect.height/2;
+            minIn = -data.maxValue;
+            minOut = subLabelRect.height/2;
+            maxOut /= 2;
+            drawZeroSep = true;
+        }
+        
+        ofBeginShape();
+        ofFill();
+        ofVertex(subLabelRect.x, subLabelRect.y + startPosY);
+        double output = mapVals(data.labelData.front(), minIn, data.maxValue, minOut, maxOut );
+        ofVertex(subLabelRect.x, subLabelRect.y + startPosY + output);
+        uint32_t i = 0;
+        for (double d : data.labelData)
+        {
+            output = mapVals(d, minIn, data.maxValue, minOut, maxOut );
+            ofSetColor (graphColor);
+            
+            ofVertex(subLabelRect.x + pointDistance * i + separation, subLabelRect.y + startPosY + output);
+            //ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output );
+            ++i;
+            
+        }
+        output = mapVals(data.labelData.back(), minIn, data.maxValue, minOut, maxOut );
+        ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY + output);
+        ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY);
+        ofEndShape();
+        
+        if (drawZeroSep)
+        {
+            ofSetLineWidth(1.25);
+            ofSetColor (175,150,150);
+            ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY,
+                       subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY);
+        }
+    }
+    void update ( void )
+    {
+        //
+    }
+    
+    void reset ( void )
+    {
+        subLabelData.clear();
+    }
+    
+    void draw ( void )
+    {
+        uint32_t numElements = subLabelData.size();
+        uint16_t heightBetweenSubLabels = state->positionAndSize.height/numElements;
+        uint16_t subLabelY = 0;
+        
+        ofSetColor (255,255,255);
+        ofDrawLine(state->positionAndSize.x, state->positionAndSize.y,
+                   state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y);
+        
+        std::map<std::string, DataContainer<std::vector<double>>>::iterator it;
+        for(it = subLabelData.begin(); it != subLabelData.end(); ++it)
+        {
+            std::string subLabel = it->first;
+            DataContainer<std::vector<double>>& data = it->second;
+            
+            drawSubGraph (subLabel, data, ofRectangle(state->positionAndSize.x,
+                                                      state->positionAndSize.y + subLabelY,
+                                                      state->positionAndSize.width,
+                                                      heightBetweenSubLabels));
+            // Draw label and background
+            drawTextLabel(subLabel, ofVec2f(state->positionAndSize.x + state->positionAndSize.width,
+                                            state->positionAndSize.y + subLabelY),
+                          ofColor(100, 100, 100), ofColor(textColor), TextAlignment::RIGHT, false);
+            
+            
+            // Draw max value
+            drawTextLabel(ofToString(data.maxValue),
+                          ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2,
+                                  state->positionAndSize.y + subLabelY),
+                          ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, false);
+            
+            // Increment Y position
+            subLabelY += heightBetweenSubLabels;
+            
+            // Draw min value
+            // Show actual min value?
+            drawTextLabel(ofToString((data.minValue < 0) ? -data.maxValue : 0),
+                          ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2,
+                                  state->positionAndSize.y + subLabelY),
+                          ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, true);
+            
+            // Draw Line at bottom of graph
+            ofSetLineWidth(2.0);
+            ofSetColor (180,180,180);
+            ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + subLabelY,
+                       state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + subLabelY);
+        }
+    }
+    uint32_t getNumSubGraphs ( void ) const
+    {
+        return subLabelData.size();
+    }
+protected:
+    std::map <std::string, DataContainer<std::vector<double>>> subLabelData;
+};
+
+#endif /* ScopeWithHistory_h */
diff --git a/tools/RapidVisualizerOSC/src/main.cpp b/tools/RapidVisualizerOSC/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e57370b26ee652c85ce0b32f19eace3b681585a4
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "ofApp.h"
+
+//========================================================================
+int main( ){
+	ofSetupOpenGL(1024,768,OF_WINDOW);			// <-------- setup the GL context
+
+	// this kicks off the running of my app
+	// can be OF_WINDOW or OF_FULLSCREEN
+	// pass in width and height too:
+	ofRunApp(new ofApp());
+
+}
diff --git a/tools/RapidVisualizerOSC/src/ofApp.cpp b/tools/RapidVisualizerOSC/src/ofApp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f58e82e2551adcb065d659823e7e6857c5754aac
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/ofApp.cpp
@@ -0,0 +1,114 @@
+#include "ofApp.h"
+
+//--------------------------------------------------------------
+void ofApp::setup(){
+    receiver.setup ( PORT );
+    rv.setup(ofRectangle(0,0,1024,768));
+    current_msg_string = 0;
+    ofBackground(30, 30, 30);
+}
+
+
+//--------------------------------------------------------------
+void ofApp::update(){
+    static float a = 0;
+    while( receiver.hasWaitingMessages() )
+    {
+        
+        ofxOscMessage m;
+        receiver.getNextMessage(m);
+        std::string address = m.getAddress();
+        std::vector<double> values;
+        for ( int i=0; i<m.getNumArgs(); i++ )
+        {
+            double value = 0.0;
+            // display the argument - make sure we get the right type
+            if( m.getArgType( i ) == OFXOSC_TYPE_INT32 )
+                value = static_cast<double>( m.getArgAsInt32( i ) );
+            else if( m.getArgType( i ) == OFXOSC_TYPE_INT64 )
+                value = static_cast<double>( m.getArgAsInt64( i ) );
+            else if( m.getArgType( i ) == OFXOSC_TYPE_FLOAT )
+                value = static_cast<double>( m.getArgAsFloat( i ) );
+            else if( m.getArgType( i ) == OFXOSC_TYPE_DOUBLE)
+                value = static_cast<double>( m.getArgAsDouble( i ) );
+            else
+                printf("Unknown datatype\n");
+            
+            values.push_back(value);
+         
+        }
+        
+        rv.addData(address, values);
+    }
+    rv.update();
+}
+
+//--------------------------------------------------------------
+void ofApp::draw(){
+    ofBackgroundGradient(ofColor(0,0,0), ofColor(10,10,10));
+    rv.draw();
+}
+
+//--------------------------------------------------------------
+void ofApp::keyPressed(int key){
+    if(key == 'h'){
+        guiHide = !guiHide;
+        rv.setGuiHidden(guiHide);
+    }
+    if(key == 'c'){
+        rv.reset();
+    }
+    if(key == 'm'){
+        // Show main menu
+    }
+}
+
+//--------------------------------------------------------------
+void ofApp::keyReleased(int key){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseMoved(int x, int y ){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseDragged(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mousePressed(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseReleased(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseEntered(int x, int y){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::mouseExited(int x, int y){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::windowResized(int w, int h){
+    rv.setSize(ofVec2f(w, h));
+}
+
+//--------------------------------------------------------------
+void ofApp::gotMessage(ofMessage msg){
+
+}
+
+//--------------------------------------------------------------
+void ofApp::dragEvent(ofDragInfo dragInfo){ 
+
+}
diff --git a/tools/RapidVisualizerOSC/src/ofApp.h b/tools/RapidVisualizerOSC/src/ofApp.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0a54c83b23be2a28c979e78c2f0da60b63c6ca7
--- /dev/null
+++ b/tools/RapidVisualizerOSC/src/ofApp.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "ofMain.h"
+#include "ofxOsc.h"
+#include "RapidVisualization.hpp"
+#define PORT 8338
+#define NUM_MSG_STRINGS 20
+
+class ofApp : public ofBaseApp{
+
+public:
+    void setup();
+    void update();
+    void draw();
+
+    void keyPressed(int key);
+    void keyReleased(int key);
+    void mouseMoved(int x, int y );
+    void mouseDragged(int x, int y, int button);
+    void mousePressed(int x, int y, int button);
+    void mouseReleased(int x, int y, int button);
+    void mouseEntered(int x, int y);
+    void mouseExited(int x, int y);
+    void windowResized(int w, int h);
+    void dragEvent(ofDragInfo dragInfo);
+    void gotMessage(ofMessage msg);
+		
+private:
+    bool guiHide = false;
+    RapidVisualization rv;
+    ofxOscReceiver receiver;
+    int current_msg_string;
+    
+    std::string msg_strings[NUM_MSG_STRINGS];
+    float timers[NUM_MSG_STRINGS];
+};