diff --git a/src/machineLearning/rapidXmmTools/rapidXmmTools.cpp b/src/machineLearning/rapidXmmTools/rapidXmmTools.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..280093ca410ffa18f8e53fc699fe416496f92fbf
--- /dev/null
+++ b/src/machineLearning/rapidXmmTools/rapidXmmTools.cpp
@@ -0,0 +1,201 @@
+#include "rapidXmmTools.h"
+#include "trainingData.h"
+#include "machineLearning.h"
+
+static bool trainingData2xmmTrainingSet(const rapidmix::trainingData& data, xmm::TrainingSet& set) {
+  if (data.trainingSet.size() <= 1) {
+    // no recorded phrase (only default one)
+    return false;
+  }
+
+  if (data.trainingSet.size() > 1 && data.trainingSet[1].elements.size() == 0) {
+    // empty recorded phrase
+    return false;
+  }
+
+  rapidmix::trainingData::element el = data.trainingSet[1].elements[0];
+  int dimIn = static_cast<int>(el.input.size());
+  int dimOut = static_cast<int>(el.output.size());
+
+  // translate and return true if data and set are compatible
+  // don't translate and return false otherwise
+
+  if (dimOut > 0 != set.bimodal()) {
+    return false;
+  }
+
+  xmm::Phrase xp;
+
+  if (set.bimodal()) {
+    set.dimension.set(dimIn + dimOut);
+    set.dimension_input.set(dimIn);
+    xp = xmm::Phrase(xmm::MemoryMode::OwnMemory, xmm::Multimodality::Bimodal);
+    xp.dimension.set(dimIn + dimOut);
+    xp.dimension_input.set(dimIn);
+  } else {
+    set.dimension.set(dimIn);
+    set.dimension_input.set(0);
+    xp = xmm::Phrase(xmm::MemoryMode::OwnMemory, xmm::Multimodality::Unimodal);
+    xp.dimension.set(dimIn);
+    xp.dimension_input.set(0);
+  }
+
+  set.clear();
+
+  //for (auto &phrase : data.trainingSet) {
+  // changed to look starting from index 1
+  // because phrase at index 0 is for unordered elements
+  for (int i = 1; i < data.trainingSet.size(); ++i) {
+    const rapidmix::trainingData::phrase &phrase = data.trainingSet[i];
+    xp.clear();
+    xp.label.set(phrase.label);
+
+    for (auto &element : phrase.elements) {
+      std::vector<float> obsIn(element.input.begin(), element.input.end());
+      std::vector<float> obsOut(element.output.begin(), element.output.end());
+      std::vector<float> obs;
+      obs.insert(obs.end(), obsIn.begin(), obsIn.end());
+      obs.insert(obs.end(), obsOut.begin(), obsOut.end());
+      xp.record(obs);
+    }
+
+    set.addPhrase(static_cast<int>(set.size()), xp);
+  }
+
+  return true;
+}
+
+//=============================== xmmTool ====================================//
+
+template <class SingleClassModel, class Model>
+bool xmmTool<SingleClassModel, Model>::train(const rapidmix::trainingData& newTrainingData) {
+  if (trainingData2xmmTrainingSet(newTrainingData, set)) {
+    model.train(&set);
+    model.reset();
+    return true;
+  }
+
+  return false;
+}
+
+////////// private JSON data manipulation methods :
+
+//TODO: add a type field (gmm/gmr/hmm/hmr) in metadata when family is xmm
+template <class SingleClassModel, class Model>
+Json::Value xmmTool<SingleClassModel, Model>::toJSON(/*std::string modelType*/) {
+  Json::Value root;
+  Json::Value metadata;
+  Json::Value modelSet;
+
+  metadata["creator"] = "Rapid API C++";
+  metadata["version"] = "v0.1.1"; //TODO: This should be a macro someplace
+  metadata["family"] = "xmm";
+  root["metadata"] = metadata;
+
+  modelSet.append(model.toJson());
+  root["modelSet"] = modelSet;
+
+  return root;
+}
+
+template <class SingleClassModel, class Model>
+bool xmmTool<SingleClassModel, Model>::fromJSON(Json::Value &jm) {
+  if (jm["metadata"]["family"].asString().compare("xmm") == 0 &&
+      jm["modelSet"].size() > 0) {
+    model.fromJson(jm["modelSet"][0]);
+    model.reset();
+    return true;
+  }
+
+  return false;
+}
+
+////////// public JSON file manipulation interface :
+
+template <class SingleClassModel, class Model>
+std::string xmmTool<SingleClassModel, Model>::getJSON() {
+  Json::Value result = toJSON();
+  return result.toStyledString();
+}
+
+template <class SingleClassModel, class Model>
+void xmmTool<SingleClassModel, Model>::writeJSON(const std::string &filepath) {
+  Json::Value root = toJSON();
+  std::ofstream jsonOut;
+  jsonOut.open (filepath);
+  Json::StyledStreamWriter writer;
+  writer.write(jsonOut, root);
+  jsonOut.close();
+}
+
+template <class SingleClassModel, class Model>
+bool xmmTool<SingleClassModel, Model>::putJSON(const std::string &jsonMessage) {
+  Json::Value parsedFromString;
+  Json::Reader reader;
+  bool parsingSuccessful = reader.parse(jsonMessage, parsedFromString);
+  return (parsingSuccessful && fromJSON(parsedFromString));
+}
+
+template <class SingleClassModel, class Model>
+bool xmmTool<SingleClassModel, Model>::readJSON(const std::string &filepath) {
+  Json::Value root;
+  std::ifstream file(filepath);
+  file >> root;
+  return fromJSON(root);
+}
+
+//============================== xmmGmmTool ==================================//
+
+std::vector<double> xmmGmmTool::process(const std::vector<double>& inputVector) {
+  xmmTool::preProcess(inputVector);
+  return model.results.smoothed_normalized_likelihoods;
+}
+
+//============================== xmmGmrTool ==================================//
+
+std::vector<double> xmmGmrTool::process(const std::vector<double>& inputVector) {
+  xmmTool::preProcess(inputVector);
+  std::vector<float> *res = &model.results.output_values;
+  std::vector<double> dRes(res->begin(), res->end());
+  return dRes;
+}
+
+//============================== xmmHmmTool ==================================//
+
+std::vector<double> xmmHmmTool::process(const std::vector<double>& inputVector) {
+  xmmTool::preProcess(inputVector);
+  std::vector<double> res;
+
+  int i(0);
+  for (auto &m : model.models) {
+    res.push_back(model.results.smoothed_normalized_likelihoods[i]);
+    res.push_back(m.second.results.progress);
+    i++;
+  }
+
+  return res;
+}
+
+//============================== xmmHmrTool ==================================//
+
+std::vector<double> xmmHmrTool::process(const std::vector<double>& inputVector) {
+  xmmTool::preProcess(inputVector);
+  std::vector<float> *res = &model.results.output_values;
+  std::vector<double> dRes(res->begin(), res->end());
+  return dRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+///// generic train method and forward declaration of specialized templates 
+///////////////////////////////////////////////////////////////////////////
+
+template <class MachineLearningModule>
+bool rapidmix::machineLearning<MachineLearningModule>::train(const trainingData &newTrainingData) {
+    return MachineLearningModule::train(newTrainingData);
+}
+
+template class rapidmix::machineLearning<xmmGmmTool>;
+template class rapidmix::machineLearning<xmmGmrTool>;
+template class rapidmix::machineLearning<xmmHmmTool>;
+template class rapidmix::machineLearning<xmmHmrTool>;
+
diff --git a/src/machineLearning/rapidXmmTools/rapidXmmTools.h b/src/machineLearning/rapidXmmTools/rapidXmmTools.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c166ba06f9f5cd70d163de24f9ce9e2bc5365cb
--- /dev/null
+++ b/src/machineLearning/rapidXmmTools/rapidXmmTools.h
@@ -0,0 +1,249 @@
+#ifndef _RAPID_XMM_TOOLS_H_
+#define _RAPID_XMM_TOOLS_H_
+
+// this works !
+#ifndef EXTERNAL_JSONCPP_PATH
+// #define EXTERNAL_JSONCPP_PATH "../../../../json/json.h" // relative to xmmJson.h
+#define EXTERNAL_JSONCPP_PATH "json.h"
+#endif /* EXTERNAL_JSONCPP_PATH */
+
+#include "xmm.h"
+
+// forward declaration
+namespace rapidmix { class trainingData; }
+
+// original defined in xmmModelConfiguration.hpp
+enum xmmRegressionEstimator {
+  xmmLikeliestRegression,
+  xmmMixtureRegression
+};
+
+// original defined in xmmGaussianDistribution.hpp
+enum xmmCovarianceMode {
+  xmmFullCovariance,
+  xmmDiagonalCovariance
+};
+
+// original defined in xmmHmmParameters.hpp
+enum xmmHmmTransitionMode {
+  xmmHmmLeftRightTransition,
+  xmmHmmErgodicTransition
+};
+
+// original defined in xmmHmmParameters.hpp
+enum xmmHmmRegressionEstimator {
+  xmmHmmFullRegression,
+  xmmHmmWindowedRegression,
+  xmmHmmLikeliestRegression
+};
+
+// this is the optional argument of machineLearning<xmmWhateverTool>'s constructors
+struct xmmToolConfig {
+  xmmToolConfig() :
+  gaussians(1),
+  relativeRegularization(0.01),
+  absoluteRegularization(0.01),
+  regressionEstimator(xmmMixtureRegression),
+  covarianceMode(xmmFullCovariance),
+  states(5),
+  hierarchical(true),
+  hmmTransitionMode(xmmHmmErgodicTransition),
+  hmmRegressionEstimator(xmmHmmFullRegression),
+  likelihoodWindow(5) {}
+
+  // general parameters :
+  uint32_t gaussians;
+  float relativeRegularization;
+  float absoluteRegularization;
+  xmmRegressionEstimator regressionEstimator;
+  xmmCovarianceMode covarianceMode;
+
+  // hmm specific :
+  uint32_t states;
+  bool hierarchical;
+  xmmHmmTransitionMode hmmTransitionMode;
+  xmmHmmRegressionEstimator hmmRegressionEstimator;
+
+  // run-time parameter :
+  uint32_t likelihoodWindow;
+};
+
+//========================== template base class =============================//
+
+template <class SingleClassModel, class Model>
+class xmmTool {
+protected:
+  xmmTool(bool bimodal) {
+    model = Model(bimodal);
+    model.configuration.multithreading = xmm::MultithreadingMode::Sequential;
+    model.configuration.changed = true;
+
+    set = xmm::TrainingSet(xmm::MemoryMode::OwnMemory,
+      bimodal
+      ? xmm::Multimodality::Bimodal
+      : xmm::Multimodality::Unimodal
+    );
+  }
+
+  virtual void preProcess(const std::vector<double> &inputVector) {
+    std::vector<float> fv(inputVector.begin(), inputVector.end());
+    model.filter(fv);
+  }
+
+public:
+  virtual ~xmmTool() {}
+
+  virtual bool train(const rapidmix::trainingData &newTrainingData);
+
+  virtual bool reset() {
+    model.reset();
+    return true;
+  }
+
+  /** Get a JSON representation of the model in the form of a styled string */
+  virtual std::string getJSON();
+  /** Write a JSON model description to specified file path */
+  virtual void writeJSON(const std::string &filepath);
+  /** configure empty model with string. See getJSON() */
+  virtual bool putJSON(const std::string &jsonMessage);
+  /** read a JSON file at file path and build a modelSet from it */
+  virtual bool readJSON(const std::string &filepath);
+
+protected:
+  Model model;
+  xmm::TrainingSet set;
+
+  Json::Value toJSON();
+  bool fromJSON(Json::Value &jm);
+};
+
+//======================= base class for GMM models ==========================//
+
+template <class SingleClassModel, class Model>
+class xmmStaticTool : public xmmTool<SingleClassModel, Model> {
+protected:
+  xmmStaticTool(xmmToolConfig cfg, bool bimodal) :
+  xmmTool<SingleClassModel, Model>(bimodal) {
+    xmm::Configuration<SingleClassModel>& mCfg = this->model.configuration;
+
+    mCfg.gaussians.set(cfg.gaussians);
+    mCfg.relative_regularization.set(cfg.relativeRegularization);
+    mCfg.absolute_regularization.set(cfg.absoluteRegularization);
+    
+    xmm::MultiClassRegressionEstimator mcre;
+    switch (cfg.regressionEstimator) {
+      case xmmLikeliestRegression:
+        mcre = xmm::MultiClassRegressionEstimator::Likeliest;
+      case xmmMixtureRegression:
+      default:
+        mcre = xmm::MultiClassRegressionEstimator::Mixture;
+        break;
+    }
+    mCfg.multiClass_regression_estimator = mcre;
+
+    xmm::GaussianDistribution::CovarianceMode gdcm;
+    switch (cfg.covarianceMode) {
+      case xmmFullCovariance:
+        gdcm = xmm::GaussianDistribution::CovarianceMode::Full;
+        break;
+      case xmmDiagonalCovariance:
+      default:
+        gdcm = xmm::GaussianDistribution::CovarianceMode::Diagonal;
+        break;
+    }
+    mCfg.covariance_mode.set(gdcm);
+
+    mCfg.changed = true;
+
+    this->model.shared_parameters->likelihood_window.set(cfg.likelihoodWindow);
+  }
+
+public:
+  virtual ~xmmStaticTool() {}
+};
+
+//======================= base class for HMM models ==========================//
+
+template <class SingleClassModel, class Model>
+class xmmTemporalTool : public xmmStaticTool<SingleClassModel, Model> {
+protected:
+  xmmTemporalTool(xmmToolConfig cfg, bool bimodal) :
+  xmmStaticTool<SingleClassModel, Model>(cfg, bimodal) {
+    xmm::Configuration<SingleClassModel>& mCfg = this->model.configuration;
+
+    mCfg.states.set(cfg.states);
+    mCfg.hierarchical.set(cfg.hierarchical);
+
+    xmm::HMM::TransitionMode htm;
+    switch (cfg.hmmTransitionMode) {
+      case xmmHmmLeftRightTransition:
+        htm = xmm::HMM::TransitionMode::LeftRight;
+        break;
+      case xmmHmmErgodicTransition:
+      default:
+        htm = xmm::HMM::TransitionMode::Ergodic;
+        break;
+    }
+    mCfg.transition_mode.set(htm);
+
+    xmm::HMM::RegressionEstimator hre;
+    switch (cfg.hmmRegressionEstimator) {
+      case xmmHmmFullRegression:
+        hre = xmm::HMM::RegressionEstimator::Full;
+        break;
+      case xmmHmmWindowedRegression:
+        hre = xmm::HMM::RegressionEstimator::Windowed;
+        break;
+      case xmmHmmLikeliestRegression:
+      default:
+        hre = xmm::HMM::RegressionEstimator::Likeliest;
+        break;
+    }
+    mCfg.regression_estimator.set(hre);
+
+    mCfg.changed = true;
+  }
+
+public:
+  virtual ~xmmTemporalTool() {}
+};
+
+//================== actual classes used in machineLearning.h ================//
+
+class xmmGmmTool : public xmmStaticTool<xmm::GMM, xmm::GMM> {
+public:
+  xmmGmmTool(xmmToolConfig cfg = xmmToolConfig()) :
+  xmmStaticTool<xmm::GMM, xmm::GMM>(cfg, false) {}
+  ~xmmGmmTool() {}
+
+  std::vector<double> process(const std::vector<double>& inputVector);
+};
+
+class xmmGmrTool : public xmmStaticTool<xmm::GMM, xmm::GMM> {
+public:
+  xmmGmrTool(xmmToolConfig cfg = xmmToolConfig()) :
+  xmmStaticTool<xmm::GMM, xmm::GMM>(cfg, true) {}
+  ~xmmGmrTool() {}
+
+  std::vector<double> process(const std::vector<double>& inputVector);
+};
+
+class xmmHmmTool : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> {
+public:
+  xmmHmmTool(xmmToolConfig cfg = xmmToolConfig()) :
+  xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM>(cfg, false) {}
+  ~xmmHmmTool() {}
+
+  std::vector<double> process(const std::vector<double>& inputVector);
+};
+
+class xmmHmrTool : public xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM> {
+public:
+  xmmHmrTool(xmmToolConfig cfg = xmmToolConfig()) :
+  xmmTemporalTool<xmm::HMM, xmm::HierarchicalHMM>(cfg, true) {}
+  ~xmmHmrTool() {}
+
+  std::vector<double> process(const std::vector<double>& inputVector);
+};
+
+#endif /* _RAPID_XMM_TOOLS_H_ */