diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/BarChart.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/BarChart.hpp
deleted file mode 100644
index 379b2df0a7c287c582dc0f1175c0b794dc3c1d77..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/BarChart.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/Graph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/Graph.hpp
deleted file mode 100644
index 546785f60e37aef49c1da60706e6bb9150946121..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/Graph.hpp
+++ /dev/null
@@ -1,122 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/HistoryGraph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/HistoryGraph.hpp
deleted file mode 100644
index 8086167419b95e1fbd7518ecf3b7fe703da6eb4a..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/HistoryGraph.hpp
+++ /dev/null
@@ -1,125 +0,0 @@
-//
-//  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 (textColor);
-        ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + heightBetweenSubLabels - 1.5,
-                   state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + heightBetweenSubLabels - 1.5);
-         
-        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 + 3,
-                                                      state->positionAndSize.width,
-                                                      heightBetweenSubLabels - 6));
-            // 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 + 3,
-                       state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + subLabelY + 3);*/
-        }
-    }
-    uint32_t getNumSubGraphs ( void ) const
-    {
-        return subLabelData.size();
-    }
-protected:
-    std::map <std::string, DataContainer<std::list<double>>> subLabelData;
-};
-#endif /* HistoryGraph_h */
diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraph.hpp
deleted file mode 100644
index 88669d91cbbb4f167f58b30f77c7a3db9b5b2713..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraph.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraphHistory.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraphHistory.hpp
deleted file mode 100644
index e3b32f887a93192d341efff9fced03f316649e0f..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraphHistory.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.cpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.cpp
deleted file mode 100644
index dc2bc832c99c53e7bc623fd9fa1ae9e7a92a2954..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-//
-//  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));
-    }
-    
-    RapidVisualizer* rapidVizPtr = visualizers[route.first];
-    rapidVizPtr->addData(address, data);
-    updateRep();
-}
-
-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));
-    }
-    
-    RapidVisualizer* rapidVizPtr = visualizers[graphName];
-    rapidVizPtr->addData(subGraphName, data);
-    updateRep();
-}
-
-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 data", 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::setHistorySize ( uint32_t size )
-{
-    defaultHistorySize = size;
-}
-
-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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.hpp
deleted file mode 100644
index 5485e6cb064bd9722d3b6bd865856cc13230fd66..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-//  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 setHistorySize ( uint32_t size );
-    void setGraphColor ( ofColor graphColor );
-    //void setGraphColor ( ofColor backgroundColor );
-    //void setGraphColor ( ofColor textColor );
-    
-    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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.cpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.cpp
deleted file mode 100644
index 1fe723fe51e5a1558daa71618f6034983d4d748e..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.hpp
deleted file mode 100644
index 0e4a9f2c402fda3d9f78a426c39aa8055f5ec4be..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.hpp
+++ /dev/null
@@ -1,79 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RealTimeGraph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RealTimeGraph.hpp
deleted file mode 100644
index 99e928e2bfca55c44fd94c9056b4e1adbe67d1ea..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RealTimeGraph.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/rapidVisualizer/ScopeWithHistory.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/ScopeWithHistory.hpp
deleted file mode 100644
index 60ab23e17e9b8d023ffb3ddb8c743e3bee94dd30..0000000000000000000000000000000000000000
--- a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/ScopeWithHistory.hpp
+++ /dev/null
@@ -1,184 +0,0 @@
-//
-//  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/examples/ofx/Bitalino_rapidmix/src/BITEnvironment.cpp b/examples/ofx/Bitalino_rapidmix/src/BITEnvironment.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2ce0110a2418bf82a2191e4b548486242dbd9419
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/BITEnvironment.cpp
@@ -0,0 +1,246 @@
+//
+//  BITEnvironment.cpp
+//  Bitalino
+//
+//  Created by James on 23/11/2017.
+//
+//
+
+#include "BITEnvironment.hpp"
+
+namespace BIT
+{
+void Environment::setup( std::string nameOfBitalino, ofRectangle posAndSize )
+{
+    this->posAndSize = posAndSize;
+    float graphHeight = posAndSize.height / ( NUM_SYNTH_PARAMS + 1 );
+    bst.setup( nameOfBitalino );
+    
+    ofRectangle bitGraphRect( posAndSize.x, posAndSize.y, posAndSize.width, graphHeight );
+    bitalinoGraph.setup( "Bitalino", ofColor( 100, 100, 255 ),
+                        ofColor( 100, 255, 100 ), ofColor( 100, 100, 100 ), bitGraphRect, true, true, 2000 );
+    
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        ofRectangle graphRect( posAndSize.x, posAndSize.y + ( i + 1 ) * graphHeight, posAndSize.width, graphHeight );
+        graphs[ i ].setup( ParamNames[ i ], ofColor( 255, 255, 255 ),
+                          ofColor( 255, 100, 100 ), ofColor( 100, 100, 100 ), graphRect, true, false, 2000 );
+        
+        // Link buffers together
+        bst.loopDataBuffers[ i ].linkTo( &graphs[ i ].memory );
+        graphs[ i ].memory.linkTo( &bst.loopDataBuffers[ i ] );
+    }
+    
+    // Only needs one way link
+    bst.bitalinoChannel.linkTo( &bitalinoGraph.memory );
+}
+    
+void Environment::update ( void )
+{ // This runs concurrent with ofx
+    // THIS can dissapear
+    RingBufferAny::VariableHeader headerInfo;
+    while ( bst.toEnvironment.anyAvailableForPop( headerInfo ) )
+    {
+        if ( headerInfo.type_index == typeid( RecordingSelection ) ) {
+            RecordingSelection sel;
+            bst.toEnvironment.pop( &sel, 1 );
+
+            if ( sel.position < 0 )
+                selectedTrainingParts.clear(  );
+            else
+                selectedTrainingParts.push_back( sel.position );
+        } else if ( headerInfo.type_index == typeid( State ) ) {
+            selectedTrainingParts.clear(  );
+            bst.toEnvironment.pop( &currentState, 1 );
+            switch ( currentState )
+            {
+                case PERFORMING:
+                    bitalinoGraph.graphColor = ofColor( 100, 255, 100 );
+                    bitalinoGraph.redraw(  );
+                    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+                    {
+                        graphs[ i ].graphColor = ofColor( 100, 100, 255 );
+                        graphs[ i ].backgroundColor = ofColor( 255, 255, 255 );
+                        graphs[ i ].redraw(  );
+                    }
+                    break;
+                case RECORDING:
+                    bitalinoGraph.graphColor = ofColor( 100, 255, 100 );
+                    bitalinoGraph.redraw(  );
+                    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+                    {
+                        graphs[ i ].graphColor = ofColor( 255, 255, 255 );
+                        graphs[ i ].backgroundColor = ofColor( 180, 100, 100 );
+                        graphs[ i ].redraw(  );
+                    }
+                    break;
+                case PLAYING:
+                    bitalinoGraph.graphColor = ofColor( 100, 255, 100 );
+                    bitalinoGraph.redraw(  );
+                    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+                    {
+                        graphs[ i ].graphColor = ofColor( 255, 100, 100 );
+                        graphs[ i ].backgroundColor = ofColor( 100, 100, 100 );
+                        graphs[ i ].redraw(  );
+                    }
+                    break;
+                case TRAINING:
+                    // Fallthrough style
+                case IDLE:
+                    bitalinoGraph.graphColor = ofColor( 100, 100, 100 );
+                    bitalinoGraph.redraw(  );
+                    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+                    {
+                        graphs[ i ].graphColor = ofColor( 100, 100, 100 );
+                        graphs[ i ].backgroundColor = ofColor( 100, 100, 100 );
+                        graphs[ i ].redraw(  );
+                    }
+                    break;
+                default:
+                    break;
+            }
+            
+        } else if ( headerInfo.type_index == typeid( BITSequencerThread::RealtimeViewData ) ) {
+            BITSequencerThread::RealtimeViewData data[ headerInfo.valuesPassed ];
+            bst.toEnvironment.pop( data, headerInfo.valuesPassed );
+            for ( size_t i = 0; i < headerInfo.valuesPassed; ++i )
+            {
+                transport = data[ i ].transportPosition;
+            }
+        }
+    }
+    
+    bitalinoGraph.update(  );
+    
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        graphs[ i ].update(  );
+    }
+
+}
+
+bool Environment::isMouseInside ( ofVec2f mousePos)
+{
+    return posAndSize.inside( mousePos );
+}
+
+void Environment::mouseActive ( ofVec2f mousePos, int8_t mouseState, bool mouseStateChanged )
+{
+    if ( currentState == PLAYING && selectedTrainingParts.empty(  ) ) // Only then are buffers to be altered
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        PokeGraph& currentGraph = graphs[ i ];
+        if ( currentGraph.isMouseInside( mousePos ) )
+        {
+            if ( previousActive && previousActive != &currentGraph )
+            {
+                previousActive->mouseActive( mousePos, -1, true );
+            }
+            currentGraph.mouseActive( mousePos, mouseState, mouseStateChanged );
+            previousActive = &currentGraph;
+        }
+    }
+}
+
+void Environment::drawSelectedTrainingParts( void )
+{
+    ofColor highlight( 255, 255, 255, 50 );
+    ofColor pillars( 255, 255, 255, 150 );
+    size_t size = selectedTrainingParts.size(  );
+    
+    int8_t complete = 0;
+    
+    double previousPoint = 0;
+    
+    for ( uint32_t i = 0; i < size; ++i )
+    { // TODO fix wrap cases
+        double point = selectedTrainingParts[ i ];
+        complete = i % 2;
+        
+        if ( i + 1 == size && complete == 0)
+        {
+            double transp = ( transport - point );
+            if ( transp < 0 )
+            {
+                selectedTrainingParts.insert( selectedTrainingParts.begin(  ) + ( i + 1 ),  1.0 );
+                selectedTrainingParts.insert( selectedTrainingParts.begin(  ) + ( i + 2 ),  0.0 );
+                i -= 1;
+                size += 2;
+                continue;
+            }
+            ofRectangle rect( posAndSize.x + point * posAndSize.width, posAndSize.y,
+                            transp * posAndSize.width, posAndSize.height );
+            ofSetColor( highlight );
+            ofFill(  );
+            ofDrawRectangle( rect );
+            ofSetColor( pillars );
+            ofSetLineWidth( 1.5f );
+            ofNoFill(  );
+            ofDrawRectangle( rect );
+            ofSetColor( 255, 255, 255, 255 );
+            return;
+        }
+        if ( complete == 1 )
+        {
+            ofRectangle rect( posAndSize.x + previousPoint * posAndSize.width, posAndSize.y,
+                                ( point - previousPoint ) * posAndSize.width, posAndSize.height );
+            ofSetColor( highlight );
+            ofFill(  );
+            ofDrawRectangle( rect );
+            ofSetColor( pillars );
+            ofSetLineWidth( 1.5f );
+            ofNoFill(  );
+            ofDrawRectangle( rect );
+        }
+        previousPoint = point;
+    }
+    ofSetColor( 255, 255, 255, 255 );
+}
+    
+void Environment::draw ( void )
+{ // This runs concurrent with ofx
+
+    double xPosTransport = posAndSize.x + posAndSize.width * transport;
+    ofDrawLine( xPosTransport, posAndSize.y, xPosTransport, posAndSize.y + posAndSize.height );
+    
+    bitalinoGraph.draw(  );
+    
+    if ( !selectedTrainingParts.empty(  ) )
+        drawSelectedTrainingParts(  );
+    
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        graphs[ i ].draw(  );
+    }
+    
+    bool connected = bst.rapidBitalino.bitalinoThread.isConnected(  );
+    
+    drawTextLabel( stateStrings[ static_cast< uint8_t >( currentState ) ], ofVec2f( posAndSize.x + 4, posAndSize.y + 21 ),
+                  (( connected ) ? ofColor( 24, 219, 92 ) : ofColor( 255, 24, 24 ) ), ofColor( 10, 10, 10 ),
+                  ofxBitmapText::TextAlignment::LEFT, false );
+}
+
+void Environment::resize ( ofRectangle posAndSize )
+{
+    this->posAndSize = posAndSize;
+    
+    float graphHeight = posAndSize.height / ( NUM_SYNTH_PARAMS + 1 );
+    
+    bitalinoGraph.setRect( ofRectangle( posAndSize.x, posAndSize.y, posAndSize.width, graphHeight ) );
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        graphs[ i ].setRect( ofRectangle( posAndSize.x, posAndSize.y + ( i + 1 ) * graphHeight, posAndSize.width, graphHeight ) );
+    }
+}
+
+void Environment::stop( void )
+{
+    bst.stop();
+}
+
+void Environment::audioOut( float *output, int bufferSize, int nChannels )
+{ // Audio thread sync callback
+    bst.audioOut(output, bufferSize, nChannels);
+}
+    
+} // End namespace BIT::
diff --git a/examples/ofx/Bitalino_rapidmix/src/BITEnvironment.hpp b/examples/ofx/Bitalino_rapidmix/src/BITEnvironment.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ecffece24d56183d696ae1153863c5c4ab288f94
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/BITEnvironment.hpp
@@ -0,0 +1,57 @@
+//
+//  BITEnvironment.hpp
+//  Bitalino
+//
+//  Created by James on 23/11/2017.
+//
+//
+
+#ifndef BITEnvironment_hpp
+#define BITEnvironment_hpp
+
+#include <stdio.h>
+#include <vector>
+#include <atomic>
+
+#include "ofMain.h"
+#include "BITSequencerThread.hpp"
+#include "PokeGraph.hpp"
+
+namespace BIT
+{
+// ML Bitalino Synth environment
+// Functions as the view + a portion of the controller ( PokeGraphs )
+class Environment
+{
+public:
+    BITSequencerThread bst;
+    
+    void setup ( std::string nameOfBitalino, ofRectangle posAndSize );
+    void update ( void );
+    bool isMouseInside ( ofVec2f mousePos );
+    void mouseActive ( ofVec2f mousePos, int8_t mouseState, bool mouseStateChanged );
+    void draw ( void );
+    void drawSelectedTrainingParts ( void );
+    void resize ( ofRectangle posAndSize );
+    void stop ( void );
+    void audioOut(float * output, int bufferSize, int nChannels);
+    
+private:
+    std::vector< double > selectedTrainingParts;
+    
+    ofRectangle posAndSize;
+    
+    PokeGraph* previousActive = nullptr;
+
+    PokeGraph bitalinoGraph; // To show the input in sync with output parameters
+    PokeGraph graphs[ NUM_SYNTH_PARAMS ]; // To show and allow editing of parameters
+    
+    double transport;
+    
+    State currentState;
+    
+};
+    
+} // End namespace BIT::
+    
+#endif /* BITSynth_hpp */
diff --git a/examples/ofx/Bitalino_rapidmix/src/BITSequencerThread.cpp b/examples/ofx/Bitalino_rapidmix/src/BITSequencerThread.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..674a91398561a1a8a37d54709b6d15bbbfd31cd1
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/BITSequencerThread.cpp
@@ -0,0 +1,381 @@
+//
+//  BITSequencerThread.cpp
+//  Bitalino
+//
+//  Created by James on 08/12/2017.
+//
+//
+
+#include "BITSequencerThread.hpp"
+
+namespace BIT
+{
+    
+BITSequencerThread::BITSequencerThread ( void ) : ThreadedProcess ()
+{
+    setState(IDLE);
+    recording.store(false);
+    selectingData.store(false);
+    transport.store(0.0);
+}
+
+BITSequencerThread::~BITSequencerThread ( void )
+{
+    
+}
+
+void BITSequencerThread::setup( std::string nameOfBitalino )
+{
+    
+    // Set callback for when model is done training (called in rapidMixThread.update method)
+    rapidMixThread.doneTrainingCallback = [&] ( void )
+    {
+        //printf("New Model Trained\n");
+        sendRunDataToOFX();
+        trainingDone = true;
+        transport.store(0.0);
+        setState( PERFORMING );
+        //trainingText = "New Model Trained";
+    };
+    
+    // Set buttonPressedCallback for rapidBitalino
+    rapidBitalino.buttonPressedCallback = std::bind(&BITSequencerThread::buttonPressed, this);
+    
+    // Set buttonReasedCallback for rapidBitalino
+    rapidBitalino.buttonReleasedCallback = std::bind(&BITSequencerThread::buttonReleased, this);
+    
+    // Set up training thread
+    rapidMixThread.setup();
+    
+    // Set up BITalino accessor + thread
+    rapidBitalino.setup( nameOfBitalino, 10 ); // downsampling 10 of the data (TODO experiment with different settings with bayes)
+    
+    toEnvironment.setup( 8192 ); // Leave room for 16kb of memory to be used in the ring-queue
+    
+    bitalinoChannel.setup( 2000 );
+    
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        loopDataBuffers[ i ].setup( 2000 );
+    }
+    
+    State s = currentState.load(  );
+    toEnvironment.push( &s, 1 ); // Send initial state
+    
+    // Start the thread
+    startThread( 10000 ); // Sleep 10 ms
+}
+
+void BITSequencerThread::setState ( State state )
+{
+    toEnvironment.push ( &state, 1 );
+    this->currentState.store(state);
+}
+
+State BITSequencerThread::getState ( void ) const
+{
+    return this->currentState.load();
+}
+    
+const char* BITSequencerThread::getStateString ( void )
+{
+    return stateStrings[static_cast<uint8_t>(getState())];
+}
+    
+void BITSequencerThread::stop( void )
+{
+    // Stop all asynchronous threads
+    this->stopThread();
+    rapidMixThread.stopThread();
+    rapidBitalino.stop();
+}
+
+void BITSequencerThread::audioOut( float *output, int bufferSize, int nChannels )
+{ // Audio thread sync callback
+    synthesizer.audioOut(output, bufferSize, nChannels);
+}
+
+double BITSequencerThread::getTransport ( void )
+{
+    return transport.load(  );
+}
+    
+void BITSequencerThread::buttonPressed ( void )
+{ // Bitalino button press
+    longSelectionTimer.reset(  );
+    switch ( currentState.load( ) )
+    { // Run update for state
+        case IDLE:
+            //printf( "Started \n" );
+            generateFirstData(  );
+            setState( PLAYING );
+            break;
+        case PERFORMING:
+        {
+            if ( trainingDone )
+            {
+                if ( recording.load(  ) )
+                {
+                    //printf( "Playing recorded gestures \n" );
+                    recording.store( false );
+                    setState( PLAYING );
+                } else {
+                    //printf( "Started recording \n" );
+                    recording.store( true );
+                    transport.store( 0.0 );
+                    
+                    // TODO: create extra state for just recording?
+                    State recState = RECORDING; // Only used by environment for color change
+                    toEnvironment.push( &recState, 1 );
+                }
+            }
+            break;
+        }
+        case PLAYING:
+        {
+            if ( !selectingData.load(  ) )
+            {
+                RecordingSelection sel{ static_cast< double >( loopPosition ) / loopSize };
+                toEnvironment.push( &sel, 1 );
+                
+                //printf( "Selecting data for example \n" );
+                trainingData.createNewPhrase( "NewPhrase" );
+                //printf( "Added training element, now size of %lu\n", trainingData.trainingSet.size(  ) );
+                selectingData.store( true );
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+void BITSequencerThread::buttonReleased( void )
+{ // Bitalino button release
+    State s = currentState.load();
+    switch ( s )
+    { // Run update for state
+        case PLAYING:
+        {
+            if (selectingData.load())
+            {
+                if (longSelectionTimer.getTimeElapsed() > longPress)
+                {
+                    RecordingSelection sel{ static_cast< double >( loopPosition ) / loopSize };
+                    toEnvironment.push( &sel, 1 );
+                    //printf("Recorded example \n");
+                    selectingData.store(false);
+                } else {
+                    //printf("Throwing away last training sample, press was for stopping \n");
+                    trainingData.trainingSet.pop_back();
+                    RecordingSelection sel{ -1.0 };
+                    toEnvironment.push( &sel, 1 );
+                    
+                    bitalinoChannel.setRangeToConstant( 0, loopSize, 0.0 );
+                    // Draw line here for next part ?
+                    
+                    if (trainingData.trainingSet.size() >= 1)
+                    {
+                        //printf("Training on selected data \n");
+                        RecordingSelection sel{ -1.0 };
+                        toEnvironment.push( &sel, 1 );
+                        trainingDone = false;
+                        rapidMixThread.train(trainingData);
+                        setState( TRAINING );
+                    } else {
+                        //printf("Reinitializing");
+                        generateFirstData();
+                        toEnvironment.push(&s, 1); // Make sure everything gets reinitialized
+                    }
+                    selectingData.store(false);
+                }
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    
+}
+
+void BITSequencerThread::mainThreadCallback( void )
+{ // Process thread sync callback
+    // Get input data (BITalino):
+    RealtimeViewData viewData;
+    std::vector< double > inputData = rapidBitalino.update(  ); // Update method uses ringbuffer and is threadsafe
+    State curState = currentState.load(  );
+    bool newState = ( curState != previousState );
+    
+    if ( newState )
+    {
+        dataPlayTimer.reset(  );
+        longSelectionTimer.reset(  );
+        switch ( curState )
+        { // Run inits for states
+            case PERFORMING:
+                loop.clear(  );
+                loopSize = 0;
+                break;
+            case PLAYING:
+                loopPosition = 0;
+                trainingData.trainingSet.clear(  );
+                break;
+            default:
+                break;
+        }
+    } else
+        switch ( curState )
+    { // Run update for state
+        case PERFORMING:
+        { // Update case for performing state
+            if (dataPlayTimer.getTimeElapsed(  ) > controlRate && trainingDone)
+            {
+                if ( !recording.load(  ) )
+                    transport.store( inputData[0] / maxValueEMG );
+                
+                SynthControlData ctrlData( rapidMixThread.model->run( inputData ) );
+                synthesizer.controlDataBuffer.push( &ctrlData, 1 );
+                currentControlData = ctrlData;
+                if ( recording.load(  ) )
+                {
+                    bitalinoChannel.resizeBounded( loopSize + 1 );
+                    bitalinoChannel[ loopSize ] = inputData[ 0 ];
+                    
+                    for ( uint32_t p = 0; p < NUM_SYNTH_PARAMS; ++p )
+                    {
+                        loopDataBuffers[ p ].resizeBounded( loopSize + 1 );
+                        loopDataBuffers[ p ][ loopSize ] = ctrlData.values[ p ];
+                    }
+                    ++loopSize;
+                }
+                dataPlayTimer.reset(  );
+            }
+            break;
+        }
+        case PLAYING:
+        { // Update case for playing state
+            if (dataPlayTimer.getTimeElapsed() > controlRate)
+            {
+                bitalinoChannel[ loopPosition ] = inputData[ 0 ];
+                SynthControlData ctrlData;
+                for ( uint32_t p = 0; p < NUM_SYNTH_PARAMS; ++p )
+                {
+                    ctrlData.values[ p ] = loopDataBuffers[ p ][ loopPosition ];
+                }
+                synthesizer.controlDataBuffer.push(&ctrlData, 1);
+                currentControlData = ctrlData;
+                if (++loopPosition >= loopSize)
+                    loopPosition = 0;
+                
+                transport.store( static_cast< double >( loopPosition ) / loopSize );
+                
+                if (selectingData.load())
+                { // Add element to trainingData
+                    std::vector<double> outputTraining = ctrlData.getValuesAsVector(  );
+                    trainingData.addElement(inputData, outputTraining);
+                }
+                dataPlayTimer.reset();
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    if ( currentState.load(  ) != IDLE )
+    {
+        viewData.transportPosition = transport.load(  );
+        toEnvironment.push( &viewData, 1 );
+    }
+    
+    bitalinoChannel.update(  );
+    
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        loopDataBuffers[ i ].update( );
+    }
+    
+    rapidMixThread.update();
+    previousState = curState;
+}
+
+void BITSequencerThread::generateFirstData ( void )
+{
+    uint8_t midiStart = 55;
+    uint32_t doremiSize = 2;
+    
+    // Calculate new size of buffers
+    uint32_t resizeSize = doremiSize * majorScaleSize * samplesPerExample;
+    
+    // Resize all buffers
+    bitalinoChannel.resizeBounded( resizeSize );
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        loopDataBuffers[ i ].resizeBounded( resizeSize );
+    }
+    
+    // Calculate doremi ladder and also random data blocks for other parameters
+    int index = 0;
+    for (uint32_t i = 0; i < doremiSize; ++i)
+    {
+        for (uint32_t step = 0; step < majorScaleSize; ++step)
+        {
+            double frequency = MTOF( midiStart + ( i * 12 ) + majorScale[ step ] );
+            SynthControlData ctrlData;
+            ctrlData.values[ CARRIER ] = frequency;
+            
+            for ( uint16_t x = 0; x < NUM_SYNTH_PARAMS; ++x )
+            {
+                if ( x != static_cast< uint8_t >( CARRIER ) )
+                    ctrlData.values[ x ] = ( ( double ) rand(  ) / RAND_MAX );
+            }
+            
+            for ( uint32_t p = 0; p < NUM_SYNTH_PARAMS; ++p )
+            {
+                loopDataBuffers[ p ].setRangeToConstant( index, index + samplesPerExample, ctrlData.values[ p ] );
+            }
+            index += samplesPerExample;
+        }
+    }
+    bitalinoChannel.setRangeToConstant( 0, resizeSize, 0 );
+    loopPosition = 0;
+    loopSize = resizeSize;
+}
+
+void BITSequencerThread::generateFirstRandomData ( void )
+{ // NO LONGER USED
+    for (uint32_t i = 0; i < 10; ++i)
+    {
+        SynthControlData ctrlData;
+        for (uint16_t x = 0; x < NUM_SYNTH_PARAMS; ++x)
+        {
+            ctrlData.values[x] = ((double)rand()/RAND_MAX);
+        }
+        for (uint32_t y = 0; y < samplesPerExample; ++y)
+            loop.push_back(ctrlData);
+    }
+}
+
+void BITSequencerThread::sendRunDataToOFX ( void )
+{   // Sweeps through the trained model and shows the input vs the outputs
+    uint32_t numValues = 256;
+    
+    bitalinoChannel.resizeBounded( numValues );
+    for ( uint32_t i = 0; i < NUM_SYNTH_PARAMS; ++i )
+    {
+        loopDataBuffers[ i ].resizeBounded( numValues );
+    }
+    
+    for ( int i = 0.0; i < numValues; i += 1 )
+    {
+        double inp = static_cast< double >( i * 2 );
+        std::vector< double > input( NUM_INPUTS_FOR_TRAINING, inp );
+        bitalinoChannel[ i ] = inp;
+        std::vector< double > outputs = rapidMixThread.model->run( input );
+        for ( uint32_t p = 0; p < NUM_SYNTH_PARAMS; ++p )
+        {
+            loopDataBuffers[ p ][ i ] = outputs[ p ];
+        }
+    }
+}
+    
+}
diff --git a/examples/ofx/Bitalino_rapidmix/src/BITSequencerThread.hpp b/examples/ofx/Bitalino_rapidmix/src/BITSequencerThread.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..18c94345b167c0217c74ca0408e5a210b49c7670
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/BITSequencerThread.hpp
@@ -0,0 +1,110 @@
+//
+//  BITSequencerThread.hpp
+//  Bitalino
+//
+//  Created by James on 08/12/2017.
+//
+//
+
+#ifndef BITSequencerThread_hpp
+#define BITSequencerThread_hpp
+
+#include <stdio.h>
+#include <functional>
+
+#include "Timer.h"
+#include "SigTools.hpp"
+#include "RapidBitalino.h"
+#include "RapidMixThread.h"
+#include "BITSynth.hpp"
+#include "ThreadedProcess.h"
+#include "RingBufferAny.hpp"
+#include "LinkedBuffer.hpp"
+
+namespace BIT
+{
+class BITSequencerThread : public ThreadedProcess
+{
+// Functions as the model
+public:
+    LinkedBuffer< double > bitalinoChannel;
+    LinkedBuffer< double > loopDataBuffers[ NUM_SYNTH_PARAMS ];
+    
+    
+    // Todo move back to protected/private (public for testing w/o bitalino)
+    void buttonPressed ( void );
+    void buttonReleased ( void );
+
+    // BITalino thread, TODO: threadsafe accessors etc
+    RapidBitalino rapidBitalino;
+    // Synth which can only be changed by ringbuffer (threadsafe)
+    Synth synthesizer;
+    
+    // Threadsafe queue of events
+    RingBufferAny toEnvironment;
+    
+    BITSequencerThread ( void );
+    ~BITSequencerThread ( void );
+    
+    void setup ( std::string nameOfBitalino );
+    void setState ( State state ); // Atomic set
+    State getState ( void ) const; // Atomic get
+    const char* getStateString ( void );
+    
+    void stop ( void );
+    void audioOut(float * output, int bufferSize, int nChannels);
+    double getTransport ( void );
+    
+    struct RealtimeViewData {
+        double transportPosition = 0.0;
+    };
+    
+protected:
+    //void buttonPressed ( void );
+    //void buttonReleased ( void );
+    void mainThreadCallback ( void );
+    void generateFirstData ( void );
+    void generateFirstRandomData ( void );
+    void sendRunDataToOFX ( void );
+    
+private:
+    // Rapidmix stuff
+    RapidMixThread rapidMixThread;
+    rapidmix::trainingData trainingData;
+    
+    bool gatheringTrainingData = false;
+    bool trainingDone = false;
+    
+    // Other stuff
+    uint32_t sampleRate = 44100;
+    uint32_t controlRate = 15; // 15ms
+    uint32_t samplesPerExample = 50;
+    
+    // DEBUGDEBUG
+    //--
+    
+    // State
+    std::atomic< State > currentState;
+    State previousState; // (synced with Data thread)
+    
+    std::atomic< bool > recording;
+    std::atomic< bool > selectingData;
+    
+    // Data thread synced
+    BIT::SynthControlData currentControlData;
+    std::vector< BIT::SynthControlData > loop;
+    int loopSize;
+    int loopPosition;
+    
+    // Timers
+    Timer dataPlayTimer;
+    Timer longSelectionTimer;
+    
+    uint32_t longPress = 400; // 400ms
+    double maxValueEMG = 512.0;
+    
+    std::atomic< double > transport;
+};
+
+}
+#endif /* BITSequencerThread_hpp */
diff --git a/examples/ofx/Bitalino_rapidmix/src/BITSynth.cpp b/examples/ofx/Bitalino_rapidmix/src/BITSynth.cpp
index 7557369349b0de41889f70582124145ea6c68bf1..cd3d81a3fd31e769509c17df8a3fcb77bf458828 100644
--- a/examples/ofx/Bitalino_rapidmix/src/BITSynth.cpp
+++ b/examples/ofx/Bitalino_rapidmix/src/BITSynth.cpp
@@ -2,417 +2,41 @@
 //  BITSynth.cpp
 //  Bitalino
 //
-//  Created by James on 23/11/2017.
+//  Created by James on 07/12/2017.
 //
 //
 
 #include "BITSynth.hpp"
 
-BITSynth::BITSynth ( void ) : ThreadedProcess ()
-{
-    inputData(0.0);
-    currentState.store(IDLE);
-    recording.store(false);
-    selectingData.store(false);
-    redraw.store(false);
-    transport.store(0.0);
-    drawState.store(DRAW_IDLE);
-}
-
-BITSynth::~BITSynth ( void )
-{
-    
-}
-
-void BITSynth::setup( ofRectangle posAndSize )
-{
-    this->posAndSize = posAndSize;
-    // Set up visualization
-    //rv.setup(posAndSize, 1024);
-    resize(posAndSize);
-    rv.setGuiHidden(true);
-    
-    // Set model creation callback: (not sync)
-    rapidMixThread.modelCreationCallback = [&] ( void )
-    { // This callback is just in case xmm is used (to change init stuff, probably change to diff setup method?)
-        rapidmix::xmmConfig xcfg;
-        xcfg.relativeRegularization = 0.005;
-        xcfg.absoluteRegularization = 0.005;
-        xcfg.states = 12;
-        xcfg.likelihoodWindow = 10;
-        selectedTraining* t = new selectedTraining();//xcfg);
-        t->setNumHiddenNodes(18);
-        //t->setNumHiddenLayers(2);
-        //t->setNumEpochs(50000);
-        return t;
-    };
-    // Set threaded train callback: (not sync)
-    rapidMixThread.threadedTrainCallback = [&] (selectedTraining* t )
-    {
-        printf("Started training in thread... \n");
-        if (!trainingData.trainingSet.empty() && trainingData.trainingSet[0].elements.size() > 1)
-            if (!t->train(trainingData))
-                printf("Training Failed\n");
-    };
-    // Set callback for when model is done training (called in rapidMixThread.update method)
-    rapidMixThread.doneTrainingCallback = [&] ( void )
-    {
-        sendRunDataToOFX();
-        transport.store(0.0);
-        initialTrainingDone = true;
-        //trainingText = "New Model Trained";
-        //printf("New Model Trained\n");
-    };
-    // Set buttonPressedCallback for rapidBitalino
-    rapidBitalino.buttonPressedCallback = [&] ( void )
-    { // Is called in sync with Data thread
-        longSelectionTimer.reset();
-        switch (currentState.load())
-        { // Run update for state
-            case IDLE:
-                printf("Started \n");
-                generateFirstData();
-                currentState.store(PLAYING);
-                break;
-            case PERFORMING:
-            {
-                if (recording.load())
-                {
-                    printf("Playing recorded gestures \n");
-                    recording.store(false);
-                    currentState.store(PLAYING);
-                } else {
-                    printf("Started recording \n");
-                    recording.store(true);
-                }
-                break;
-            }
-            case PLAYING:
-            {
-                if (!selectingData.load())
-                {
-                    printf("Selecting data for example \n");
-                    trainingData.startRecording("NewPhrase");
-                    selectingData.store(true);
-                }
-                break;
-            }
-            default:
-                break;
-        }
-    };
-
-    // Set buttonReasedCallback for rapidBitalino
-    rapidBitalino.buttonReleasedCallback = [&] ( void )
-    { // Is called in sync with Data thread
-        switch (currentState.load())
-        { // Run update for state
-            case PLAYING:
-            {
-                if (selectingData.load())
-                {
-                    if (longSelectionTimer.getTimeElapsed() > longPress)
-                    {
-                        printf("Recorded example \n");
-                        selectingData.store(false);
-                    } else {
-                        printf("Throwing away last training sample, press was for stopping \n");
-                        trainingData.trainingSet.pop_back();
-                        
-                        if (trainingData.trainingSet.size() >= 1)
-                        {
-                            //if (dataIsAbove) TODO test if data is not to flat
-                            printf("Training on selected data \n");
-                            rapidMixThread.train();
-                            currentState.store(PERFORMING);
-                        } else {
-                            printf("Reinitializing");
-                            loop.clear();
-                            generateFirstData();
-                            sendLoopDataToOFX();
-                        }
-                        selectingData.store(false);
-                    }
-                }
-                break;
-            }
-            default:
-                break;
-        }
-    };
-
-    // Set up training thread
-    rapidMixThread.setup();
-    
-    // Set up BITalino accessor + thread
-    rapidBitalino.setup( 10 ); // downsampling 10 of the data (TODO experiment with different settings with bayes)
-    
-    // Set up the ringbuffer for controldata which is pushed in to the audio thread
-    controlDataBuffer.setup(100); // Leave room for 10 control data to sync over to audio thread
-    // ^ TODO try highter control data storage room with usleep implemented in data thread
-    
-    toOFXVis.setup(1000); // Leave room for 1000 data to sync over to ofx side
-    
-    toOFXRunVis.setup(1000); // Leave room for 1000 data to sync over to ofx side
-    
-    // Start the thread
-    startThread();
-}
-
-void BITSynth::setState ( State state )
-{
-    this->currentState.store(state);
-}
-
-void BITSynth::inputData( double input )
-{ // This being atomic can negate the need for a ringbuffer...
-    // TODO think of what will be the solution of input here
-    //currentInput.store(0.0);
-}
-
-void BITSynth::update ( void )
-{
-    if (redraw.load()) // replace with safe condition / lock?
-    {
-        rv.reset();
-        uint32_t itemsToRead = toOFXRunVis.items_available_for_read();
-        drawType t = drawState.load();
-        if (t == DRAW_RUN)
-        {
-            itemsToRead = toOFXRunVis.items_available_for_read();
-        } else if (t == DRAW_PLAYBACK) {
-            itemsToRead = toOFXVis.items_available_for_read();
-        }
-        
-        if (itemsToRead)
-        {
-            rv.setHistorySize(itemsToRead);
-            SynthControlData data[itemsToRead];
-            if (t == DRAW_RUN)
-            {
-                toOFXRunVis.pop(data, itemsToRead);
-            } else if (t == DRAW_PLAYBACK) {
-                toOFXVis.pop(data, itemsToRead);
-            }
-            
-            for (uint32_t i=0; i < itemsToRead; ++i)
-            {
-                std::vector<double> dVect = data[i].getValuesAsVector();
-                for (uint32_t param=0; param < BIT::NUM_SYNTH_PARAMS; ++param)
-                {
-                    std::vector<double> sVect = {dVect[param]};
-                    rv.addData("/"+std::string(BIT::ParamNames[param]), sVect);
-                }
-            }
-        }
-        redraw.store(false);
-    }
-
-    rv.update();
-}
-
-void BITSynth::draw ( void )
-{
-    rv.draw();
-    
-    double xPosTransport = posAndSize.x + posAndSize.width * transport.load();
-    ofDrawLine(xPosTransport, posAndSize.y, xPosTransport, posAndSize.y + posAndSize.height);
-    
-    rapidBitalino.draw();
-    drawTextLabel(stateStrings[currentState.load()], ofVec2f(posAndSize.x, posAndSize.y+21), ofColor(24, 219, 92), ofColor(10, 10, 10), TextAlignment::LEFT, false );
-}
-
-void BITSynth::resize ( ofRectangle posAndSize )
-{
-    this->posAndSize = posAndSize;
-    float heightOffset = 48.0;
-    
-    
-    rv.setPosAndSize(ofRectangle(posAndSize.x, posAndSize.y + heightOffset, posAndSize.width, posAndSize.height-heightOffset));
-}
-
-void BITSynth::stop( void )
-{
-    // Stop all asynchronous threads
-    stopThread();
-    rapidMixThread.stopThread();
-    rapidBitalino.stop();
-}
-
-void BITSynth::audioOut( float *output, int bufferSize, int nChannels )
-{ // Audio thread sync callback
-    for (uint32_t i = 0; i < bufferSize; ++i)
+namespace BIT {
+    // Simple fm synth
+    Synth::Synth ( void )
     {
-        if (controlDataBuffer.items_available_for_read())
-            controlDataBuffer.pop(&audioControlData, 1);
-        
-        SVF.setCutoff(dFilt1.lopass(110 + fmin(fabs(audioControlData[BIT::CUTOFF]), 0.95) * 5000, 0.001));
-        SVF.setResonance(0.1 + fmin(fabs(audioControlData[BIT::RESONANCE]), 0.9));
-        
-        double modulator = VCO2.sinewave(fabs(20 + audioControlData[BIT::MODULATOR]  * 1000.0)) * 50;
-        double carrier = VCO1.sinewave(fabs(audioControlData[BIT::CARRIER] + modulator));
-        double filtered = SVF.play(carrier, 1.0, 0, 0, 0) * 0.25;
-        double delay1 = DL1.dl(filtered, dFilt2.lopass(fmin(fabs(audioControlData[BIT::SIZE_A]) * 88200, 88199), 0.01),
-                                              fabs(audioControlData[BIT::FB_A]));
-        double delay2 = DL2.dl(filtered, dFilt3.lopass(fmin(fabs(audioControlData[BIT::SIZE_B]) * 88200, 88199), 0.01),
-                                              fabs(audioControlData[BIT::FB_B]));
-        
-        output[i * nChannels] = filtered * 0.75 + delay1 * 0.125 + delay2 * 0.0125;
-        output[i * nChannels + 1] = filtered * 0.75 + delay1 * 0.0125 + delay2 * 0.125;
+        // Set up the ringbuffer for controldata which is pushed in to the audio thread
+        controlDataBuffer.setup( 100 ); // Leave room for 10 control data to sync over to audio thread
     }
-}
-
-void BITSynth::mainThreadCallback( void )
-{ // Process thread sync callback
-    // Get input data (BITalino):
-    std::vector<double> inputData = rapidBitalino.update(); // Update method uses ringbuffer and is threadsafe
-    //maxValueEMG = max(inputData[0], maxValueEMG);
-    printf("input = %f\n", inputData[0]);
-    State curState = currentState.load();
-    bool newState = (curState != previousState);
     
-    // TODO this can be cleaned up.. could put the states in classes/structs
-    if (newState)
-    {
-        dataPlayTimer.reset();
-        longSelectionTimer.reset();
-        switch (curState)
-        { // Run inits for states
-            case PERFORMING:
-                loop.clear();
-                break;
-            case PLAYING:
-                sendLoopDataToOFX();
-                loopPosition = loop.begin();
-                trainingData.trainingSet.clear();
-                break;
-            default:
-                break;
-        }
-    } else
-    switch (curState)
-    { // Run update for state
-        case PERFORMING:
+    void Synth::audioOut ( float *output, int bufferSize, int nChannels )
+    { // Audio thread sync callback
+        for ( uint32_t i = 0; i < bufferSize; ++i )
         {
-            if (dataPlayTimer.getTimeElapsed() > controlRate && initialTrainingDone)
-            {
-                transport.store(inputData[0]/maxValueEMG);
-                SynthControlData ctrlData(rapidMixThread.model->run(inputData));
-                controlDataBuffer.push(&ctrlData, 1);
-                currentControlData = ctrlData;
-                if (recording.load())
-                {
-                    loop.push_back(ctrlData);
-                }
-                dataPlayTimer.reset();
-            }
-            break;
-        }
-        case PLAYING:
-        {   // Set loopPosition to begin in state change?
+            if ( controlDataBuffer.items_available_for_read(  ) )
+                controlDataBuffer.pop( &audioControlData, 1 );
             
-            if (!loop.empty() && dataPlayTimer.getTimeElapsed() > controlRate)
-            {
-                SynthControlData ctrlData = *loopPosition;
-                controlDataBuffer.push(&ctrlData, 1);
-                currentControlData = ctrlData;
-                if (++loopPosition == loop.end())
-                {
-                    loopPosition = loop.begin();
-                }
-                
-                transport.store(static_cast<double>(loopPosition - loop.begin()) / loop.size());
-                
-                if (selectingData.load() && oldInputData != inputData[0])
-                {
-                    std::vector<double> outputTraining = ctrlData.getValuesAsVector();
-                    //printf("%f, %f\n", inputData[0], outputTraining[0], outputTraining[1], outputTraining[2], outputTraining[3]);
-                    trainingData.addElement(inputData, outputTraining);
-                    oldInputData = inputData[0];
-                }
-                dataPlayTimer.reset();
-            }
-            break;
-        }
-        default:
-            break;
-    }
-    
-    // TODO add usleep (fine tune for data synchronization)
-    rapidMixThread.update();
-    previousState = curState;
-}
-
-void BITSynth::generateFirstData ( void )
-{
-    uint8_t midiStart = 55;
-    uint32_t doremiSize = 2;
-    //SynthControlData data[doremiSize * BIT::majorScaleSize]; // Doremi
-    // First generate doremi ladder
-    for (uint32_t i = 0; i < doremiSize; ++i)
-    {
-        for (uint32_t step = 0; step < BIT::majorScaleSize; ++step)
-        {
-            double frequency = MTOF(midiStart + ( i * 12 ) + BIT::majorScale[step]);
-            SynthControlData ctrlData;
-            ctrlData.values[BIT::CARRIER] = frequency;
-            for (uint16_t x = 0; x < BIT::NUM_SYNTH_PARAMS; ++x)
-            {
-                if (x != static_cast<uint8_t>(BIT::CARRIER))
-                    ctrlData.values[x] = ((double)rand()/RAND_MAX);
-            }
-
-            for (uint32_t y = 0; y < samplesPerExample; ++y)
-                loop.push_back(ctrlData);
+            SVF.setCutoff( dFilt1.lopass( 110 + fmin( fabs( audioControlData[ CUTOFF ] ), 0.95 ) * 5000, 0.001 ) );
+            SVF.setResonance( 0.1 + fmin( fabs( audioControlData[ RESONANCE ] ), 0.9 ) );
             
-            //data[i * step] = ctrlData;
-        }
-    }
-}
-
-void BITSynth::generateFirstRandomData ( void )
-{ // TODO TEMPORARY
-    for (uint32_t i = 0; i < 10; ++i)
-    {
-        SynthControlData ctrlData;
-        for (uint16_t x = 0; x < BIT::NUM_SYNTH_PARAMS; ++x)
-        {
-            ctrlData.values[x] = ((double)rand()/RAND_MAX);
-        }
-        for (uint32_t y = 0; y < samplesPerExample; ++y)
-            loop.push_back(ctrlData);
-    }
-}
-
-void BITSynth::sendRunDataToOFX ( void )
-{
-    toOFXRunVis.reset();
-    for (double i=0.0; i<maxValueEMG; i+= 1)
-    {
-        std::vector<double> t(rapidBitalino.numOutputs, i);
-        SynthControlData data(rapidMixThread.model->run(t));
-        std::vector<double> d = data.getValuesAsVector();
-        for (int p = 0; p < d.size(); ++p)
-        {
-            printf("%f: %s, %f \n", i, BIT::ParamNames[p], d[p]);
+            double modulator = VCO2.sinewave( fabs( 20 + audioControlData[ MODULATOR ]  * 1000 ) ) * ( 500 * fabs( audioControlData[ AMP ] ) );
+            double carrier = VCO1.sinewave( fabs( audioControlData[ CARRIER ] + modulator ) );
+            double filtered = SVF.play( carrier, 1.0, 0, 0, 0 ) * 0.25;
+            double delay1 = DL1.dl( filtered, dFilt2.lopass( fmin( fabs( audioControlData[ SIZE_A ] ) * 88200, 88199 ), 0.01 ),
+                                   fabs( audioControlData[ FB_A ] ) );
+            double delay2 = DL2.dl( filtered, dFilt3.lopass( fmin( fabs( audioControlData[ SIZE_B ] ) * 88200, 88199 ), 0.01 ),
+                                   fabs( audioControlData[ FB_B ] ) );
+            
+            output[ i * nChannels ] = filtered * 0.75 + delay1 * 0.125 + delay2 * 0.0125;
+            output[ i * nChannels + 1 ] = filtered * 0.75 + delay1 * 0.0125 + delay2 * 0.125;
         }
-        toOFXRunVis.push(&data, 1);
     }
-    
-    drawState.store(DRAW_RUN);
-    redraw.store(true);
-}
 
-void BITSynth::sendLoopDataToOFX ( void )
-{
-    toOFXVis.reset(); // Reset read and write pointers
-    if (toOFXVis.items_available_for_write() < loop.size())
-    {
-        // TODO: test if resizing is threadsafe in this context... or implement atomics for it
-        toOFXVis.setSize(loop.size() + 1); // This can be called here because not audio (but will block for a bit)
-    }
-    
-    toOFXVis.push(&loop[0],  loop.size());
-    drawState.store(DRAW_PLAYBACK);
-    redraw.store(true);
 }
diff --git a/examples/ofx/Bitalino_rapidmix/src/BITSynth.hpp b/examples/ofx/Bitalino_rapidmix/src/BITSynth.hpp
index d6a339edae33c1d9585f9fdd1766bb8151c4d170..fbf461339119e62bf0fae0a7241dbaece573e93d 100644
--- a/examples/ofx/Bitalino_rapidmix/src/BITSynth.hpp
+++ b/examples/ofx/Bitalino_rapidmix/src/BITSynth.hpp
@@ -2,7 +2,7 @@
 //  BITSynth.hpp
 //  Bitalino
 //
-//  Created by James on 23/11/2017.
+//  Created by James on 07/12/2017.
 //
 //
 
@@ -11,131 +11,20 @@
 
 #include <stdio.h>
 #include <vector>
-#include <atomic>
-#include <algorithm>
-#include <iterator>
-#include <mutex>
-
-// Rapid Mix and other stuff
-#include "ThreadedProcess.h"
-#include "rapidmix.h"
-#include "RapidMixThread.h"
-#include "RapidBitalino.h"
-#include "RingBuffer.hpp"
 #include "ofxMaxim.h"
-#include "ofMain.h"
-#include "Timer.h"
-#include "RapidVisualization.hpp"
-#include "SigTools.hpp"
-
-typedef rapidmix::staticRegression selectedTraining;
-
-namespace BIT
-{
-    enum SynthControl
-    {
-        CARRIER,
-        MODULATOR,
-        AMP,
-        CUTOFF,
-        RESONANCE,
-        SIZE_A,
-        SIZE_B,
-        FB_A,
-        FB_B,
-        NUM_SYNTH_PARAMS // ALWAYS AT END, REMEMBER TO ADD YOUR PARAMETER AS A STRING BELOW ASWELL
-    };
-    
-    inline const uint8_t majorScaleSize = 7;
-    
-    inline const uint8_t majorScale[majorScaleSize]
-    {
-        0, 2, 4, 5, 7, 9, 11
-    };
-
-    // C++17 only: (to use below c++17 put it in an instance of some <datatype>)
-    inline const char* ParamNames[NUM_SYNTH_PARAMS] = {
-        "1 Carrier",
-        "2 Modulator",
-        "3 Amp",
-        "4 Cutoff",
-        "5 Resonance",
-        "6 SizeA",
-        "7 SizeB",
-        "8 FeedbackA",
-        "9 FeedbackB"
-    };
-
-}
+#include "RingBuffer.hpp"
+#include "GlobalDefs.h"
 
-struct SynthControlData
-{
-    double values[BIT::NUM_SYNTH_PARAMS];
-    SynthControlData ( void )
-    {
-    }
+namespace BIT {
+// Synthesizer
     
-    SynthControlData ( std::vector<double> data )
-    {
-        setValues (data);
-    }
-    
-    double& operator[] (const BIT::SynthControl index)
-    {
-        return values[static_cast<uint32_t>(index)];
-    }
-    
-    int32_t setValues ( std::vector<double>& data )
-    { // Returns number of elements which exceeds limit of synth param size
-        std::copy(data.begin(), data.begin() + BIT::NUM_SYNTH_PARAMS, values);
-        return data.size() - BIT::NUM_SYNTH_PARAMS;
-    }
-    
-    std::vector<double> getValuesAsVector ( void )
-    {
-        return std::vector<double>(std::begin(values), std::end(values));
-    }
-};
-
-class BITSynth : public ThreadedProcess
-{
+class Synth {
 public:
-    enum State {
-        TRAINING,
-        PERFORMING,
-        PLAYING,
-        IDLE,
-        NUMBER_OF_STATES
-    };
-    const char* stateStrings[NUMBER_OF_STATES]
-    {
-        "Training",
-        "Performing",
-        "Playing",
-        "Idle"
-    };
-
-    BITSynth ( void );
-    ~BITSynth ( void );
-    
-    void setup ( ofRectangle posAndSize );
-    
-    void setState ( State state );
-    void inputData ( double input );
-
-    void update ( void );
-    void draw ( void );
-    void resize ( ofRectangle posAndSize );
-    void stop ( void );
-    
-    void audioOut(float * output, int bufferSize, int nChannels);
+    // From data thread to Audio thread
+    RingBuffer<BIT::SynthControlData> controlDataBuffer;
     
-protected:
-    void mainThreadCallback ( void );
-    void generateFirstData ( void );
-    void generateFirstRandomData ( void );
-    void sendLoopDataToOFX ( void );
-    void sendRunDataToOFX ( void );
+    Synth ( void );
+    void audioOut( float *output, int bufferSize, int nChannels );
     
 private:
     // ofMaxim audio stuff
@@ -143,74 +32,14 @@ private:
     maxiSVF SVF;
     
     maxiFractionalDelay DL1, DL2;
+    
     // For smoothing parameter changes:
     maxiFilter dFilt1, dFilt2, dFilt3;
     
-    // Rapidmix stuff
-    // TODO: turn the threaded base class that is inherited from in to a
-    // class which you can add callbacks to so these arent weirdly balanced
-    // between the two.
-    RapidMixThread<selectedTraining> rapidMixThread;
-    rapidmix::trainingData trainingData;
-    
-    //std::string trainingText = "idle";
-    bool gatheringTrainingData = false;
-    
-    // BITalino thread, TODO: Read above
-    RapidBitalino rapidBitalino;
-    
-    // Other stuff
-    uint32_t sampleRate = 44100;
-    uint32_t controlRate = 50; // 50ms
-    uint32_t samplesPerExample = 20;
-    
-    // DEBUGDEBUG
-    double oldInputData = 0.0;
-    //--
-    
-    
-    std::atomic<State> currentState;
-    State previousState; // (synced with Data thread)
-    
-    std::atomic<bool> recording;
-    std::atomic<bool> selectingData;
-    
-    // Data thread synced
-    SynthControlData currentControlData;
-    std::vector<SynthControlData> loop;
-    std::vector<SynthControlData>::iterator loopPosition;
-    bool initialTrainingDone = false;
-    
-    // Timers
-    Timer dataPlayTimer;
-    Timer longSelectionTimer;
-    
-    uint32_t longPress = 400; // 200ms
-    
     // Audio thread synced
-    SynthControlData audioControlData;
-    
-    // From Data thread to Audio thread
-    RingBuffer<SynthControlData> controlDataBuffer;
-    RingBuffer<SynthControlData> toOFXVis;
-    RingBuffer<SynthControlData> toOFXRunVis;
-    
-    // OFX stuff
-    RapidVisualization rv;
-    ofRectangle posAndSize;
-    enum drawType {
-        DRAW_IDLE,
-        DRAW_RUN,
-        DRAW_PLAYBACK
-    };
-    
-    double maxValueEMG = 600.0;
-    
-    // Data to OFX threadsafe
-    std::atomic<bool> redraw;
-    std::atomic<drawType> drawState;
-    std::atomic<double> transport;
-    
+    BIT::SynthControlData audioControlData;
 };
 
+}
+
 #endif /* BITSynth_hpp */
diff --git a/examples/ofx/Bitalino_rapidmix/src/BitalinoThread.h b/examples/ofx/Bitalino_rapidmix/src/BitalinoThread.h
index c0142495f964951f8abc07c0b967902ed5e26463..4d6c3dc155dccf04b9e1e419e6403203da2f6247 100644
--- a/examples/ofx/Bitalino_rapidmix/src/BitalinoThread.h
+++ b/examples/ofx/Bitalino_rapidmix/src/BitalinoThread.h
@@ -16,14 +16,15 @@
 
 class BitalinoThread : public ThreadedProcess {
 public:
-    RingBuffer<BITalino::Frame> data; // The data gathered in the main thread, safely accessable from outside
+    RingBuffer< BITalino::Frame > data; // The data gathered in the main thread, safely accessable from outside
     
-    BitalinoThread ( void ) : ThreadedProcess ()
+    BitalinoThread ( void ) : ThreadedProcess (  )
     {
-        connected.store(false);
-        recording.store(false);
-        tries.store(0);
-        deviceName = "/dev/cu.BITalino-DevB"; // Debug init (Mac OS virt. serial over bt)
+        connected.store( false );
+        recording.store( false );
+        tries.store( 0 );
+        // NOTE THAT DEVICE NAME CAN BE SET IN SETUP
+        this->deviceName = "/dev/cu.BITalino-DevB"; // Debug init ( Mac OS virt. serial over bt )
     }
     
     ~BitalinoThread ( void )
@@ -32,99 +33,99 @@ public:
     
     void setup ( std::string deviceName, uint64_t bufferSize,
                 uint16_t sampleRate, std::vector<int32_t> channels,
-                uint16_t frameCount=100  )
+                uint16_t frameCount=100 )
     {
         this->deviceName = deviceName;
         this->sampleRate = sampleRate;
         this->channels = channels;
-        frameBuffer.resize(frameCount);
-        pollTestBuffer.resize(1);
-        data.setup(bufferSize);
+        frameBuffer.resize( frameCount );
+        pollTestBuffer.resize( 1 );
+        data.setup( bufferSize );
+        startThread( 500 ); // sleep for 0.5 ms after each callback
     }
     
     void setRecording ( bool v )
     { // Allow data to be pushed in to the ringbuffer
-        recording.store(v);
+        recording.store( v );
     }
     
     bool isRecording ( void ) const
     {
-        return recording.load();
+        return recording.load(  );
     }
 
     bool isConnected ( void ) const
     {
-        return connected.load();
+        return connected.load(  );
     }
     
     uint32_t getConnectionTries( void ) const
     {
-        return tries.load();
+        return tries.load(  );
     }
     
 protected:
-    void mainThreadCallback ( void )
+    void mainThreadCallback ( void ) override
     {
         try {
-            switch (threadState)
+            switch ( threadState )
             {
                 case SEARCHING_FOR_DEVICE:
                     ++currentTries;
-                    tries.store(currentTries);
-                    if (!dev)
-                        dev = new BITalino(deviceName.c_str());
-                    dev->start(sampleRate, channels);
+                    tries.store( currentTries );
+                    if ( !dev )
+                        dev = new BITalino( deviceName.c_str(  ) );
+                    dev->start( sampleRate, channels );
                     threadState = IDLE_BUT_CONNECTED;
-                    connected.store(true);
+                    connected.store( true );
                     currentTries = 0;
                     break;
                 case IDLE_BUT_CONNECTED:
-                    if (recording.load())
+                    if ( recording.load(  ) )
                     {
                         threadState = RECORDING_DATA;
                     } else {
-                        dev->read(pollTestBuffer); // Poll small data to check if alive
-                        usleep(100000); // Wait 100 ms
+                        dev->read( pollTestBuffer ); // Poll small data to check if alive
+                        usleep( 100000 ); // Wait 100 ms
                     }
                     break;
                 case RECORDING_DATA:
-                    if (!recording.load())
+                    if ( !recording.load(  ) )
                     {
                         threadState = IDLE_BUT_CONNECTED;
                     } else {
-                        dev->read(frameBuffer);
-                        if (data.items_available_for_write() >= frameBuffer.size())
-                            data.push(&frameBuffer[0], frameBuffer.size());
+                        dev->read( frameBuffer );
+                        if ( data.items_available_for_write(  ) >= frameBuffer.size(  ) )
+                            data.push( &frameBuffer[ 0 ], frameBuffer.size(  ) );
                         // Else skipped frame... notify?
                     }
                     break;
                 default:
                     break;
             }
-            usleep(100);
-        } catch (BITalino::Exception &e) {
-            // printf("BITalino exception: %s\n", e.getDescription());
+        } catch ( BITalino::Exception &e ) {
+            // printf( "BITalino exception: %s\n", e.getDescription(  ) );
             // TODO: check which exact exception is communication lost etc.
             threadState = SEARCHING_FOR_DEVICE;
-            connected.store(false);
-            if (dev)
+            connected.store( false );
+            if ( dev )
             {
                 delete dev;
                 dev = nullptr;
             }
-            usleep(500000); // 500ms Timeout before trying to reconnect
+            usleep( 500000 ); // 500ms Timeout before trying to reconnect again
         }
     }
     
-    std::atomic<bool> connected;
-    std::atomic<bool> recording;
+    std::atomic< bool > connected;
+    std::atomic< bool > recording;
     std::string deviceName;
     
     BITalino* dev = nullptr;
     uint16_t sampleRate = 1000;
-    std::vector<int32_t> channels;
+    std::vector< int32_t > channels;
     
-    std::atomic<uint32_t> tries;
+    std::atomic< uint32_t > tries;
     uint32_t currentTries = 0;
     
 private:
diff --git a/examples/ofx/Bitalino_rapidmix/src/GlobalDefs.h b/examples/ofx/Bitalino_rapidmix/src/GlobalDefs.h
new file mode 100644
index 0000000000000000000000000000000000000000..268d5896dd264abf835a5af88be7c253dc322d04
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/GlobalDefs.h
@@ -0,0 +1,102 @@
+//
+//  GlobalDefs.h
+//  Bitalino
+//
+//  Created by James on 08/12/2017.
+//
+//
+
+#ifndef GlobalDefs_h
+#define GlobalDefs_h
+
+namespace BIT
+{
+    // Synth parameters
+    // Internal states
+    struct RecordingSelection {
+        double position;
+    };
+    enum State {
+        TRAINING,
+        PERFORMING,
+        RECORDING,
+        PLAYING,
+        IDLE,
+        NUMBER_OF_STATES
+    };
+    static const char* stateStrings[NUMBER_OF_STATES]
+    {
+        "Training",
+        "Performing",
+        "Recording",
+        "Playing",
+        "Idle"
+    };
+    //
+    
+    enum SynthControl
+    {
+        CARRIER,
+        MODULATOR,
+        AMP,
+        CUTOFF,
+        RESONANCE,
+        SIZE_A,
+        SIZE_B,
+        FB_A,
+        FB_B,
+        NUM_SYNTH_PARAMS
+    };
+    static const char* ParamNames[NUM_SYNTH_PARAMS] =
+    {
+        "1 Carrier",
+        "2 Modulator",
+        "3 Amp",
+        "4 Cutoff",
+        "5 Resonance",
+        "6 SizeA",
+        "7 SizeB",
+        "8 FeedbackA",
+        "9 FeedbackB"
+    };
+    
+    // Major Scale
+    static const uint8_t majorScaleSize = 7;
+    static const uint8_t majorScale[majorScaleSize]
+    {
+        0, 2, 4, 5, 7, 9, 11
+    };
+
+    
+    // Synth ctrldata struct
+    struct SynthControlData
+    {
+        double values[BIT::NUM_SYNTH_PARAMS];
+        SynthControlData ( void )
+        {
+        }
+        
+        SynthControlData ( std::vector<double> data )
+        {
+            setValues (data);
+        }
+        
+        double& operator[] (const BIT::SynthControl index)
+        {
+            return values[static_cast<uint32_t>(index)];
+        }
+        
+        int32_t setValues ( std::vector<double>& data )
+        { // Returns number of elements which exceeds limit of synth param size
+            std::copy(data.begin(), data.begin() + BIT::NUM_SYNTH_PARAMS, values);
+            return data.size() - BIT::NUM_SYNTH_PARAMS;
+        }
+        
+        std::vector<double> getValuesAsVector ( void )
+        {
+            return std::vector<double>(std::begin(values), std::end(values));
+        }
+    };
+}
+
+#endif /* GlobalDefs_h */
diff --git a/examples/ofx/Bitalino_rapidmix/src/LinkedBuffer.hpp b/examples/ofx/Bitalino_rapidmix/src/LinkedBuffer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..da1a927ee8315e574c5f1a4d137850589eff62cc
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/LinkedBuffer.hpp
@@ -0,0 +1,473 @@
+//
+//  LinkedBuffer.hpp
+//  Lock-free (except when linking atm) buffer which propagates its changes to linked buffers
+//  All linked buffers can be in different threads (read: should be)
+//  Requires an update function to be called in the thread which it resides in
+//  Concurrent sets must be ordered to have synchronized operations, accumulation can be nonsync
+//
+//  Created by James on 04/01/2018.
+//  Copyright 漏 2017 James Frink. All rights reserved.
+//
+
+/*
+ TODOS:
+ - Cache line optimization!!!
+ - Write own underlying allocator so ( AUTO ) resizing can be lock-free
+ - !!!!! Add iterators ( But not the c++17 deprecated one )
+ - ACCUMULATOR!! ( This and certain operations can be concurrent without passing a + b, just + and b)
+ - Make linking lock-free
+ - Check for feedback loops when linking and throw error / return false if thats the case
+ - !! Add more instructions, such as:
+    -  Curves?
+    - !Summing
+    - !Checksum sharing
+    - Function?
+    - Make something useful of double operator setter? < Test new implementation
+    - Resizing!
+    - Allow different sized buffers with relative - interpolated - sets?
+ 
+  allow all integer and float types in subscript operator
+ */
+
+// This is mostly just an experiment
+
+#ifndef LinkedBuffer_hpp
+#define LinkedBuffer_hpp
+
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+#include "Spinlock.hpp"
+#include "RingBufferAny.hpp"
+
+template < class T >
+class LinkedBuffer {
+public:
+    
+    template < class subT >
+    struct Subscript {
+        subT index;
+        LinkedBuffer< T >* parent;
+        T operator= ( const T& val )
+        {
+            parent->set( index, val );
+            return val;
+        }
+        operator T ( void ) const
+        {
+            return parent->get( index );
+        }
+    };
+    
+    const T& get ( size_t index ) const;
+    const T& get ( double index ) const;
+    
+    Subscript< size_t > operator[  ] ( const int index ); // Set single value
+    Subscript< double > operator[  ] ( const double index );  // Set interpolated
+    void set ( size_t index, T value );
+    void set ( double index, T value ); // For interpolated setting
+    
+    //void accumulate ( size_t index, T value );
+    void assign ( size_t startIndex, T* values, size_t numItems );
+    void setRangeToConstant ( size_t startIndex, size_t stopIndex, T value );
+    void setLine ( double startIndex, T startValue, double stopIndex, T stopValue );
+    
+    void setup ( size_t bufferSize ); // Sets up buffer size and queue sizes
+    void resize ( size_t bufferSize ); // TODO: propegate resize message?
+    void resizeBounded ( size_t bufferSize ); // Resize without trying to alloc
+    
+    size_t size ( void ) const;
+    
+    // TODO: Check for possible feedback loops
+    bool linkTo ( LinkedBuffer* const other ); // Returns true on link (false on == this or if null)
+    bool unLinkFrom ( LinkedBuffer* const other ); // Returns true on unlink, false if doesn't exist
+    
+    bool update ( void );
+    
+    uint32_t maxDataToParsePerUpdate = 4096; // Set this to a value that doesn't block your thread for forever
+    
+    size_t trueSize;
+    
+private:
+    template < class TT >
+    void propagate ( const LinkedBuffer* from, TT* const data, size_t numItems );
+    
+    RingBufferAny comQueue; // Lock-free linked buffer communications queue
+    
+    std::vector< LinkedBuffer< T >* > links;
+    Spinlock editLinks;
+    
+    std::vector< T > localMemory;
+    size_t memorySize;
+    
+    enum MessageTypes {
+        BOUNDED_MEMORY_RESIZE,
+        SINGLE_INDEX,
+        SET_RANGE_TO_CONSTANT,
+        SET_LINE,
+        INDEX_SPECIFIER_ACCUM, // TODO
+        DATA,
+        NONE
+    };
+    
+    // Command struct headers
+    struct ControlMessage {
+        const LinkedBuffer* lastSource; // For propagation ( don't send back to source )
+        MessageTypes type = NONE;
+        
+        union message {
+            struct BoundedResizeHeader {
+                size_t size;
+            } boundedResizeHeader;
+            
+            struct SingleIndexHeader {
+                size_t index;
+            } singleIndexHeader;
+            
+            struct SetRangeToConstantHeader {
+                size_t startIndex;
+                size_t stopIndex;
+                T value;
+            } setRangeToConstantHeader;
+            
+            struct SetLineHeader {
+                double startIndex;
+                T startValue;
+                double distance;
+                T deltaIncrement;
+            } setLineHeader;
+        } containedMessage;
+    };
+    // Add instructions such as resize buffer etc
+    
+    // TODO: Union or something like it to create better header instruction storage
+    ControlMessage lastIndexSpecifier;
+    
+    static const size_t tSize = sizeof ( T );
+};
+
+template < class T >
+const T& LinkedBuffer< T >::get ( const size_t index ) const
+{
+    return localMemory[ index ];
+}
+template < class T >
+const T& LinkedBuffer< T >::get ( const double index ) const
+{
+    size_t truncPos = index; // Truncate
+    double fractAmt = index - truncPos;
+    return localMemory[ truncPos ] * ( 1.0 - fractAmt ) + localMemory[ ++truncPos ] * fractAmt;
+}
+
+template < class T >
+typename LinkedBuffer< T >::template Subscript< size_t > LinkedBuffer< T >::operator[  ] ( const int index )
+{ // Single value setting through subscript operator
+    return Subscript< size_t > { static_cast< size_t >( index ), this };
+}
+template < class T >
+typename LinkedBuffer< T >::template Subscript< double > LinkedBuffer< T >::operator[  ] ( const double index )
+{ // Interpolated setting through subscript operator
+    return Subscript< double > { index , this };
+}
+
+template < class T >
+void LinkedBuffer< T >::set ( size_t index, T value )
+{
+    // Single value
+    ControlMessage hm;
+    hm.lastSource = this;
+    hm.type = SINGLE_INDEX;
+    hm.containedMessage.singleIndexHeader.index = index;
+    if ( !comQueue.push( &hm, 1 ) )
+        throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+    // Propagate the value on next update
+    if ( !comQueue.push( &value, 1 ) )
+        throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+}
+template < class T >
+void LinkedBuffer< T >::set ( double index, T value )
+{ // Linear interpolated set
+    T values[2]; // Linear interpolated values starting at index x
+    size_t truncPos = index; // Truncate
+    
+    if ( truncPos >= 0 && truncPos < memorySize )
+    { // Only set value if within bounds ( unsigned )
+        double fractAmt = index - truncPos;
+        size_t secondPos = truncPos + 1;
+        bool fits = ( secondPos < memorySize );
+        if ( fits )
+        {
+            double iFractAmt = ( 1.0 - fractAmt );
+            values[ 0 ] = ( localMemory[ truncPos ] * fractAmt ) + ( value * iFractAmt );
+            values[ 1 ] =  ( localMemory[ secondPos ] * iFractAmt ) + ( value * fractAmt );
+        } else {
+            values[0] = value;
+        }
+            
+        ControlMessage hm;
+        hm.lastSource = this;
+        hm.type = SINGLE_INDEX;
+        hm.containedMessage.singleIndexHeader.index = truncPos;
+        // Propagate the header on next update
+        if ( !comQueue.push( &hm, 1 ) )
+            throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+        // Propagate the value(s) on next update
+        if ( !comQueue.push( values, ( fits ) ? 2 : 1 ) )
+            throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+    }
+}
+
+template < class T >
+void LinkedBuffer< T >::assign ( size_t startIndex, T* values, size_t numItems )
+{
+    ControlMessage hm;
+    hm.lastSource = this;
+    hm.type = SINGLE_INDEX;
+    hm.containedMessage.singleIndexHeader.index = index;
+    // Propagate the header on next update
+    if ( !comQueue.push( &hm, 1 ) )
+        throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+    // Propagate the value(s) on next update
+    if ( !comQueue.push( &values, numItems ) )
+        throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+}
+
+template < class T >
+void LinkedBuffer< T >::setRangeToConstant( size_t startIndex, size_t stopIndex, T value )
+{
+    ControlMessage hm;
+    hm.lastSource = this;
+    hm.type = SET_RANGE_TO_CONSTANT;
+    hm.containedMessage.setRangeToConstantHeader.startIndex = startIndex;
+    hm.containedMessage.setRangeToConstantHeader.stopIndex = stopIndex;
+    hm.containedMessage.setRangeToConstantHeader.value = value;
+    // Propagate header
+    if ( !comQueue.push( &hm, 1 ) )
+        throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+}
+
+template < class T >
+void LinkedBuffer< T >::setLine ( double startIndex, T startValue, double stopIndex, T stopValue )
+{
+    double distance = stopIndex - startIndex;
+    if ( distance < 0 )
+    {
+        distance = std::abs( distance );
+        std::swap( startValue, stopValue );
+        std::swap( startIndex, stopIndex );
+    }
+    if ( distance > 0 )
+    { // Disallow div by zero
+        ControlMessage hm;
+        hm.lastSource = this;
+        hm.type = SET_LINE;
+        hm.containedMessage.setLineHeader.startIndex = startIndex;
+        hm.containedMessage.setLineHeader.startValue = startValue;
+        hm.containedMessage.setLineHeader.distance = distance;
+        hm.containedMessage.setLineHeader.deltaIncrement = ( stopValue - startValue ) / distance;
+        // Propagate the header on next update
+        if ( !comQueue.push( &hm, 1 ) )
+            throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+    }
+}
+
+template < class T >
+void LinkedBuffer< T >::setup ( size_t bufferSize )
+{
+    resize( bufferSize );
+}
+
+template < class T >
+void LinkedBuffer< T >::resize ( size_t bufferSize )
+{
+    localMemory.resize( bufferSize );
+    memorySize = bufferSize;
+    trueSize = memorySize;
+    comQueue.resize( ( bufferSize * tSize ) * 4 ); // This is the memory overhead
+}
+
+template < class T >
+void LinkedBuffer< T >::resizeBounded ( size_t bufferSize )
+{ // Just sets memory size ( unless > trueSize )
+    ControlMessage hm;
+    hm.lastSource = this;
+    hm.type = BOUNDED_MEMORY_RESIZE;
+    hm.containedMessage.boundedResizeHeader.size = bufferSize;
+    // Propagate the header on next update
+    if ( !comQueue.push( &hm, 1 ) )
+        throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+}
+
+template < class T >
+size_t LinkedBuffer< T >::size ( void ) const
+{
+    return memorySize;
+}
+
+template < class T >
+bool LinkedBuffer< T >::linkTo ( LinkedBuffer< T >* const other )
+{
+    if ( other == this || other == nullptr )
+        return false;
+    
+    // TODO: Check here for feedback loop
+    
+    // TODO: Should effort be made to make this lock-free?
+    // Reasoning: live linking, not only in setup?
+    editLinks.lock(  );
+    links.push_back( other );
+    editLinks.unlock(  );
+    
+    return true;
+}
+
+template < class T >
+bool LinkedBuffer< T >::unLinkFrom ( LinkedBuffer< T >* const other )
+{
+    if ( other == this || other == nullptr )
+        return false;
+    
+    bool success = false;
+    
+    // TODO: Should effort be made to make this lock-free?
+    // Reasoning: live linking, not only in setup?
+    editLinks.lock(  );
+    
+    auto it = std::find( links.begin(  ), links.end(  ), other );
+    if ( it != links.end(  ) )
+    {
+        links.erase( it );
+        success = true;
+    }
+    
+    editLinks.unlock(  );
+    return success;
+}
+
+template < class T >
+bool LinkedBuffer< T >::update ( void )
+{
+    uint32_t parsedData = 0;
+    bool anyNewData = false;
+    
+    RingBufferAny::VariableHeader headerInfo;
+    while ( comQueue.anyAvailableForPop( headerInfo ) && ( ++parsedData < maxDataToParsePerUpdate ) )
+    {
+        if ( headerInfo.type_index == typeid( ControlMessage ) ) {
+            
+            comQueue.pop( &lastIndexSpecifier, 1 );
+            
+            switch ( lastIndexSpecifier.type )
+            {
+                case SET_RANGE_TO_CONSTANT:
+                {
+                    auto m = lastIndexSpecifier.containedMessage.setRangeToConstantHeader;
+                    if ( m.stopIndex <= memorySize )
+                        std::fill( localMemory.begin(  ) + m.startIndex,
+                                   localMemory.begin(  ) + m.stopIndex,
+                                    m.value );
+                    
+                    anyNewData = true;
+                    break;
+                }
+                case SET_LINE:
+                {
+                    auto m = lastIndexSpecifier.containedMessage.setLineHeader;
+                    double currentIndex = m.startIndex;
+                    if ( m.startIndex >= 0 && m.startIndex < memorySize )
+                    {
+                        T startValue = m.startValue;
+                        T deltaIncrement = m.deltaIncrement;
+                        for ( size_t i = 0; i < m.distance; ++i )
+                        {
+                            size_t truncPos = currentIndex; // Truncate
+                            double fractAmt = currentIndex - truncPos;
+                            size_t secondPos = truncPos + 1;
+                            T value = startValue + deltaIncrement * i;
+                            
+                            if ( secondPos < memorySize )
+                            {
+                                double iFractAmt = ( 1.0 - fractAmt );
+                                localMemory[ truncPos ] = ( localMemory[ truncPos ] * fractAmt ) + ( value * iFractAmt );
+                                localMemory[ secondPos ] =  ( localMemory[ secondPos ] * iFractAmt ) + ( value * fractAmt );
+                            } else {
+                                localMemory[ truncPos ] = value;
+                            }
+                            currentIndex += 1;
+                        }
+                        
+                        anyNewData = true;
+                    }
+                    break;
+                }
+                case BOUNDED_MEMORY_RESIZE:
+                {
+                    size_t newSize = lastIndexSpecifier.containedMessage.boundedResizeHeader.size;
+                    if ( newSize <= trueSize )
+                    {
+                        memorySize = newSize;
+                    } else {
+                        // TODO: Allocator
+                        resize( newSize );
+                    }
+                    break;
+                }
+                    
+                default:
+                    break;
+            }
+            
+            // Propagate header
+            ControlMessage nextIndexSpecifier( lastIndexSpecifier );
+            nextIndexSpecifier.lastSource = this;
+            propagate( lastIndexSpecifier.lastSource, &nextIndexSpecifier, 1 );
+            
+        } else if ( headerInfo.type_index == typeid( T ) ) {
+            
+            if ( lastIndexSpecifier.type == SINGLE_INDEX )
+            {
+                auto m = lastIndexSpecifier.containedMessage.singleIndexHeader;
+                if ( m.index < memorySize )
+                {
+                    // Set the value(s) locally
+                    auto setIndex = ( localMemory.begin(  ) + m.index ).operator->();
+                    comQueue.pop( setIndex, headerInfo.valuesPassed );
+                    
+                    propagate( lastIndexSpecifier.lastSource, setIndex, headerInfo.valuesPassed );
+
+                    anyNewData = true;
+                }
+            } else {
+                std::runtime_error( "Data was not expected" );
+            }
+            
+            lastIndexSpecifier = ControlMessage(  ); // Reset
+            
+        } else {
+            throw std::runtime_error( "Uncaught data" );
+        }
+    }
+    
+    return anyNewData;
+}
+
+template < class T >
+template < class TT >
+void LinkedBuffer< T >::propagate ( const LinkedBuffer* from, TT* const data, size_t numItems )
+{
+    if ( from == nullptr )
+        throw std::runtime_error( " Propagation source is null " );
+    
+    // Propagation is spread across update methods of multiple threads
+    for ( LinkedBuffer* lb : links )
+    {
+        if ( lb != from )
+        {
+            if ( !lb->comQueue.push( data, numItems ) )
+                throw std::runtime_error( "Item(s) does not fit in queue, add auto-resizing here once == non-blocking" );
+        }
+    }
+}
+
+
+#endif /* LinkedBuffer_hpp */
diff --git a/examples/ofx/Bitalino_rapidmix/src/PokeGraph.cpp b/examples/ofx/Bitalino_rapidmix/src/PokeGraph.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b02a66f719d44fb2571a729d90698c913601db14
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/PokeGraph.cpp
@@ -0,0 +1,249 @@
+//
+//  PokeGraph.cpp
+//  Bitalino
+//
+//  Created by James on 21/12/2017.
+//
+//
+
+#include "PokeGraph.hpp"
+
+void PokeGraph::setup ( std::string label, ofColor textColor, ofColor graphColor, ofColor backgroundColor,
+                       ofRectangle posRect, bool fillGraph, bool dontDrawZero, uint32_t memorySize )
+{
+    this->label = label;
+    this->textColor = textColor;
+    this->graphColor = graphColor;
+    this->backgroundColor = backgroundColor;
+    this->posRect = posRect;
+    graphRect = posRect;
+    graphRect.scaleFromCenter( 0.99f, 0.75f );
+    
+    this->fillGraph = fillGraph;
+    this->dontDrawZero = dontDrawZero;
+    
+    memory.setup( memorySize );
+    calculateScaling(  );
+    
+    renderToMemory(  );
+}
+
+void PokeGraph::setResolution ( uint32_t memorySize )
+{
+    memory.resize( memorySize );
+    calculateScaling(  );
+    renderToMemory(  );
+}
+
+uint32_t PokeGraph::getResolution ( void ) const
+{
+    return memory.size(  );
+}
+
+void PokeGraph::pokeValue ( double position, double value )
+{
+    memory[ position * memory.size(  ) ] = value;
+    renderToMemory(  );
+}
+
+bool PokeGraph::isMouseInside ( ofVec2f mousePos)
+{
+    return graphRect.inside( mousePos );
+}
+
+void PokeGraph::mouseActive ( ofVec2f mousePos, int8_t mouseState, bool mouseStateChanged )
+{
+    switch ( mouseState ) {
+        case 0:
+            // Left button pressed
+            if ( mouseStateChanged )
+            { // Pressed
+                initialClickpos = mousePos;
+            } else {
+                // Held
+                memory.setLine( ( initialClickpos.x - graphRect.x ) * screenToMemoryScaling.x,                // startIndex
+                               maxVal - ( initialClickpos.y - graphRect.y ) * screenToMemoryScaling.y,           // startValue
+                               ( mousePos.x - graphRect.x ) * screenToMemoryScaling.x,                        // StopIndex
+                               maxVal - ( mousePos.y - graphRect.y ) * screenToMemoryScaling.y );                // StopValue
+            }
+            break;
+            
+        case 1:
+            // Fallthrough to right mouse button
+        
+        case 2:
+            // Right button pressed
+            if ( mouseStateChanged )
+            {
+                previousPosition = mousePos;
+            }
+            
+            if ( std::fabs( previousPosition.x - mousePos.x ) > memoryToScreenScaling.x )
+            { // Smooth out sudden changes
+                memory.setLine( ( previousPosition.x - graphRect.x ) * screenToMemoryScaling.x,                // startIndex
+                               maxVal - ( previousPosition.y - graphRect.y ) * screenToMemoryScaling.y,           // startValue
+                               ( mousePos.x - graphRect.x ) * screenToMemoryScaling.x,                        // StopIndex
+                               maxVal - ( mousePos.y - graphRect.y ) * screenToMemoryScaling.y );                // StopValue
+            } else {
+                memory[ ( mousePos.x - graphRect.x ) * screenToMemoryScaling.x ] =
+                                    maxVal - ( mousePos.y - graphRect.y ) * screenToMemoryScaling.y;
+            }
+            previousPosition = mousePos;
+            break;
+            
+        default:
+            // Reset
+            previousPosition = ofVec2f(  );
+            initialClickpos = ofVec2f(  );
+            // Mouse released
+            break;
+    }
+}
+
+void PokeGraph::update ( void )
+{
+    if ( memory.update(  ) )
+    {
+        for ( int i = 0; i < memory.size(  ); ++i )
+        {
+            double value = std::fabs( memory[ i ] );
+            if ( value > maxVal )
+                maxVal = value;
+        }
+        calculateScaling(  );
+        renderToMemory(  );
+        // Needs to update
+        // Redraw
+    }
+}
+
+void PokeGraph::draw ( void )
+{
+    rendered.draw( posRect.position );
+}
+
+
+void PokeGraph::resize ( ofVec2f wh )
+{
+    this->posRect.width = wh.x;
+    this->posRect.height = wh.y;
+    graphRect = posRect;
+    graphRect.scaleFromCenter( 0.99f, 0.8f );
+    calculateScaling(  );
+    renderToMemory(  );
+}
+
+void PokeGraph::setRect ( ofRectangle posRect )
+{
+    this->posRect = posRect;
+    graphRect = posRect;
+    graphRect.scaleFromCenter( 0.99f, 0.8f );
+    calculateScaling(  );
+    renderToMemory(  );
+}
+
+void PokeGraph::redraw ( void )
+{
+    calculateScaling(  );
+    renderToMemory(  );
+}
+
+void PokeGraph::calculateScaling ( void )
+{
+    memoryToScreenScaling = ofVec2f( graphRect.width / static_cast< float > ( memory.size(  ) - 1 ), graphRect.height / maxVal );
+    screenToMemoryScaling = ofVec2f( static_cast< float > ( memory.size(  ) - 1 ) / graphRect.width, maxVal / graphRect.height );
+}
+
+void PokeGraph::renderToMemory ( void )
+{
+    ofRectangle relativePosRect = ofRectangle( 2, 0, posRect.width - 2, posRect.height - 2 );
+    ofRectangle relativeGraphRect = ofRectangle( graphRect.x - posRect.x,
+                                                graphRect.y - posRect.y,
+                                                graphRect.width,
+                                                graphRect.height );
+    
+    rendered.clear(  );
+    ofFbo::Settings settings;
+    settings.width = posRect.width;
+    settings.height = posRect.height;
+    settings.useDepth = false;
+    settings.useStencil = false;
+    rendered.allocate( settings );
+    rendered.begin(  );
+    
+    ofClear( 255, 255, 255, 0 );
+    ofSetLineWidth( 2 );
+    
+    //ofBackground(255, 100, 100, 255);
+    
+    // Background
+    // Fill
+    ofFill(  );
+    ofSetColor( backgroundColor, 100 );
+    ofDrawRectRounded( relativePosRect, 5 );
+    
+    // Label
+    ofSetColor( textColor );
+    ofDrawBitmapString( label, relativePosRect.x + 2, relativePosRect.y + 14 );
+    
+    
+    float absWidth = relativeGraphRect.width ;
+    // Graph
+    if ( fillGraph )
+    {
+        ofBeginShape(  );
+        // Fill
+        ofFill(  );
+        ofSetColor( graphColor, 100 );
+        ofVertex( relativeGraphRect.x, ( relativeGraphRect.y + relativeGraphRect.height ) );
+        for ( int32_t i = 0; i < memory.size(  ); ++i )
+        {
+            double value = memory[ i ];
+            if ( !dontDrawZero || ( dontDrawZero && value != 0 ) )
+                ofVertex( relativeGraphRect.x + i * memoryToScreenScaling.x,
+                         ( relativeGraphRect.y + relativeGraphRect.height ) - value * memoryToScreenScaling.y );
+            else
+            {
+                ofVertex( relativeGraphRect.x + i * memoryToScreenScaling.x,
+                         ( relativeGraphRect.y + relativeGraphRect.height ) );
+            }
+        }
+        ofVertex( relativeGraphRect.x + absWidth, ( relativeGraphRect.y + relativeGraphRect.height ) );
+        
+        ofEndShape(  );
+    }
+    ofBeginShape(  );
+    // Outline
+    ofNoFill(  );
+    ofSetColor( graphColor );
+    
+    ofVertex( relativeGraphRect.x, ( relativeGraphRect.y + relativeGraphRect.height ) );
+    for ( int32_t i = 0; i < memory.size(  ); ++i )
+    {
+        double value = std::fabs( memory[ i ] );
+        if ( !dontDrawZero || ( dontDrawZero && value != 0 ) )
+            ofVertex( relativeGraphRect.x + i * memoryToScreenScaling.x,
+                     ( relativeGraphRect.y + relativeGraphRect.height ) - value * memoryToScreenScaling.y );
+        else
+        {
+            ofEndShape(  );
+            ofBeginShape(  );
+        }
+    }
+    ofVertex( relativeGraphRect.x + absWidth, ( relativeGraphRect.y + relativeGraphRect.height ) );
+    
+    ofEndShape(  );
+    ofSetColor( backgroundColor, 175 );
+    ofSetLineWidth( 1.5f );
+    ofDrawLine( relativeGraphRect.x, relativeGraphRect.y + relativeGraphRect.height,
+               relativeGraphRect.x + relativeGraphRect.width, relativeGraphRect.y + relativeGraphRect.height );
+    
+    // Outline
+    ofNoFill(  );
+    ofSetColor( backgroundColor );
+    ofDrawRectRounded( relativePosRect, 5 );
+    
+    rendered.end(  );
+    
+    ofSetColor( 255, 255, 255 );
+}
diff --git a/examples/ofx/Bitalino_rapidmix/src/PokeGraph.hpp b/examples/ofx/Bitalino_rapidmix/src/PokeGraph.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ada56617403a1a6488d343caf515b4ad8c0a8cc
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/PokeGraph.hpp
@@ -0,0 +1,66 @@
+//
+//  PokeGraph.hpp
+//  Bitalino
+//
+//  Created by James on 21/12/2017.
+//
+//
+
+// A grapb which allows input and makes use of a threadsafe non-locking buffer
+
+#ifndef PokeGraph_hpp
+#define PokeGraph_hpp
+
+#include <stdio.h>
+#include "ofMain.h"
+#include "LinkedBuffer.hpp"
+
+class PokeGraph {
+public:
+    LinkedBuffer< double > memory; // Threadsafe non-(b)locking, linkable buffer
+    
+    void setup ( std::string label, ofColor textColor, ofColor graphColor, ofColor backgroundColor, ofRectangle posRect, bool fillGraph, bool dontDrawZero, uint32_t memorySize );
+    
+    void setResolution ( uint32_t memorySize );
+    uint32_t getResolution ( void ) const;
+    
+    void pokeValue ( double position, double value );
+    
+    bool isMouseInside ( ofVec2f mousePos );
+    void mouseActive ( ofVec2f mousePos, int8_t mouseState, bool mouseStateChanged );
+    
+    void update ( void );
+    void draw ( void );
+    
+    void resize ( ofVec2f wh );
+    void setRect ( ofRectangle posRect );
+    
+    bool fillGraph = false;
+    bool dontDrawZero = false;
+    ofColor textColor, graphColor, backgroundColor;
+    
+    void redraw ( void );
+    
+protected:
+    void calculateScaling ( void );
+    void renderToMemory ( void );
+    
+private:
+    ofFbo rendered;
+    
+    ofVec2f memoryToScreenScaling;
+    ofVec2f screenToMemoryScaling;
+    
+    ofVec2f initialClickpos;
+    ofVec2f previousPosition;
+    
+    ofRectangle graphRect;
+    ofRectangle posRect;
+    
+    std::string label;
+    
+    double maxVal = 1.0;
+    
+};
+
+#endif /* PokeGraph_hpp */
diff --git a/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.cpp b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.cpp
index e77ca250e02fe0e188ecb5793b413046b4b14673..4b1a72b36496591a7cf80b94445f84e4d734572f 100644
--- a/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.cpp
+++ b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.cpp
@@ -16,104 +16,147 @@ RapidBitalino::~RapidBitalino ( void )
 {
 }
 
-void RapidBitalino::clearTrainingData ( void )
+void RapidBitalino::setup ( std::string nameOfBitalino, uint32_t sampleEveryN )
 {
-    // Clear the training set
-    (*currentPhrase).elements.clear();
-    printf("Cleared training data\n");
-}
-
-void RapidBitalino::recordTrainingData( uint32_t samplesToCollect, double output )
-{
-    this->samplesToCollect = samplesToCollect;
-    gatheringTrainingData = true;
-    bitalinoThread.data.reset(); // Reset read/write pointers
-    currentTrainingOutput = { output };
-    printf("Recoriding training input for output: %f\n", output);
-}
-
-void RapidBitalino::setup ( void )
-{
-    // Get a reference to a new phrase which stores our trainingData
-    currentPhrase = trainingData.createNewPhrase("BITalino");
-    // Set threaded train callback: (not sync)
-    rapidMixThread.threadedTrainCallback = [&] (selectedTraining* t )
-    {
-        if (trainingData.trainingSet.size() > 0)
-            t->train(trainingData);
-    };
-    // Set callback for when model is done training (sync)
-    rapidMixThread.doneTrainingCallback = [&] ( void )
-    {
-        trainingText = "New Model Trained";
-        printf("New Model Trained\n");
-    };
+    setDownsample( downsample );
     
     // Set up the bitalino
-    bitalinoThread.setup("/dev/cu.BITalino-DevB", 2000,
+    bitalinoThread.setup( nameOfBitalino, 2000,
              1000, {0, 1, 2, 3, 4, 5},
-             100);
-    // Start the bitalino's thread (and allow it to start searching for the device)
-    bitalinoThread.startThread();
+             100 );
+    // Start the bitalino's thread ( and allow it to start searching for the device )
     // Start receiving data as soon as it's connected
-    bitalinoThread.setRecording(true);
+    bitalinoThread.setRecording( true );
     // Initialize with 0, 0
-    bitalinoProcessedOutput = { 0.0, 0.0 };
-    // Init FFT
-    fft.setup(128, 32, 32);
+    bitalinoProcessedOutput = std::vector< double >( NUM_INPUTS_FOR_TRAINING, 0.0 );
+    // Setup OSC
+    sender.setup( HOST, PORT );
 }
 
-bool RapidBitalino::processBitalinoOutput(BITalino::Frame& frame)
+void RapidBitalino::setDownsample ( uint32_t downsample )
 {
-    std::vector<double> output;
-    double newVal = static_cast<float>(frame.analog[0]);
-    
-    discreteVal -= discreteVal / N;
-    discreteVal += newVal / N;
-    discreteValCalibrated = newVal - discreteVal;
+    this->downsample.store( downsample );
+}
+
+bool RapidBitalino::processBitalinoOutput( BITalino::Frame& frame )
+{
+    std::vector< double > output;
+    discreteValCalibrated = static_cast< float >( frame.analog [ 0 ] - 512.0 );
     
     testCheapRMSdiscrete -= testCheapRMSdiscrete / M;
-    testCheapRMSdiscrete += (discreteValCalibrated*discreteValCalibrated) / M;
-    //bitalinoProcessedOutput = { sqrt(testCheapRMSdiscrete) };
+    testCheapRMSdiscrete += ( discreteValCalibrated * discreteValCalibrated ) / M;
     
-    if (fft.process(discreteValCalibrated))
+    if ( sampleValue >= downsample.load(  ) )
     {
-        bitalinoProcessedOutput = { fft.spectralCentroid(), sqrt(testCheapRMSdiscrete) };
+        double rms = sqrt( testCheapRMSdiscrete );
+        double deltaRMS = rms - previousValue;
+        double bayesianFiltered = rapidProcess.bayesFilter( discreteValCalibrated / 1000.0 );
+        buttonState = static_cast< double >( frame.digital [ 0 ] );
+        double accelZ = static_cast< double > ( frame.analog [ 4 ] );
+        double deltaAccelZ = accelZ - previousAccelZ;
+        
+        bitalinoProcessedOutput = std::vector< double >( NUM_INPUTS_FOR_TRAINING, rms ); // Hack for more hidden nodes atm.
+        
+        // UNCOMMENT TO GET DEBUG OSC DATA
+        // OSC MESSAGE ]
+        /*
+        ofxOscMessage d;
+        d.setAddress( "/BitalinoRawDigital" );
+        d.addIntArg( frame.digital [ 0 ] );
+        d.addIntArg( frame.digital [ 1 ] );
+        d.addIntArg( frame.digital [ 2 ] );
+        d.addIntArg( frame.digital [ 3 ] );
+        sender.sendMessage( d );
+        ofxOscMessage a;
+        a.setAddress( "/BitalinoRawAnalog" );
+        a.addIntArg( frame.analog [ 0 ] );
+        a.addIntArg( frame.analog [ 1 ] );
+        a.addIntArg( frame.analog [ 2 ] );
+        a.addIntArg( frame.analog [ 3 ] );
+        a.addIntArg( frame.analog [ 4 ] );
+        a.addIntArg( frame.analog [ 5 ] );
+        
+        sender.sendMessage( a );
+        
+        ofxOscMessage b;
+        b.setAddress( "/BayesianFilter" );
+        b.addDoubleArg( bayesianFiltered );
+        sender.sendMessage( b );
+        ofxOscMessage m;
+        m.setAddress( "/RMS" );
+        m.addDoubleArg( rms );
+        sender.sendMessage( m );
+        ofxOscMessage dt;
+        dt.setAddress( "/DeltaRMS" );
+        dt.addDoubleArg( deltaRMS );
+        sender.sendMessage( dt );
+        ofxOscMessage at;
+        at.setAddress( "/DeltaACCELZ" );
+        at.addDoubleArg( deltaAccelZ );
+        sender.sendMessage( at );
+        ofxOscMessage n;
+        n.setAddress( "/ProcessedRaw" );
+        n.addDoubleArg( discreteValCalibrated );
+        sender.sendMessage( n );
+         */
+        // --
+        
+        
+        sampleValue = 0;
+        previousValue = rms;
+        previousAccelZ = accelZ;
         
         return true;
     }
+    ++sampleValue;
     return false;
 }
 
-void RapidBitalino::update ( void )
-{ // TODO: move this to its own thread and create communications between ofx and this so it doesn't block ofx
-    rapidMixThread.update();
+std::vector< double > RapidBitalino::update ( void )
+{
+    std::vector< double > output = std::vector<double>( NUM_INPUTS_FOR_TRAINING, 0.0 );
+    double numItemsToAverage = 0.0;
+    bool buttonPress = previousButtonPress;
     
-    uint32_t items = bitalinoThread.data.items_available_for_read();
-    BITalino::Frame data[items];
-    bitalinoThread.data.pop(data, items);
-    //double output;
+    uint32_t items = bitalinoThread.data.items_available_for_read(  );
     
-    for (uint32_t i = 0; i < items; ++i)
+    if ( items )
     {
-        if (processBitalinoOutput(data[i]))
+        buttonPress = false;
+        BITalino::Frame data [ items ];
+        bitalinoThread.data.pop( data, items );
+        
+        for ( uint32_t i = 0; i < items; ++i )
         {
-            tOutput = rapidMixThread.model->run(bitalinoProcessedOutput)[0];
-            printf("Input = %f, %f, Output = %f\n",bitalinoProcessedOutput[0],bitalinoProcessedOutput[1], tOutput);
-            
-            if (gatheringTrainingData)
-            {
-                if (samplesToCollect > 0)
-                {
-                    (*currentPhrase).addElement(bitalinoProcessedOutput, currentTrainingOutput);
-                    --samplesToCollect;
-                } else {
-                    gatheringTrainingData = false;
-                    rapidMixThread.train(); // Start training process in its thread
-                }
+            if ( processBitalinoOutput( data [ i ] ) )
+            { // Downsample scope
+                if ( !data [ i ].digital [ 0 ] )
+                    buttonPress = true;
+                
+                assert( output.size(  ) == bitalinoProcessedOutput.size(  ) );
+                // Sum the data
+                std::transform( output.begin(  ), output.end(  ),
+                               bitalinoProcessedOutput.begin(  ), output.begin(  ), std::plus<double>(  ) );
+                ++numItemsToAverage;
             }
         }
+        // calculate the average
+        if ( numItemsToAverage > 1.0 )
+            std::transform( output.begin(  ), output.end(  ), output.begin(  ),
+                       std::bind2nd( std::divides<double>(  ), numItemsToAverage ) );
+
+    } else {
+        output = bitalinoProcessedOutput;
     }
+    
+    if ( buttonPressedCallback && buttonPress && !previousButtonPress )
+        buttonPressedCallback(  );
+    
+    else if ( buttonReleasedCallback && !buttonPress && previousButtonPress )
+        buttonReleasedCallback(  );
+    
+    previousButtonPress = buttonPress;
+    return output;
 }
 
 void RapidBitalino::draw ( void )
@@ -121,18 +164,19 @@ void RapidBitalino::draw ( void )
     // Todo, draw some trivial debug interface items
     // ie:
     /*
-     - BITalino isConnected ()
-     - BITalino isRecording () // if receiving data ?
-     - RapidMixThread isTraining ()
+     - BITalino isConnected (  )
+     - BITalino isRecording (  ) // if receiving data ?
+     - RapidMixThread isTraining (  )
      - input and output values
      */
-    ofDrawBox(ofVec2f(400,(tOutput/4)*600), 50);
+    //ofDrawBox( ofVec2f( 400,( tOutput/4 )*600 ), 50 );
+    //ofDrawSphere( 512, 384, ( tOutput/4 )*600 );
+    drawTextLabel( ( bitalinoThread.isConnected(  ) ) ? "Bitalino connected" : "Looking for BITalino... " + ofToString( bitalinoThread.getConnectionTries(  ) ) + " tries", ofVec2f( 0,0 ), ofColor( 0,0,0 ), ofColor( 255,255,255 ), ofxBitmapText::TextAlignment::LEFT, false );
 }
 
 void RapidBitalino::stop ( void )
 {
-    rapidMixThread.stopThread();
-    bitalinoThread.stopThread();
+    bitalinoThread.stopThread(  );
 }
 
 
diff --git a/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.h b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.h
index eb1d77acb778786743204a452363212300f91094..f5a31b5471203601d17aac932b41b154474ac51b 100644
--- a/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.h
+++ b/examples/ofx/Bitalino_rapidmix/src/RapidBitalino.h
@@ -9,60 +9,69 @@
 #ifndef RapidBitalino_h
 #define RapidBitalino_h
 
+#include <algorithm>
+#include <functional>
+
 #include "ofMain.h"
-#include "rapidmix.h"
-#include "RapidMixThread.h"
 #include "BitalinoThread.h"
-#include "maxiFFT.h"
+#include "rapidmix.h"
+
+// TODO ifdefs聽for osc debug
+
+#include "ofxOsc.h"
+#include "Tools.h"
 
-typedef rapidmix::staticRegression selectedTraining;
+#define HOST "localhost"
+#define PORT 8338
+
+#define NUM_INPUTS_FOR_TRAINING 1
 
 class RapidBitalino {
 public:
+    BitalinoThread bitalinoThread; // For isConnected etc
+    std::function< void ( void ) > buttonPressedCallback = nullptr;
+    std::function< void ( void ) > buttonReleasedCallback = nullptr;
+    
     RapidBitalino ( void );
     ~RapidBitalino ( void );
     
-    void clearTrainingData ( void );
-    void recordTrainingData ( uint32_t numberOfSamplesToCollect, double output );
-    void setup ( void );
-    
-    void update ( void );
+    void setup ( std::string nameOfBitalino, uint32_t sampleEveryN );
+    void setDownsample ( uint32_t downsample );
+    std::vector< double > update ( void ); // returns averages of all data that is currently waiting in buffer
     void draw ( void );
-    
     void stop ( void );
     
 private:
-    // Private member funcs
-    bool processBitalinoOutput(BITalino::Frame& frame);
-    
-    // Private variables
-    std::string trainingText = "idle";
+    // OSC
+    ofxOscSender sender;
     
-    // Rapid Mix stuff
-    rapidmix::trainingData trainingData;
-    std::vector<rapidmix::trainingData::phrase>::iterator currentPhrase;
+    // Private member funcs
+    bool processBitalinoOutput( BITalino::Frame& frame );
     
     // My own stuff
     uint32_t samplesToCollect;
-    std::vector<double> currentTrainingOutput;
-    
-    RapidMixThread<selectedTraining> rapidMixThread;
-    BitalinoThread bitalinoThread;
-    
-    bool gatheringTrainingData = false;
-    
+    std::vector< double > currentTrainingOutput;
+
     // Processing the BITalino output
-    maxiFFT fft;
     double discreteVal = 0;
     double discreteValCalibrated = 0;
     double N = 1000;
     double M = 100;
     
     double testCheapRMSdiscrete = 0;
+    double buttonState = 0;
+    double previousAccelZ = 0.0;
+    
+    std::vector< double > bitalinoProcessedOutput;
+    bool previousButtonPress = false;
     
-    double tOutput = 0.0;
+    // rapidStream for Bayesian filter
+    rapidmix::rapidStream rapidProcess;
     
-    std::vector<double> bitalinoProcessedOutput;
+    //debug
+    uint32_t sampleValue = 0;
+    std::atomic< uint32_t > downsample;
+    double previousValue = 0;
 };
 
 
diff --git a/examples/ofx/Bitalino_rapidmix/src/RapidMixThread.h b/examples/ofx/Bitalino_rapidmix/src/RapidMixThread.h
index d8efb2e42558e187f54db3521f1f6e5ca14b9135..3760beef5d1cc41ed389df4cd3e9d12bcd9df9e2 100644
--- a/examples/ofx/Bitalino_rapidmix/src/RapidMixThread.h
+++ b/examples/ofx/Bitalino_rapidmix/src/RapidMixThread.h
@@ -1,7 +1,7 @@
 //
 //  RapidMixThread/h
 //  This implementation of rapidMix trains in a different thread and has a synchronized
-//  update process with your main thread, which triggers a (sync) callback on doneTraining.
+//  update process with your main thread, which triggers a ( sync ) callback on doneTraining.
 //  Allows you to train one model and keep using it while the next one trains, the new
 //  model will be swapped in sync with the thread the update is called in once it's done.
 //  Created by James on 19/11/2017.
@@ -15,82 +15,104 @@
 #include <functional>
 #include <unistd.h> // usleep
 #include "ThreadedProcess.h"
+#include "rapidmix.h"
+
+typedef rapidmix::staticRegression selectedTraining;
 
-template <typename T>
 class RapidMixThread : public ThreadedProcess
 {
 public:
-    T* model = nullptr; // The model to be accessed
-    std::function<void ( void ) > doneTrainingCallback = nullptr; // CB on done training
-    std::function<void ( T* modelToBeTrained ) > threadedTrainCallback = nullptr; // Callback entry in train thread to pass training data and train the new model before it gets swapped in to place, note that any adjustments to the passed trainingdata or other non threadsafe elements at this point will result in undefined behavior
+    std::function< void ( void ) > doneTrainingCallback = nullptr;
+    selectedTraining* model = nullptr; // The model to be accessed from outside this thread
     
-    RapidMixThread ( void ) : ThreadedProcess ()
+    RapidMixThread ( void ) : ThreadedProcess (  )
     {
-        model = new T();
-        training.store(false);
-        doneTraining.store(false);
-        startThread(); // Start training thread
+        training.store( false );
+        doneTraining.store( false );
     }
     
     ~RapidMixThread ( void )
     {
-        stopThread();
-        if (newModel)
+        stopThread(  );
+        if ( newModel )
             delete newModel;
-        if (model)
+        if ( model )
             delete model;
+        printf ( "Stop rapidmixthread\n" );
     }
     
-    void train ( void )
+    void setup ( void )
     {
-        if (!training.load())
+        model = createModel(  );
+        startThread( 100000 ); // start training thread with sleep time of 100 ms
+    }
+    
+    bool train ( rapidmix::trainingData& data )
+    {
+        if ( !training.load(  ) )
         {
-            training.store(true);
+            this->trainingData = data;
+            training.store( true );
+            return true;
         }
+        return false;
     }
     
     bool isTraining ( void ) const
     {
-        return training.load();
+        return training.load(  );
     }
     
     void update ( void )
     { // To be called in your main loop
-        if (doneTraining.load())
+        if ( doneTraining.load(  ) )
         {
-            if (newModel)
+            if ( newModel )
             {
-                std::swap(model, newModel);
+                std::swap( model, newModel );
             } else
-                printf("New model was not created successfully...\n");
+                throw std::runtime_error( "New model was not created successfully" );
+            
+            if ( doneTrainingCallback )
+                doneTrainingCallback(  );
             
-            if (doneTrainingCallback)
-                doneTrainingCallback();
-            doneTraining.store(false);
+            //printf( "Done training\n" );
+            doneTraining.store( false );
         }
     }
     
 protected:
+    selectedTraining* createModel ( void )
+    {
+        // Doing this to prevent repetitive stuff when testing different models
+        selectedTraining* t = new selectedTraining(  );
+        t->setNumHiddenNodes( 18 );
+        return t;
+    }
+    
     void mainThreadCallback ( void )
     { // Training thread
-        if (isTraining())
+        if ( isTraining(  ) )
         {
-            if (newModel)
+            if ( newModel )
                 delete newModel;
             
-            newModel = new T();
-            if (threadedTrainCallback)
-                threadedTrainCallback(newModel);
+            newModel = createModel(  );
+            
+            //printf( "Started training in thread... \n" );
+            if ( !trainingData.trainingSet.empty(  ) && trainingData.trainingSet[0].elements.size(  ) > 1 )
+                if ( !newModel->train( trainingData ) )
+                    throw std::runtime_error( "Training failed" );;
             
-            training.store(false);
-            doneTraining.store(true);
+            training.store( false );
+            doneTraining.store( true );
         }
-        usleep(100000); // Sleep 100 ms
     }
     
-    std::atomic<bool> training;
-    std::atomic<bool> doneTraining;
-    T* newModel = nullptr;
+    std::atomic< bool > training;
+    std::atomic< bool > doneTraining;
+    selectedTraining* newModel = nullptr;
+    rapidmix::trainingData trainingData;
     
 private:
 };
diff --git a/examples/ofx/Bitalino_rapidmix/src/RingBuffer.hpp b/examples/ofx/Bitalino_rapidmix/src/RingBuffer.hpp
index 401bc7049ff06c6198b98d83b30f4f67c5659939..b97bd4f2bf92948d2353eff14e63470ee7023e96 100644
--- a/examples/ofx/Bitalino_rapidmix/src/RingBuffer.hpp
+++ b/examples/ofx/Bitalino_rapidmix/src/RingBuffer.hpp
@@ -23,6 +23,7 @@ public:
     
     unsigned long push(const T* data, unsigned long n);
     unsigned long pop(T* data, unsigned long n);
+    unsigned long getWithoutPop(T* data, unsigned long n);
     unsigned long items_available_for_write() const;
     unsigned long items_available_for_read() const;
     bool isLockFree() const;
@@ -206,12 +207,69 @@ unsigned long RingBuffer<T>::pop(T* data, unsigned long n)
     return n_to_read;
 } // pop()
 
+/*
+ * Try to read as many items as possible and return the number actually read
+ */
+template <class T>
+unsigned long RingBuffer<T>::getWithoutPop(T* data, unsigned long n)
+{
+    unsigned long space = array_size, n_to_read, memory_to_read, first_chunk, second_chunk, current_head;
+    
+    //space = items_available_for_read(); //if checking outside of thread, not necessary?
+    if(blockingPop)
+    {
+        while((space = items_available_for_read()) < n)
+        { // blocking
+            usleep(blockingNap);
+        } // while
+    } // if
+    
+    if(space == 0)
+        return 0;
+    
+    n_to_read = (n <= space) ? n : space; // limit
+    
+    current_head = head_index.load();
+    if(current_head + n_to_read <= array_size)
+    { // no wrapping necessary
+        memory_to_read = n_to_read * type_size;
+        memcpy(data, buffer + current_head, memory_to_read);
+        //head_index.store(current_head + n_to_read);
+    }
+    else { // read has to wrap
+        first_chunk = array_size - current_head;
+        memory_to_read = first_chunk * type_size;
+        memcpy(data, buffer + current_head, memory_to_read);
+        
+        second_chunk = n_to_read - first_chunk;
+        memory_to_read = second_chunk * type_size;
+        memcpy(data + first_chunk, buffer, memory_to_read);
+        //head_index.store(second_chunk);
+        
+    }
+    return n_to_read;
+} // getWithoutPop()
+
 template <class T>
 bool RingBuffer<T>::isLockFree() const
 {
     return (tail_index.is_lock_free() && head_index.is_lock_free());
 } // isLockFree()
 
+
+template <class T>
+void RingBuffer<T>::setSize(unsigned long size)
+{
+    if (buffer)
+        delete [] buffer;
+    
+    this->array_size = array_size;
+    buffer = new T [array_size](); // allocate storage
+    type_size = sizeof(T);
+    tail_index.store(0);
+    head_index.store(0);
+}
+
 template <class T>
 void RingBuffer<T>::reset()
 {
diff --git a/examples/ofx/Bitalino_rapidmix/src/RingBufferAny.hpp b/examples/ofx/Bitalino_rapidmix/src/RingBufferAny.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2738222fc93e04676dc0214c48fc2b464638df90
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/RingBufferAny.hpp
@@ -0,0 +1,157 @@
+//
+//  RingBufferAny.hpp
+//  Can be used as a non-blocking eventpoll/ringbuffer without having to write unions etc ahead of time
+//  Allowing rapid expansion of inter-thread communication with several datatypes being stored in the same queue.
+//  Created by James Frink on 16/12/2017.
+//  Copyright 漏 2017 James Frink. All rights reserved.
+//
+
+#ifndef RingBufferAny_h
+#define RingBufferAny_h
+
+#include <atomic>
+#include <memory>
+#include <typeindex>
+#include <type_traits>
+
+#include "RingBufferV.hpp"
+#include "Spinlock.hpp"
+
+// WARNING: stdlib objects that use dynamic allocation ( string, list, vector etc are not supported atm )
+// If you use your own structures, make sure to use primitive types and stack allocated arrays
+// Spinlocks in this are only to protect against wrongful use and when resizing the buffer
+// Note that resizing the buffer to a smaller one than before might cause a complete reset of the heads
+
+class RingBufferAny : protected RingBufferV< int8_t > {
+public:
+    struct VariableHeader {
+        std::type_index type_index = typeid( nullptr );
+        size_t sizeOfInput = 0;
+        size_t valuesPassed = 0;
+    };
+    
+    RingBufferAny ( void ) : RingBufferV< int8_t > (  ) {}
+    RingBufferAny ( size_t sizeOfBuffer ) : RingBufferV< int8_t > (  )
+    {
+        setup( sizeOfBuffer );
+    }
+    ~RingBufferAny ( void ) {}
+    
+    void setup ( size_t sizeOfBuffer )
+    {
+        resize( sizeOfBuffer );
+    }
+   
+    void resize ( size_t size )
+    {
+        inputSpin.lock(  );
+        outputSpin.lock(  );
+        
+        this->sizeOfBuffer.store( size );
+        this->RingBufferV< int8_t >::setSize( size );
+        
+        inputSpin.unlock(  );
+        outputSpin.unlock(  );
+    }
+    
+    size_t size ( void ) const
+    {
+        return sizeOfBuffer.load(  );
+    }
+    
+    template <class T>
+    void adjustSizeIfNeeded( size_t numElements )
+    {
+        size_t totalSize = numElements * sizeof( T );
+        if ( totalSize > sizeOfBuffer.load(  ) )
+        {
+            setup( totalSize );
+        }
+    }
+    
+    void reset ( void )
+    {
+        this->RingBufferV< int8_t >::reset(  );
+    }
+    
+    // TODO add vector/list serialization support
+    
+    bool anyAvailableForPop ( VariableHeader& outputHeader )
+    { // Return if an element is available to be popped out of the queue, as well as the header information if available
+        outputSpin.lock(  ); // Lock
+        
+        size_t avForRead = items_available_for_read(  );
+        if ( avForRead > headerSize )
+        {
+            this->RingBufferV< int8_t >::getWithoutPop( reinterpret_cast< int8_t* > ( &outputHeader ), headerSize ); // Unlock case 1
+            
+            outputSpin.unlock(  );
+            return ( avForRead >= ( headerSize + outputHeader.sizeOfInput ) );
+        }
+        
+        outputSpin.unlock(  ); // Unlock case 2
+        return false;
+    }
+    
+    template <class T>
+    bool push (T* inputData, size_t numValues)
+    { // Push specified number of values starting at pointer inputData on to the queue
+        VariableHeader vh;
+        vh.type_index = std::type_index( typeid( T ) );
+        vh.valuesPassed = numValues;
+        vh.sizeOfInput = sizeof( *inputData ) * numValues;
+        inputSpin.lock(  ); // Lock
+        
+        if ( ( headerSize + vh.sizeOfInput ) <= items_available_for_write(  ) )
+        {
+            // Write header
+            this->RingBufferV< int8_t >::push( reinterpret_cast< int8_t* > ( &vh ), headerSize );
+            // Write object(s)
+            this->RingBufferV< int8_t >::push( reinterpret_cast< int8_t* > ( inputData ), vh.sizeOfInput );
+            
+            inputSpin.unlock(  ); // Unlock case 1
+            return true;
+        }
+        
+        inputSpin.unlock(  ); // Unlock case 2
+        return false;
+    }
+    
+    template <class T>
+    void pop ( T* output, size_t outputSize )
+    { // Pop single or multiple values from queue
+        VariableHeader vh;
+        outputSpin.lock(  ); // Lock
+        
+        size_t avForRead = items_available_for_read(  );
+        
+        // Get Header
+        if ( avForRead < headerSize )
+            throw std::runtime_error( "Not enough data in buffer to pop header, use anyAvailableForPop to check this!" );
+        else
+            this->RingBufferV< int8_t >::pop( reinterpret_cast< int8_t* > ( &vh ), headerSize );
+        
+        if ( std::type_index( typeid( T ) ) != vh.type_index )
+            throw std::runtime_error( "Type matching error!");
+        if ( vh.valuesPassed > outputSize ) // Possibility: add seperate unloading (with moveable header?)
+            throw std::runtime_error( "Number of values passed on push will not fit in pop structure, use the correct return structure." );
+        
+        // Get Object(s)
+        if ( avForRead < vh.sizeOfInput )
+            throw std::runtime_error( "Not enough data in buffer to pop object(s), use anyAvailableForPop to check this!" );
+        else
+            this->RingBufferV<int8_t>::pop( reinterpret_cast< int8_t* > ( output ), vh.sizeOfInput );
+        
+        outputSpin.unlock(  ); // Unlock
+    }
+    
+protected:
+    std::atomic< size_t > sizeOfBuffer;
+    static const size_t headerSize = sizeof( VariableHeader );
+    
+private:
+    Spinlock inputSpin; // Placeholder type
+    Spinlock outputSpin;// ''
+};
+
+#endif /* RingBufferAny_h */
diff --git a/examples/ofx/Bitalino_rapidmix/src/RingBufferV.hpp b/examples/ofx/Bitalino_rapidmix/src/RingBufferV.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3060319b095e96d398ad4e3a22c1b7e6c46e30b0
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/RingBufferV.hpp
@@ -0,0 +1,261 @@
+/*
+ * RingBufferV.hpp
+ */
+
+#ifndef RingBufferV_HPP
+#define RingBufferV_HPP
+
+#include <iostream>
+#include <atomic>
+#include <string>
+#include <unistd.h>
+#include <string.h> // memcpy
+#include <cstring>
+#include <vector>
+
+// Vector implementation of RingBuffer for better resizing + allowing later implementation of own non-blocking freestore allocator without having to resort to using boost lib
+
+template <class T>
+class RingBufferV
+{
+public:
+    RingBufferV ( void );
+    RingBufferV ( size_t size );
+    ~RingBufferV ( void );
+    void setup ( size_t size );
+    
+    size_t push ( const T* data, size_t n );
+    size_t pop ( T* data, size_t n );
+    size_t getWithoutPop ( T* data, size_t n );
+    size_t items_available_for_write ( void ) const;
+    size_t items_available_for_read ( void ) const;
+    bool isLockFree ( void ) const;
+    void pushMayBlock ( bool block );
+    void popMayBlock ( bool block );
+    void setBlockingNap ( size_t blockingNap );
+    void setSize ( size_t size );
+    void reset ( void );
+    
+private:
+    size_t array_size;
+    std::vector< T > buffer;
+    static constexpr long type_size = sizeof( T ); // Not used atm
+
+    std::atomic< size_t > tail_index = { 0 }; // write pointer
+    std::atomic< size_t > head_index = { 0 }; // read pointer
+
+    bool blockingPush;
+    bool blockingPop;
+    useconds_t blockingNap = 500; // 0.5 ms
+}; // RingBufferV{}
+
+template < class T >
+RingBufferV< T >::RingBufferV ( void )
+{
+    blockingPush = false;
+    blockingPop = false;
+} // RingBufferV( void )
+
+template < class T >
+RingBufferV< T >::RingBufferV ( size_t array_size )
+{
+    blockingPush = false;
+    blockingPop = false;
+    
+    setup( array_size );
+} // RingBufferV( void )
+
+template < class T >
+RingBufferV< T >::~RingBufferV ( void )
+{
+    
+} // ~RingBufferV( void )
+
+template < class T >
+void RingBufferV< T >::setup ( size_t array_size )
+{
+    setSize( array_size ); // allocate storage
+}
+
+template < class T >
+size_t RingBufferV< T >::items_available_for_write ( void ) const
+{
+    long pointerspace = head_index.load(  ) - tail_index.load(  ); // signed
+    
+    if ( pointerspace > 0 )
+        return pointerspace; // NB: > 0 so NOT including 0
+    else
+        return pointerspace + array_size;
+} // items_available_for_write( void )
+
+template < class T >
+size_t RingBufferV< T >::items_available_for_read ( void ) const
+{
+    long pointerspace = tail_index.load(  ) - head_index.load(  ); // signed
+    
+    if ( pointerspace >= 0 )
+        return pointerspace; // NB: >= 0 so including 0
+    else
+        return pointerspace + array_size;
+} // items_available_for_read( void )
+
+template < class T >
+void RingBufferV< T >::pushMayBlock ( bool block )
+{
+    this->blockingPush = block;
+} // pushMayBlock( void )
+
+template < class T >
+void RingBufferV< T >::popMayBlock ( bool block )
+{
+    this->blockingPop = block;
+} // popMayBlock( void )
+
+template < class T >
+void RingBufferV< T >::setBlockingNap ( size_t blockingNap )
+{
+    this->blockingNap = blockingNap;
+} // setBlockingNap( void )
+
+
+/*
+ * Try to write as many items as possible and return the number actually written
+ */
+template < class T >
+size_t RingBufferV< T >::push ( const T* data, size_t n )
+{
+    size_t space = array_size, n_to_write, first_chunk, second_chunk, current_tail;
+    
+    //space = items_available_for_write();
+    if ( blockingPush )
+    {
+        while ( ( space = items_available_for_write(  ) ) < n )
+        { // blocking
+            usleep( blockingNap );
+        } // while, Any better solutions to this?
+    } // if
+    
+    n_to_write = ( n <= space ) ? n : space; // limit
+    
+    current_tail = tail_index.load(  );
+    if ( current_tail + n_to_write <= array_size )
+    { // chunk fits without wrapping
+        std::copy_n( data, n_to_write, buffer.begin(  ) + current_tail );
+        tail_index.store( current_tail + n_to_write );
+        
+    } else { // chunk has to wrap
+        first_chunk = array_size - current_tail;
+        std::copy_n( data, first_chunk, buffer.begin(  ) + current_tail );
+        second_chunk = n_to_write - first_chunk;
+        std::copy_n( data + first_chunk, second_chunk, buffer.begin(  ) );
+        tail_index.store( second_chunk );
+    }
+    
+    return n_to_write;
+} // push( const T* data, size_t n )
+
+
+/*
+ * Try to read as many items as possible and return the number actually read
+ */
+template < class T >
+size_t RingBufferV< T >::pop ( T* data, size_t n )
+{
+    size_t space = array_size, n_to_read, first_chunk, second_chunk, current_head;
+    
+    //space = items_available_for_read(); // if checking outside of thread, not necessary?
+    if ( blockingPop )
+    {
+        while ( ( space = items_available_for_read(  ) ) < n )
+        { // blocking
+            usleep( blockingNap );
+        } // while
+    } // if
+    
+    if ( space == 0 )
+        return 0;
+    
+    n_to_read = ( n <= space ) ? n : space; // limit
+    
+    current_head = head_index.load(  );
+    if ( current_head + n_to_read <= array_size )
+    { // no wrapping necessary
+        std::copy_n( buffer.begin(  ) + current_head, n_to_read, data );
+        head_index.store( current_head + n_to_read );
+        
+    } else { // read has to wrap
+        first_chunk = array_size - current_head;
+        std::copy_n( buffer.begin(  ) + current_head, first_chunk, data );
+        second_chunk = n_to_read - first_chunk;
+        std::copy_n( buffer.begin(  ), second_chunk, data + first_chunk );
+        head_index.store( second_chunk );
+
+    }
+    return n_to_read;
+} // pop( T* data, size_t n )
+
+/*
+ * Try to read as many items as possible and return the number actually read
+ */
+template < class T >
+size_t RingBufferV< T >::getWithoutPop ( T* data, size_t n )
+{
+    size_t space = array_size, n_to_read, first_chunk, second_chunk, current_head;
+    
+    //space = items_available_for_read(); //if checking outside of thread, not necessary?
+    if ( blockingPop )
+    {
+        while ( ( space = items_available_for_read(  ) ) < n )
+        { // blocking
+            usleep( blockingNap );
+        } // while
+    } // if
+    
+    if ( space == 0 )
+        return 0;
+    
+    n_to_read = ( n <= space ) ? n : space; // limit
+    
+    current_head = head_index.load(  );
+    if ( current_head + n_to_read <= array_size )
+    { // no wrapping necessary
+        std::copy_n( buffer.begin(  ) + current_head, n_to_read, data );
+        //head_index.store(current_head + n_to_read);
+        
+    } else { // read has to wrap
+        first_chunk = array_size - current_head;
+        std::copy_n( buffer.begin(  ) + current_head, first_chunk, data );
+        second_chunk = n_to_read - first_chunk;
+        std::copy_n( buffer.begin(  ), second_chunk, data + first_chunk );
+        //head_index.store(second_chunk);
+        
+    }
+    return n_to_read;
+} // getWithoutPop( T* data, size_t n )
+
+template <class T>
+bool RingBufferV<T>::isLockFree ( void ) const
+{
+    return ( tail_index.is_lock_free(  ) && head_index.is_lock_free(  ) );
+} // isLockFree( void )
+
+
+template <class T>
+void RingBufferV< T >::setSize( size_t size )
+{
+    this->array_size = size;
+    buffer.resize( array_size ); // allocate storage
+    if ( tail_index.load(  ) <= array_size || head_index.load(  ) <= array_size )
+    {
+        reset(  );
+    }
+}
+
+template <class T>
+void RingBufferV<T>::reset( void )
+{
+    tail_index.store( 0 );
+    head_index.store( 0 );
+} // isLockFree( void )
+
+#endif
diff --git a/examples/ofx/Bitalino_rapidmix/src/SigTools.cpp b/examples/ofx/Bitalino_rapidmix/src/SigTools.cpp
index bdb69a682901781481b0fb9ec40ac31d46ce56b8..53d91e1d7b81ddd54fabdc58b9f6dc39a10f825e 100644
--- a/examples/ofx/Bitalino_rapidmix/src/SigTools.cpp
+++ b/examples/ofx/Bitalino_rapidmix/src/SigTools.cpp
@@ -8,10 +8,10 @@
 
 #include "SigTools.hpp"
 
-double MTOF(unsigned char midi) {
-    return pow(2,(double)(midi-69)/12.f)*440.0f;
+double MTOF ( unsigned char midi ) {
+    return pow( 2, static_cast< double >( midi-69 ) / 12.0 ) * 440.0;
 }
 
-double FTOM(double freq) {
-    return 12.f*log2(freq/440.0f)+69;
+double FTOM ( double freq ) {
+    return 12.0 * log2( freq / 440.0 ) + 69;
 }
diff --git a/examples/ofx/Bitalino_rapidmix/src/SigTools.hpp b/examples/ofx/Bitalino_rapidmix/src/SigTools.hpp
index 7b0d148a89426013c9d30a44b128d7d24d559289..53f51da4fe8d4f34351ecebaeb70fd103ed43e19 100644
--- a/examples/ofx/Bitalino_rapidmix/src/SigTools.hpp
+++ b/examples/ofx/Bitalino_rapidmix/src/SigTools.hpp
@@ -12,7 +12,7 @@
 #include <stdio.h>
 #include <math.h>
 
-double MTOF(unsigned char midi);
-double FTOM(double freq);
+double MTOF ( unsigned char midi );
+double FTOM ( double freq );
 
 #endif /* SigTools_hpp */
diff --git a/examples/ofx/Bitalino_rapidmix/src/Spinlock.hpp b/examples/ofx/Bitalino_rapidmix/src/Spinlock.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2b783acfb9664a0d9918fdedda4d04f5bdf8d64
--- /dev/null
+++ b/examples/ofx/Bitalino_rapidmix/src/Spinlock.hpp
@@ -0,0 +1,25 @@
+//
+//  Spinlock.h
+//  beladrum
+//
+//  Created by James on 11/05/17.
+//  Copyright 漏 2017 HKU. All rights reserved.
+//
+
+#ifndef Spinlock_h
+#define Spinlock_h
+
+#include <atomic>
+
+class Spinlock {
+    std::atomic_flag locked = ATOMIC_FLAG_INIT ;
+public:
+    void lock ( void ) {
+        while (locked.test_and_set(std::memory_order_acquire)) { ; }
+    }
+    void unlock ( void ) {
+        locked.clear(std::memory_order_release);
+    }
+};
+
+#endif /* Spinlock_h */
diff --git a/examples/ofx/Bitalino_rapidmix/src/ThreadedProcess.h b/examples/ofx/Bitalino_rapidmix/src/ThreadedProcess.h
index 4f9d5949639fef2a396211d5fe57ca7ce835c5b1..348e709b1cb83e547a3ef5e6a4e9a0ee072d7be6 100644
--- a/examples/ofx/Bitalino_rapidmix/src/ThreadedProcess.h
+++ b/examples/ofx/Bitalino_rapidmix/src/ThreadedProcess.h
@@ -24,32 +24,33 @@ public:
     
     virtual ~ThreadedProcess ( void )
     {
-        stopThread();
+        stopThread(  );
     }
     
     bool isThreadRunning ( void ) const
     {
-        return running.load();
+        return running.load(  );
     }
     
-    // (re)Start main thread
-    void startThread ( void )
+    // ( re )Start main thread
+    void startThread ( uint64_t threadSleepTime = 1 )
     {
-        if (running.load())
+        this->threadSleepTime = threadSleepTime;
+        if ( running.load(  ) )
         { // Thread is already running
-            stopThread();
+            stopThread(  );
         }
         running.store( true );
-        processMainThread = std::thread(&ThreadedProcess::mainLoop, this); // Spawn thread
+        processMainThread = std::thread( &ThreadedProcess::mainLoop, this ); // Spawn thread
     }
     
     // Stop main thread
     void stopThread ( void )
     {
-        if (running.load())
+        if ( running.load(  ) )
         {
             running.store( false );
-            processMainThread.join();
+            processMainThread.join(  );
         }
     }
     
@@ -61,13 +62,15 @@ protected:
 private:
     void mainLoop ( void )
     {
-        while (running.load())
+        while ( running.load(  ) )
         {
-            mainThreadCallback();
+            mainThreadCallback(  );
+            usleep( threadSleepTime );
         }
     }
     
-    std::atomic<bool> running;
+    std::atomic< bool > running;
+    uint64_t threadSleepTime = 1;
 };
 
 
diff --git a/examples/ofx/Bitalino_rapidmix/src/Timer.h b/examples/ofx/Bitalino_rapidmix/src/Timer.h
index 4cbc3f89c7b4a33a54b8144c26fd1cad9a21b7f4..5474cd996fb0b3b9e13a49b901dea886378f6755 100644
--- a/examples/ofx/Bitalino_rapidmix/src/Timer.h
+++ b/examples/ofx/Bitalino_rapidmix/src/Timer.h
@@ -16,12 +16,12 @@ class Timer {
 public:
     uint64_t getTimeElapsed ( void )
     { // Since last call of reset
-        return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count();
+        return std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::high_resolution_clock::now() - start ).count(  );
 
     }
     void reset ( void )
     {
-        start = std::chrono::high_resolution_clock::now();
+        start = std::chrono::high_resolution_clock::now(  );
     }
 private:
     std::chrono::high_resolution_clock::time_point start;
diff --git a/examples/ofx/Bitalino_rapidmix/src/Tools.h b/examples/ofx/Bitalino_rapidmix/src/Tools.h
index 96c0fe10d0da37637f468b79f3162c9ddf5b9b97..ca3e2f22f6bd14794272c114d45d42063e82dd67 100644
--- a/examples/ofx/Bitalino_rapidmix/src/Tools.h
+++ b/examples/ofx/Bitalino_rapidmix/src/Tools.h
@@ -21,9 +21,9 @@ namespace ofxBitmapText {
 
     static inline void drawTextLabel ( std::string label, ofVec2f position, ofColor labelBackgroundColor, ofColor stringColor, TextAlignment alignment, bool drawAbove )
     {
-        uint32_t strLenPix = label.length()*8;
+        uint32_t strLenPix = label.length(  )*8;
         
-        switch (alignment) {
+        switch ( alignment ) {
             case TextAlignment::LEFT:
                 // No exception
                 break;
@@ -37,14 +37,15 @@ namespace ofxBitmapText {
                 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));
+        ofFill(  );
+        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 ) );
+        ofSetColor( 255, 255, 255, 255 );
     }
 
 }
diff --git a/examples/ofx/Bitalino_rapidmix/src/main.cpp b/examples/ofx/Bitalino_rapidmix/src/main.cpp
index e57370b26ee652c85ce0b32f19eace3b681585a4..9bd27ad807ea3eb61cb06672b8372e861d9638bc 100644
--- a/examples/ofx/Bitalino_rapidmix/src/main.cpp
+++ b/examples/ofx/Bitalino_rapidmix/src/main.cpp
@@ -1,13 +1,11 @@
-#include "ofMain.h"
 #include "ofApp.h"
+#include "ofAppGlutWindow.h"
 
 //========================================================================
 int main( ){
-	ofSetupOpenGL(1024,768,OF_WINDOW);			// <-------- setup the GL context
+    ofAppGlutWindow window;
+	ofSetupOpenGL( &window, 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());
+	ofRunApp( new ofApp(  ) );
 
 }
diff --git a/examples/ofx/Bitalino_rapidmix/src/ofApp.cpp b/examples/ofx/Bitalino_rapidmix/src/ofApp.cpp
index b156ff1d90ec33be5a3a4c84191aa5e42b782651..67087de429e2882e08883dc1203d75e7aa7d063b 100644
--- a/examples/ofx/Bitalino_rapidmix/src/ofApp.cpp
+++ b/examples/ofx/Bitalino_rapidmix/src/ofApp.cpp
@@ -1,111 +1,143 @@
 #include "ofApp.h"
 
 //--------------------------------------------------------------
-void ofApp::setup(){
-    rapidBitalino.setup();
+void ofApp::setup ( void )
+{
+    ofSetWindowTitle( "Rapid Bitalino Example" );
+    
+    sampleRate 	= 44100; /* Sampling Rate */
+    bufferSize	= 512; /* Buffer Size. you have to fill this buffer with sound using the for loop in the audioOut method */
+    
+    ofSetVerticalSync( true );
+    ofEnableAlphaBlending(  );
+    ofEnableSmoothing(  );
+    
+    ofBackground( 0, 0, 0 );
+    
+    // Enter the name of your BITalino board here
+    bitEnvironment.setup( "/dev/cu.BITalino-DevB", ofRectangle( 0, 0, 1024, 768 ) );
+    
+    ofxMaxiSettings::setup( sampleRate, 2, bufferSize );
+    
+    // sets up and starts a global ofSoundStream.
+    ofSoundStreamSetup( 2, 0, sampleRate, bufferSize, 4 );
 }
 
 //--------------------------------------------------------------
-void ofApp::update(){
-    rapidBitalino.update();
-    /*
-    static bool connection = false;
-    bool connectionStatus = BT.isConnected();
-    if (connection != connectionStatus)
-    {
-        connection = connectionStatus;
-        if (connection)
-        {
-            printf("Connected after %u attempt(s)\n", BT.getConnectionTries());
-        }
-    }
-    
-    uint32_t items = BT.data.items_available_for_read();
-    BITalino::Frame tFrame;
-    for (uint32_t i = 0; i < items; ++i)
-    {
-        BT.data.pop(&tFrame, 1);
-        printf("%d \t : %d %d %d %d ; %d %d %d %d %d %d\n",   // dump the first frame
-               tFrame.seq,
-               tFrame.digital[0], tFrame.digital[1], tFrame.digital[2], tFrame.digital[3],
-               tFrame.analog[0], tFrame.analog[1], tFrame.analog[2], tFrame.analog[3], tFrame.analog[4], tFrame.analog[5]);
-    }
-     */
+void ofApp::update ( void )
+{
+    bitEnvironment.update(  );
 }
 
 //--------------------------------------------------------------
-void ofApp::draw(){
-    rapidBitalino.draw();
+void ofApp::draw ( void )
+{
+    ofBackground( 0, 0, 0 );
+    bitEnvironment.draw(  );
 }
 
 //--------------------------------------------------------------
-void ofApp::exit(){
-    printf("stopping...\n");
-    rapidBitalino.stop();
+void ofApp::audioOut ( float *output, int bufferSize, int nChannels )
+{
+    bitEnvironment.audioOut ( output, bufferSize, nChannels );
 }
 
 //--------------------------------------------------------------
-void ofApp::keyPressed(int key){
-    static uint32_t numTrainingData = 20;
-    if (key == 'c') {
-        rapidBitalino.clearTrainingData();
-    } else if (key == '1') {
-        rapidBitalino.recordTrainingData(numTrainingData, 1.0);
-    } else if (key == '2') {
-        rapidBitalino.recordTrainingData(numTrainingData, 2.0);
-    } else if (key == '3') {
-        rapidBitalino.recordTrainingData(numTrainingData, 3.0);
-    } else if (key == '4') {
-        rapidBitalino.recordTrainingData(numTrainingData, 4.0);
-    }
+void ofApp::exit ( void )
+{
+    printf( "stopping...\n" );
+//    rapidBitalino.stop(  );
+    bitEnvironment.stop(  );
 }
 
 //--------------------------------------------------------------
-void ofApp::keyReleased(int key){
-    
+void ofApp::keyPressed ( int key )
+{
+    if ( key == '1' && !pr ) {
+        bitEnvironment.bst.buttonPressed(  );
+        printf( "1 down\n" );
+        pr = true;
+    }
 }
 
 //--------------------------------------------------------------
-void ofApp::mouseMoved(int x, int y ){
+void ofApp::keyReleased ( int key )
+{
+    if ( key == '1' ) {
+        bitEnvironment.bst.buttonReleased(  );
+        printf( "1 up\n" );
+        pr = false;
+    }
+}
 
+void ofApp::updateMouse ( int x, int y, int8_t mouseButtonState )
+{
+    // Only really one mouse function necessary for this example:
+    if ( mouseButtonState != this->mouseButtonState )
+    {
+        mouseButtonChanged = true;
+        this->mouseButtonState = mouseButtonState;
+    } else
+        mouseButtonChanged = false;
+    
+    ofVec2f mousePos( x, y );
+    if ( bitEnvironment.isMouseInside( mousePos ) )
+    {
+        bitEnvironment.mouseActive( mousePos, mouseButtonState, mouseButtonChanged );
+    }
 }
 
 //--------------------------------------------------------------
-void ofApp::mouseDragged(int x, int y, int button){
-
+void ofApp::mouseMoved ( int x, int y )
+{
+    updateMouse( x, y, mouseButtonState );
 }
 
 //--------------------------------------------------------------
-void ofApp::mousePressed(int x, int y, int button){
-
+void ofApp::mouseDragged ( int x, int y, int button )
+{
+    updateMouse( x, y, button );
 }
 
 //--------------------------------------------------------------
-void ofApp::mouseReleased(int x, int y, int button){
-
+void ofApp::mousePressed ( int x, int y, int button )
+{
+    //std::cout << "BUTTON: " <<  button << std::endl;
+    updateMouse( x, y, button );
 }
 
 //--------------------------------------------------------------
-void ofApp::mouseEntered(int x, int y){
-
+void ofApp::mouseReleased ( int x, int y, int button )
+{
+    updateMouse( x, y, -1 );
 }
 
 //--------------------------------------------------------------
-void ofApp::mouseExited(int x, int y){
-
+void ofApp::mouseEntered( int x, int y )
+{
+    updateMouse( x, y, mouseButtonState );
 }
 
 //--------------------------------------------------------------
-void ofApp::windowResized(int w, int h){
+void ofApp::mouseExited ( int x, int y )
+{
+    updateMouse( x, y, mouseButtonState );
+}
 
+//--------------------------------------------------------------
+void ofApp::windowResized ( int w, int h )
+{
+    bitEnvironment.resize( ofRectangle( 0, 0, w, h ) );
 }
 
 //--------------------------------------------------------------
-void ofApp::gotMessage(ofMessage msg){
+void ofApp::gotMessage ( ofMessage msg )
+{
 
 }
 
 //--------------------------------------------------------------
-void ofApp::dragEvent(ofDragInfo dragInfo){ 
+void ofApp::dragEvent ( ofDragInfo dragInfo )
+{
 
 }
diff --git a/examples/ofx/Bitalino_rapidmix/src/ofApp.h b/examples/ofx/Bitalino_rapidmix/src/ofApp.h
index 2cf79a8f915a0148aef8f3b74ffa81893f2830a4..f6387fd903f6f62bf90a0b42a1c8c7e3685eb879 100644
--- a/examples/ofx/Bitalino_rapidmix/src/ofApp.h
+++ b/examples/ofx/Bitalino_rapidmix/src/ofApp.h
@@ -1,29 +1,44 @@
 #pragma once
 
 #include "ofMain.h"
+#include "ofxMaxim.h"
 #include "RapidBitalino.h"
+#include "BITEnvironment.hpp"
 
 class ofApp : public ofBaseApp{
 
 public:
-    void setup();
-    void update();
-    void draw();
-    void exit();
-
-    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);
+    void setup ( void );
+    void update ( void );
+    void draw ( void );
+    void audioOut ( float * output, int bufferSize, int nChannels );
+    void exit ( void );
+    
+    void keyPressed ( int key );
+    void keyReleased ( int key );
+    
+    void updateMouse ( int x, int y, int8_t mouseButtonState );
+    
+    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:
+    int8_t mouseButtonState = -1;
+    bool mouseButtonChanged = false;
+    
+    //DEBUG
+    bool pr = false;
+    //---
     
-    RapidBitalino rapidBitalino;
+    BIT::Environment bitEnvironment;
+    int		bufferSize; 
+    int		sampleRate;
 };