diff --git a/src/signalProcessing/rapidPiPoTools/rapidPiPoHost.cpp b/src/signalProcessing/rapidPiPoTools/rapidPiPoHost.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..06211c9dea6748094789e15af10a41cb29b01bb8
--- /dev/null
+++ b/src/signalProcessing/rapidPiPoTools/rapidPiPoHost.cpp
@@ -0,0 +1,880 @@
+#include "rapidPiPoHost.h"
+
+//===================== P I P O = H O S T = U T I L S ========================//
+
+static const unsigned int maxWordLen = 256;
+
+static bool getPiPoInstanceAndAttrName(const char *attrName,
+                                       char *instanceName,
+                                       char *pipoAttrName)
+{
+  const char *dot = std::strrchr(attrName, '.');
+
+  if (dot != NULL)
+  {
+    unsigned int pipoAttrNameLen = dot - attrName;
+    std::strcpy(pipoAttrName, dot + 1);
+
+    if (pipoAttrNameLen > maxWordLen)
+    {
+      pipoAttrNameLen = maxWordLen;
+    }
+
+    std::strncpy(instanceName, attrName, pipoAttrNameLen);
+    instanceName[pipoAttrNameLen] = '\0';
+
+    return true;
+  }
+
+  return false;
+}
+
+
+static void fromPiPoStreamAttributes(PiPoStreamAttributes &src,
+                                     pipoStreamAttributes &dst)
+{
+  unsigned int numCols = src.dims[0];
+  unsigned int numLabels = src.numLabels;
+  
+  if (numLabels > PIPO_MAX_LABELS) {
+    numLabels = PIPO_MAX_LABELS;
+  }
+  
+  if (numLabels > numCols) {
+    numLabels = numCols;
+  }
+
+  dst.hasTimeTags = src.hasTimeTags;
+
+  if (src.rate <= MIN_PIPO_SAMPLERATE) {
+    dst.rate = MIN_PIPO_SAMPLERATE;
+  } else if (src.rate >= MAX_PIPO_SAMPLERATE) {
+    dst.rate = MAX_PIPO_SAMPLERATE;
+  } else {
+    dst.rate = src.rate;
+  }
+
+  dst.rate = src.rate;
+  dst.offset = src.offset;
+  dst.dims = { src.dims[0], src.dims[1] };
+
+  dst.labels = std::vector<std::string>();
+
+  for (unsigned int i = 0; i < numLabels; ++i)
+  {
+    dst.labels.push_back(std::string(src.labels[i]));
+  }
+
+  dst.hasVarSize = src.hasVarSize;
+  dst.domain = src.domain;
+  dst.maxFrames = src.maxFrames;
+}
+
+
+static void toPiPoStreamAttributes(pipoStreamAttributes &src,
+                                   PiPoStreamAttributes &dst)
+{
+  const char *labs[src.labels.size()];
+
+  for (unsigned int i = 0; i < src.labels.size(); ++i)
+  {
+    labs[i] = labels[i].c_str();
+  }
+
+  dst = PiPoStreamAttributes(
+    src.hasTimeTags,
+    src.rate,
+    src.offset,
+    { src.dims[0], src.dims[1] },
+    &labs[0],
+    src.hasVarSize,
+    src.domain;
+    src.maxFrames
+  );
+}
+
+//========================= H O S T = M E T H O D S ==========================//
+
+PiPoHost::PiPoHost() :
+inputStreamAttrs(PIPO_MAX_LABELS),
+outputStreamAttrs(PIPO_MAX_LABELS)
+{
+  PiPoCollection::init();
+  this->out = new PiPoOut(this);
+  this->graph = nullptr;
+}
+
+PiPoHost::~PiPoHost()
+{
+  if (this->graph != nullptr)
+  {
+    delete this->graph;
+  }
+
+  delete this->out;
+}
+
+bool
+PiPoHost::setPiPoGraph(std::string name)
+{
+  if (this->graph != nullptr)
+  {
+    delete this->graph;
+  }
+
+  this->graph = PiPoCollection::create(name);
+
+  if (this->graph != NULL)
+  {
+    this->graphName = name;
+    this->graph->connect((PiPo *)this->out);
+    return true;
+  }
+
+  this->graph = nullptr;
+  this->graphName = "undefined";
+  return false;
+}
+
+void
+PiPoHost::clearPiPoGraph()
+{
+  if (this->graph != nullptr)
+  {
+    delete this->graph;
+    this->graph = nullptr;
+  }
+}
+
+
+void
+PiPoHost::onNewFrameOut(double time, std::vector<PiPoValue> &frame)
+{
+  std::cout << time << std::endl;
+  std::cout << "please override this method" << std::endl;
+}
+
+std::vector<PiPoValue>
+PiPoHost::getLastFrameOut()
+{
+  return this->out->getLastFrame();
+}
+
+
+
+void
+PiPoHost::setInputStreamAttributes(pipoStreamAttributes &sa, bool propagate)
+{
+  toPiPoStreamAttributes(sa, inputStreamAttrs);
+
+  if (propagate)
+  {
+    this->propagateInputStreamAttributes();
+  }
+}
+
+pipoStreamAttributes
+PiPoHost::getOutputStreamAttributes()
+{
+  pipoStreamAttributes sa;
+  return fromPiPoStreamAttributes(this->outputStreamAttrs, sa);
+}
+
+int
+PiPoHost::frames(double time, double weight, PiPoValue *values, unsigned int size,
+                 unsigned int num)
+{
+  return this->graph->frames(time, weight, values, size, num);
+}
+
+
+
+// bool
+// setAttr(const std::string &attrName, bool value)
+// {
+
+// }
+
+// bool
+// setAttr(const std::string &attrName, int value)
+// {
+
+// }
+
+bool
+setAttr(const std::string &attrName, double value)
+{
+  PiPo::Attr *attr = this->graph->getAttr(attrName.c_str());
+  
+  if (attr != NULL) {
+    int iAttr = attr->getIndex();
+    return this->pipo->setAttr(iAttr, value);
+  }
+
+  return false;
+}
+
+bool
+setAttr(const std::string &attrName, const std::vector<double> &values)
+{
+  PiPo::Attr *attr = this->pipo->getAttr(attrName.c_str());
+
+  if (attr != NULL) {
+    int iAttr = attr->getIndex();
+    double vals[values.size()];
+    unsigned int i = 0;
+    for (auto &value : values) {
+      vals[i] = value;
+      i++;
+    }
+    return this->pipo->setAttr(iAttr, &vals[0], values.size());
+  }
+
+  return false;
+}
+
+bool
+setAttr(const std::string &attrName, const std::string &value) // for enums
+{
+  PiPo::Attr *attr = this->pipo->getAttr(attrName.c_str());
+  
+  if (attr != NULL) {
+    int iAttr = attr->getIndex();
+    PiPo::Type type = attr->getType();
+  
+    if (type == PiPo::Type::Enum) {
+      std::vector<const char *> *list = attr->getEnumList();
+      
+      for (int i = 0; i < list->size(); i++) {
+        if (strcmp(list->at(i), value.c_str()) == 0) {
+          attr->set(0, i);
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
+
+void
+PiPoHost::propagateInputStreamAttributes()
+{
+  if (this->graph != nullptr)
+  {
+    this->graph->streamAttributes(this->inputStreamAttrs.hasTimeTags,
+                            this->inputStreamAttrs.rate,
+                            this->inputStreamAttrs.offset,
+                            this->inputStreamAttrs.dims[0],
+                            this->inputStreamAttrs.dims[1],
+                            this->inputStreamAttrs.labels,
+                            this->inputStreamAttrs.hasVarSize,
+                            this->inputStreamAttrs.domain,
+                            this->inputStreamAttrs.maxFrames);
+  }
+}
+
+
+
+
+// void
+// PiPoHost::streamAttributesChanged(PiPo *pipo, PiPo::Attr *attr) {
+//   this->propagateInputAttributes();
+// }
+
+// void
+// PiPoHost::signalError(PiPo *pipo, std::string errorMsg) {
+//   // todo
+// }
+
+// void
+// PiPoHost::signalWarning(PiPo *pipo, std::string warningMsg) {
+//   // todo
+// }
+
+//--------------------- INPUT STREAM ATTRIBUTES SETTERS ----------------------//
+
+/*
+void
+PiPoHost::setInputHasTimeTags(bool hasTimeTags, bool propagate) {
+  this->inputStreamAttrs.hasTimeTags = hasTimeTags;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+#define MIN_PIPO_SAMPLERATE (1.0 / 31536000000.0) // once a year
+#define MAX_PIPO_SAMPLERATE (96000000000.0)
+
+void
+PiPoHost::setInputFrameRate(double rate, bool propagate) {
+  if (rate <= MIN_PIPO_SAMPLERATE) {
+    this->inputStreamAttrs.rate = MIN_PIPO_SAMPLERATE;
+  } else if (rate >= MAX_PIPO_SAMPLERATE) {
+    this->inputStreamAttrs.rate = MAX_PIPO_SAMPLERATE;
+  } else {
+    this->inputStreamAttrs.rate = rate;
+  }
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+PiPoHost::setInputFrameOffset(double offset, bool propagate) {
+  this->inputStreamAttrs.offset = offset;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+PiPoHost::setInputDims(int width, int height, bool propagate) {
+  this->inputStreamAttrs.dims[0] = width;
+  this->inputStreamAttrs.dims[1] = height;
+  
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+PiPoHost::setInputLabels(const std::vector<std::string> &labels, bool propagate) {
+  const char *labs[labels.size()];
+
+  for (unsigned int i = 0; i < labels.size(); ++i) {
+    labs[i] = labels[i].c_str();
+  }
+
+  this->inputStreamAttrs.labels = &labs[0];
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+PiPoHost::setInputHasVarSize(bool hasVarSize, bool propagate) {
+  this->inputStreamAttrs.hasVarSize = hasVarSize;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+PiPoHost::setInputDomain(double domain, bool propagate) {
+  this->inputStreamAttrs.domain = domain;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+PiPoHost::setInputMaxFrames(int maxFrames, bool propagate) {
+  this->inputStreamAttrs.maxFrames = maxFrames;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+//--------------------- INPUT STREAM ATTRIBUTES GETTERS ----------------------//
+
+bool
+PiPoHost::getInputHasTimeTags() {
+  return this->inputStreamAttrs.hasTimeTags;
+}
+
+double
+PiPoHost::getInputFrameRate() {
+  return this->inputStreamAttrs.rate;
+}
+
+double
+PiPoHost::getInputFrameOffset() {
+  return this->inputStreamAttrs.offset;
+}
+
+void
+PiPoHost::getInputDims(int &width, int &height) {
+  width = this->inputStreamAttrs.dims[0];
+  height = this->inputStreamAttrs.dims[1];
+}
+
+void
+PiPoHost::getInputLabels(std::vector<std::string> &labels) {
+  //for (unsigned int i = 0; i < )
+}
+
+bool
+PiPoHost::getInputHasVarSize() {
+  return this->inputStreamAttrs.hasVarSize;
+}
+
+double
+PiPoHost::getInputDomain() {
+  return this->inputStreamAttrs.domain;
+}
+
+int
+PiPoHost::getInputMaxFrames() {
+  return this->inputStreamAttrs.maxFrames;
+}
+//*/
+
+//--------------------- OUTPUT STREAM ATTRIBUTES GETTERS ---------------------//
+
+void
+PiPoHost::setOutputAttributes(bool hasTimeTags, double rate, double offset,
+                              unsigned int width, unsigned int height,
+                              const char **labels, bool hasVarSize,
+                              double domain, unsigned int maxFrames) {
+  if (labels != NULL) {
+    int numLabels = width;
+    
+    if (numLabels > PIPO_MAX_LABELS) {
+      numLabels = PIPO_MAX_LABELS;
+    }
+    
+    for (unsigned int i = 0; i < numLabels; i++) {
+      try {
+        this->outputStreamAttrs.labels[i] = labels[i];        
+      } catch(std::exception e) {
+        this->outputStreamAttrs.labels[i] = "unnamed";
+      }
+    }
+    
+    this->outputStreamAttrs.numLabels = numLabels;
+  } else {
+    this->outputStreamAttrs.numLabels = 0;
+  }
+  
+  this->outputStreamAttrs.hasTimeTags = hasTimeTags;
+  this->outputStreamAttrs.rate = rate;
+  this->outputStreamAttrs.offset = offset;
+  this->outputStreamAttrs.dims[0] = width;
+  this->outputStreamAttrs.dims[1] = height;
+  this->outputStreamAttrs.hasVarSize = hasVarSize;
+  this->outputStreamAttrs.domain = domain;
+  this->outputStreamAttrs.maxFrames = maxFrames; 
+}
+
+bool
+PiPoHost::getOutputHasTimeTags() {
+  return this->outputStreamAttrs.hasTimeTags;
+}
+
+double
+PiPoHost::getOutputFrameRate() {
+  return this->outputStreamAttrs.rate;
+}
+
+double
+PiPoHost::getOutputFrameOffset() {
+  return this->outputStreamAttrs.offset;
+}
+
+void
+PiPoHost::getOutputDims(int &width, int &height) {
+  width = this->outputStreamAttrs.dims[0];
+  height = this->outputStreamAttrs.dims[1];
+}
+
+void
+PiPoHost::getOutputLabels(std::vector<std::string> &labels) {
+  labels.clear();
+
+  for (unsigned int i = 0; this->outputStreamAttrs.numLabels; ++i) {
+
+    if (this->outputStreamAttrs.labels[i] != NULL) {
+      labels.push_back(std::string(this->outputStreamAttrs.labels[i]));
+    } else {
+      labels.push_back("unnamed");
+    }
+  }
+}
+
+bool
+PiPoHost::getOutputHasVarSize() {
+  return this->outputStreamAttrs.hasVarSize;
+}
+
+double
+PiPoHost::getOutputDomain() {
+  return this->outputStreamAttrs.domain;
+}
+
+int
+PiPoHost::getOutputMaxFrames() {
+  return this->outputStreamAttrs.maxFrames;
+}
+
+
+
+
+
+
+
+
+
+
+//===================== PIPO HOST CLASS IMPLEMENTATION =======================//
+
+rapidPiPoHost::rapidPiPoHost(rapidPiPoOwner *rpo) :
+owner(rpo),
+inputStreamAttrs(PIPO_MAX_LABELS),
+outputStreamAttrs(PIPO_MAX_LABELS) {
+  PiPoCollection::init();
+  outputter = new rapidPiPoOutputter(this);
+  chain = nullptr;
+}
+
+rapidPiPoHost::~rapidPiPoHost() {
+  if (chain != nullptr) {
+    delete chain;
+  }
+  delete outputter;
+}
+
+rapidPiPoOwner *
+rapidPiPoHost::getOwner() {
+  return owner;
+}
+
+void
+rapidPiPoHost::onNewFrame(double time, std::vector<PiPoValue> &frame) {
+  std::cout << time << std::endl;
+  owner->onNewFrame(frame);
+}
+// void
+// rapidPiPoHost::onNewFrame(const std::function<void(std::vector<PiPoValue>,
+//                                              rapidPiPoOwner *rpo)> cb) {
+//   outputter->setFrameCallback(cb);
+// }
+
+// void
+// rapidPiPoHost::onNewFrame(std::function<void(std::vector<PiPoValue>)> cb) {
+//   outputter->setSimpleFrameCallback(cb);
+// }
+
+std::vector<PiPoValue>
+rapidPiPoHost::getLastFrame() {
+  return outputter->getLastFrame();
+}
+
+rapidPiPo *
+rapidPiPoHost::setPiPoChain(std::string name) {
+  if (chain != nullptr) {
+    delete chain;
+  }
+
+  chain = new rapidPiPo(name);
+  chain->connect((PiPo *)outputter);
+  return chain;
+}
+
+void
+rapidPiPoHost::clearPiPoChain() {
+  delete chain;
+  chain = nullptr;
+}
+
+void
+rapidPiPoHost::propagateInputAttributes() {
+  if (chain != nullptr) {
+    const char *colNameStr[PIPO_MAX_LABELS];
+
+    unsigned int numCols = this->inputStreamAttrs.dims[0];
+    unsigned int numLabels = this->inputStreamAttrs.numLabels;
+    
+    if (numLabels > PIPO_MAX_LABELS) {
+      numLabels = PIPO_MAX_LABELS;
+    }
+    
+    if (numLabels > numCols) {
+      numLabels = numCols;
+    }
+    
+    std::vector<std::string> labels(numLabels);
+
+    if (numLabels > 0) {
+      for (unsigned int i = 0; i < numLabels; i++) {
+        colNameStr[i] = this->inputStreamAttrs.labels[i];
+      }
+      
+      for (unsigned int i = numLabels; i < numCols; i++) {
+        colNameStr[i] = "unnamed";
+      }
+      
+      for (unsigned int i = 0; i < numCols; ++i) {
+        labels[i] = std::string(colNameStr[i]);
+      }
+    }
+    
+    chain->streamAttributes(this->inputStreamAttrs.hasTimeTags,
+                            this->inputStreamAttrs.rate,
+                            this->inputStreamAttrs.offset,
+                            this->inputStreamAttrs.dims[0],
+                            this->inputStreamAttrs.dims[1],
+                            labels,
+                            this->inputStreamAttrs.hasVarSize,
+                            this->inputStreamAttrs.domain,
+                            this->inputStreamAttrs.maxFrames);
+  }
+}
+
+// void
+// rapidPiPoHost::streamAttributesChanged(PiPo *pipo, PiPo::Attr *attr) {
+//   this->propagateInputAttributes();
+// }
+
+// void
+// rapidPiPoHost::signalError(PiPo *pipo, std::string errorMsg) {
+//   // todo
+// }
+
+// void
+// rapidPiPoHost::signalWarning(PiPo *pipo, std::string warningMsg) {
+//   // todo
+// }
+
+//--------------------- INPUT STREAM ATTRIBUTES SETTERS ----------------------//
+
+void
+rapidPiPoHost::setInputHasTimeTags(bool hasTimeTags, bool propagate) {
+  this->inputStreamAttrs.hasTimeTags = hasTimeTags;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+#define MIN_PIPO_SAMPLERATE (1.0 / 31536000000.0) /* once a year */
+#define MAX_PIPO_SAMPLERATE (96000000000.0)
+
+void
+rapidPiPoHost::setInputFrameRate(double rate, bool propagate) {
+  if (rate <= MIN_PIPO_SAMPLERATE) {
+    this->inputStreamAttrs.rate = MIN_PIPO_SAMPLERATE;
+  } else if (rate >= MAX_PIPO_SAMPLERATE) {
+    this->inputStreamAttrs.rate = MAX_PIPO_SAMPLERATE;
+  } else {
+    this->inputStreamAttrs.rate = rate;
+  }
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+rapidPiPoHost::setInputFrameOffset(double offset, bool propagate) {
+  this->inputStreamAttrs.offset = offset;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+rapidPiPoHost::setInputDims(int width, int height, bool propagate) {
+  this->inputStreamAttrs.dims[0] = width;
+  this->inputStreamAttrs.dims[1] = height;
+  
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+rapidPiPoHost::setInputLabels(const std::vector<std::string> &labels, bool propagate) {
+  const char *labs[labels.size()];
+
+  for (unsigned int i = 0; i < labels.size(); ++i) {
+    labs[i] = labels[i].c_str();
+  }
+
+  this->inputStreamAttrs.labels = &labs[0];
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+rapidPiPoHost::setInputHasVarSize(bool hasVarSize, bool propagate) {
+  this->inputStreamAttrs.hasVarSize = hasVarSize;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+rapidPiPoHost::setInputDomain(double domain, bool propagate) {
+  this->inputStreamAttrs.domain = domain;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+void
+rapidPiPoHost::setInputMaxFrames(int maxFrames, bool propagate) {
+  this->inputStreamAttrs.maxFrames = maxFrames;
+
+  if (propagate) {
+    this->propagateInputAttributes();
+  }
+}
+
+//--------------------- INPUT STREAM ATTRIBUTES GETTERS ----------------------//
+
+bool
+rapidPiPoHost::getInputHasTimeTags() {
+  return this->inputStreamAttrs.hasTimeTags;
+}
+
+double
+rapidPiPoHost::getInputFrameRate() {
+  return this->inputStreamAttrs.rate;
+}
+
+double
+rapidPiPoHost::getInputFrameOffset() {
+  return this->inputStreamAttrs.offset;
+}
+
+void
+rapidPiPoHost::getInputDims(int &width, int &height) {
+  width = this->inputStreamAttrs.dims[0];
+  height = this->inputStreamAttrs.dims[1];
+}
+
+void
+rapidPiPoHost::getInputLabels(std::vector<std::string> &labels) {
+  //for (unsigned int i = 0; i < )
+}
+
+bool
+rapidPiPoHost::getInputHasVarSize() {
+  return this->inputStreamAttrs.hasVarSize;
+}
+
+double
+rapidPiPoHost::getInputDomain() {
+  return this->inputStreamAttrs.domain;
+}
+
+int
+rapidPiPoHost::getInputMaxFrames() {
+  return this->inputStreamAttrs.maxFrames;
+}
+
+//--------------------- OUTPUT STREAM ATTRIBUTES GETTERS ---------------------//
+
+void
+rapidPiPoHost::setOutputAttributes(bool hasTimeTags, double rate, double offset,
+                                   unsigned int width, unsigned int height,
+                                   const char **labels, bool hasVarSize,
+                                   double domain, unsigned int maxFrames) {
+  if (labels != NULL) {
+    int numLabels = width;
+    
+    if (numLabels > PIPO_MAX_LABELS) {
+      numLabels = PIPO_MAX_LABELS;
+    }
+    
+    for (unsigned int i = 0; i < numLabels; i++) {
+      try {
+        this->outputStreamAttrs.labels[i] = labels[i];        
+      } catch(std::exception e) {
+        this->outputStreamAttrs.labels[i] = "unnamed";
+      }
+    }
+    
+    this->outputStreamAttrs.numLabels = numLabels;
+  } else {
+    this->outputStreamAttrs.numLabels = 0;
+  }
+  
+  this->outputStreamAttrs.hasTimeTags = hasTimeTags;
+  this->outputStreamAttrs.rate = rate;
+  this->outputStreamAttrs.offset = offset;
+  this->outputStreamAttrs.dims[0] = width;
+  this->outputStreamAttrs.dims[1] = height;
+  this->outputStreamAttrs.hasVarSize = hasVarSize;
+  this->outputStreamAttrs.domain = domain;
+  this->outputStreamAttrs.maxFrames = maxFrames; 
+}
+
+bool
+rapidPiPoHost::getOutputHasTimeTags() {
+  return this->outputStreamAttrs.hasTimeTags;
+}
+
+double
+rapidPiPoHost::getOutputFrameRate() {
+  return this->outputStreamAttrs.rate;
+}
+
+double
+rapidPiPoHost::getOutputFrameOffset() {
+  return this->outputStreamAttrs.offset;
+}
+
+void
+rapidPiPoHost::getOutputDims(int &width, int &height) {
+  width = this->outputStreamAttrs.dims[0];
+  height = this->outputStreamAttrs.dims[1];
+}
+
+void
+rapidPiPoHost::getOutputLabels(std::vector<std::string> &labels) {
+  labels.clear();
+
+  for (unsigned int i = 0; this->outputStreamAttrs.numLabels; ++i) {
+
+    if (this->outputStreamAttrs.labels[i] != NULL) {
+      labels.push_back(std::string(this->outputStreamAttrs.labels[i]));
+    } else {
+      labels.push_back("unnamed");
+    }
+  }
+}
+
+bool
+rapidPiPoHost::getOutputHasVarSize() {
+  return this->outputStreamAttrs.hasVarSize;
+}
+
+double
+rapidPiPoHost::getOutputDomain() {
+  return this->outputStreamAttrs.domain;
+}
+
+int
+rapidPiPoHost::getOutputMaxFrames() {
+  return this->outputStreamAttrs.maxFrames;
+}
+
+// void
+// rapidPiPoHost::setRapidPiPoParam(rapidPiPoParam *param) {
+//   char instanceName[maxWordLen];
+//   char pipoAttrName[maxWordLen];
+
+//   if (getPiPoInstanceAndAttrName(param->getName(), instanceName, pipoAttrName)) {
+//     // todo (or not todo)
+//   }
+// }
+
+// void
+// rapidPiPoHost::getPiPoParams(std::vector<rapidPiPoParam> &params) {
+
+// }
diff --git a/src/signalProcessing/rapidPiPoTools/rapidPiPoHost.h b/src/signalProcessing/rapidPiPoTools/rapidPiPoHost.h
new file mode 100644
index 0000000000000000000000000000000000000000..b665a3f024d869a2755958352d0f6dcaf3fe59be
--- /dev/null
+++ b/src/signalProcessing/rapidPiPoTools/rapidPiPoHost.h
@@ -0,0 +1,312 @@
+#ifndef _RAPID_PIPO_HOST_H_
+#define _RAPID_PIPO_HOST_H_
+
+#include "PiPo.h"
+#include "PiPoHost.h"
+#include "PiPoCollection.h"
+
+#define MIN_PIPO_SAMPLERATE (1.0 / 31536000000.0) /* once a year */
+#define MAX_PIPO_SAMPLERATE (96000000000.0)
+
+#define PIPO_OUT_RING_SIZE 2
+
+struct pipoStreamAttributes {
+  pipoStreamAttributes() :
+  hasTimeTags(false),
+  rate(MIN_PIPO_SAMPLERATE),
+  offset(0),
+  labels({ "" }),
+  hasVarSize(false),
+  domain(0),
+  maxFrames(256)
+  {
+      dims[0] = 1;
+      dims[1] = 1;
+  }
+
+  bool hasTimeTags;
+  double rate;
+  double offset;
+  unsigned int dims[2]; // width, height (by pipo convention)
+  std::vector<std::string> labels;
+  bool hasVarSize;
+  double domain;
+  unsigned int maxFrames;
+};
+
+
+//class PiPoObserver;
+class PiPoOut;
+
+//================================ H O S T ===================================//
+
+class PiPoHost : public PiPo::Parent {
+    friend class PiPoOut;
+    
+private:
+    PiPo *graph;
+    std::string graphName;
+    PiPoOut *out;
+    // PiPoObserver *obs;
+    PiPoStreamAttributes inputStreamAttrs;
+    PiPoStreamAttributes outputStreamAttrs;
+    
+public:
+    // PiPoHost(PiPoObserver *obs);
+    PiPoHost();
+    ~PiPoHost();
+    
+    // PiPoObserver *getObserver();
+
+    virtual bool setPiPoGraph(std::string name);
+    virtual void clearPiPoGraph();
+
+    // override this method when inheriting !!!
+    virtual void onNewFrameOut(double time, std::vector<PiPoValue> &frame);
+    virtual std::vector<PiPoValue> getLastFrameOut();
+    
+    virtual int setInputStreamAttributes(pipoStreamAttributes sa, bool propagate = true);
+    virtual pipoStreamAttributes &getOutputStreamAttributes();
+
+    virtual int frames(double time, double weight, PiPoValue *values, unsigned int size,
+                       unsigned int num);
+
+    // virtual bool setAttr(const std::string &attrName, bool value);
+    // virtual bool setAttr(const std::string &attrName, int value);
+    virtual bool setAttr(const std::string &attrName, double value);
+    virtual bool setAttr(const std::string &attrName, const std::vector<double> &values);
+    virtual bool setAttr(const std::string &attrName, const std::string &value); // for enums
+
+    // virtual const std::vector<std::string>& getAttrNames();
+    // virtual bool isBoolAttr(const std::string &attrName);
+    // virtual bool isEnumAttr(const std::string &attrName);
+    // virtual bool isIntAttr(const std::string &attrName);
+    // virtual bool isIntArrayAttr(const std::string &attrName);
+    // virtual bool isFloatAttr(const std::string &attrName);
+    // virtual bool isFloatArrayAttr(const std::string &attrName);
+    // virtual bool isStringAttr(const std::string &attrName);
+
+    // virtual bool getBoolAttr(const std::string &attrName);
+    // virtual int getIntAttr(const std::string &attrName);
+    // virtual float getFloatAttr(const std::string &attrName);
+
+
+
+    // int streamAttributes(bool hasTimeTags, double rate, double offset,
+    //                      unsigned int width, unsigned int height,
+    //                      const std::vector<std::string> &labels,
+    //                      bool hasVarSize, double domain, unsigned int maxFrames,
+    //                      bool propagate = true);
+
+    // void propagateInputAttributes();
+    
+
+    // void streamAttributesChanged(PiPo *pipo, PiPo::Attr *attr);
+    // void signalError(PiPo *pipo, std::string errorMsg);
+    // void signalWarning(PiPo *pipo, std::string warningMsg);
+    
+    /*
+    void setInputHasTimeTags(bool hasTimeTags, bool propagate = true);
+    void setInputFrameRate(double rate, bool propagate = true);
+    void setInputFrameOffset(double offset, bool propagate = true);
+    void setInputDims(int width, int height, bool propagate = true);
+    void setInputLabels(const std::vector<std::string> &labels, bool propagate = true);
+    void setInputHasVarSize(bool hasVarSize, bool propagate = true);
+    void setInputDomain(double domain, bool propagate = true);
+    void setInputMaxFrames(int maxFrames, bool propagate = true);
+    
+    bool getInputHasTimeTags();
+    double getInputFrameRate();
+    double getInputFrameOffset();
+    void getInputDims(int &width, int &height);
+    void getInputLabels(std::vector<std::string> &labels);
+    bool getInputHasVarSize();
+    double getInputDomain();
+    int getInputMaxFrames();
+    
+    bool getOutputHasTimeTags();
+    double getOutputFrameRate();
+    double getOutputFrameOffset();
+    void getOutputDims(int &width, int &height);
+    void getOutputLabels(std::vector<std::string> &labels);
+    bool getOutputHasVarSize();
+    double getOutputDomain();
+    int getOutputMaxFrames();
+
+    // void setPiPoParam(PiPoParam *param);
+    //*/
+private:
+    void propagateInputStreamAttributes();
+    void setOutputAttributes(bool hasTimeTags, double rate, double offset,
+                             unsigned int width, unsigned int height,
+                             const char **labels, bool hasVarSize,
+                             double domain, unsigned int maxFrames);
+    
+};
+
+//================================= PiPoOut ==================================//
+
+ class PiPoOut : public PiPo {
+private:
+    PiPoHost *host;
+    std::atomic<int> writeIndex, readIndex;
+    std::vector<std::vector<PiPoValue>> ringBuffer;
+    //std::function<void(std::vector<PiPoValue>, PiPoObserver *rpo)> frameCallback;
+    std::function<void(std::vector<PiPoValue>)> simpleFrameCallback;
+    
+public:
+    PiPoOut(PiPoHost *host) :
+    PiPo((PiPo::Parent *)host) {
+        this->host = host;
+        writeIndex = 0;
+        readIndex = 0;
+        ringBuffer.resize(PIPO_OUT_RING_SIZE);
+    }
+    
+    ~PiPoOut() {}
+    
+    int streamAttributes(bool hasTimeTags,
+                         double rate, double offset,
+                         unsigned int width, unsigned int height,
+                         const char **labels, bool hasVarSize,
+                         double domain, unsigned int maxFrames) {
+        
+        this->host->setOutputAttributes(hasTimeTags, rate, offset, width, height,
+                                        labels, hasVarSize, domain, maxFrames);
+        
+        for (int i = 0; i < PIPO_OUT_RING_SIZE; ++i) {
+            ringBuffer[i].resize(width * height);
+        }
+        
+        return 0;
+    }
+    
+    int frames(double time, double weight, float *values,
+               unsigned int size, unsigned int num) {
+        
+        if (num > 0) {
+            for (int i = 0; i < num; ++i) {
+                
+                for (int j = 0; j < size; ++j) {
+                    ringBuffer[writeIndex][j] = values[i * size + j];
+                }
+                
+                // atomic swap ?
+                writeIndex = 1 - writeIndex;
+                readIndex = 1 - writeIndex;
+                
+                this->host->onNewFrameOut(time, ringBuffer[readIndex]);
+                
+                if (writeIndex + 1 == PIPO_OUT_RING_SIZE) {
+                    writeIndex = 0;
+                } else {
+                    writeIndex++;
+                }
+            }
+        }
+        
+        return 0;
+    }
+    
+    //void setFrameCallback(std::function<void(std::vector<PiPoValue>,
+    //                                         PiPoObserver *obs)> f) {
+    //    frameCallback = f;
+    //}
+    
+    void setSimpleFrameCallback(std::function<void(std::vector<PiPoValue>)> f) {
+        simpleFrameCallback = f;
+    }
+    
+    std::vector<PiPoValue> getLastFrame() {
+        std::vector<PiPoValue> f;
+        
+        if (readIndex > -1) {
+            f = ringBuffer[readIndex];
+        }
+        
+        return f;
+    }
+};
+
+//================================ PARAMETER =================================//
+
+// can we avoid using such a class ?
+/*
+class rapidPiPoParam {
+  std::string name;
+  std::string pipoName;
+  std::string paramName;
+  std::vector<std::string> values;
+
+public:
+  rapidPiPoParam() :
+  name(""), pipoName(""), paramName("") {}
+
+  rapidPiPoParam(std::string name, std::string pipoName, std::string paramName,
+                 std::vector<std::string> const &values) {
+    this->name = name;
+    this->pipoName = pipoName;
+    this->paramName = paramName;
+    this->values = std::vector<std::string>(values.size());
+    for (int i = 0; i < values.size(); ++i) {
+      this->values[i] = values[i];
+    }
+  }
+
+  const char *getName() {
+    return name.c_str();
+  }
+
+  const char *getParamName() {
+    return paramName.c_str();
+  }
+
+  const char *getPiPoName() {
+    return pipoName.c_str();
+  }
+
+  int getNumValues() {
+    return values.size();
+  }
+
+  bool isValueInt(int i) {
+    // todo
+    return false;
+  }
+
+  bool isValueFloat(int i) {
+    // todo
+    return false;
+  } 
+
+  bool isValueNum(int i) {
+    // todo;
+    return false;
+  }
+
+  float getValueFloat(int i) {
+    // todo
+    return 0.;
+  }
+
+  int getValueInt(int i) {
+    // todo
+    return 0;
+  }
+
+  const char *getValueString() {
+    return values[0].c_str();
+    //return values[i].c_str();
+  }
+
+  std::string getValuesAsString() {
+    std::string res = values[0];
+    for (int i = 1; i < values.size(); ++i) {
+      res += " " + values[i];
+    }
+    return res;
+  }
+};
+//*/
+
+#endif /* _RAPID_PIPO_HOST_H_ */
diff --git a/src/signalProcessing/rapidPiPoTools/rapidPiPoTools.h b/src/signalProcessing/rapidPiPoTools/rapidPiPoTools.h
new file mode 100644
index 0000000000000000000000000000000000000000..45c381bba89694fe5529cc103ec640bde0a2f7db
--- /dev/null
+++ b/src/signalProcessing/rapidPiPoTools/rapidPiPoTools.h
@@ -0,0 +1,6 @@
+#ifndef _RAPID_PIPO_TOOLS_H_
+#define _RAPID_PIPO_TOOLS_H_
+
+#include "rapidPiPoHost.h"
+
+# endif /* _RAPID_PIPO_TOOLS_H_ */
\ No newline at end of file