Program Listing for File multichannelfilter.cpp

Return to documentation for file (processors/multichannelfilter/multichannelfilter.cpp)

// ---------------------------------------------------------------------
// This file is part of falcon-core.
//
// Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders
//
// Falcon-server is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Falcon-server is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
// ---------------------------------------------------------------------

#include "multichannelfilter.hpp"

#include <chrono>
#include <exception>
#include <string>
#include <thread>

MultiChannelFilter::MultiChannelFilter() : IProcessor() {
  add_option("filter", filter_def_, "Filter definition.", true);
}

void MultiChannelFilter::Configure(const GlobalContext &context) {
  if (!filter_def_()["file"]) {
    filter_template_.reset(dsp::filter::construct_from_yaml(filter_def_()));
  } else {
    std::string f = context.resolve_path(
        filter_def_()["file"].as<std::string>(), "filters");
    filter_template_.reset(dsp::filter::construct_from_file(f));
  }
}

void MultiChannelFilter::CreatePorts() {
  data_in_port_ = create_input_port<MultiChannelType<double>>(
      "data", MultiChannelType<double>::Capabilities(ChannelRange(1, MAX_NCHANNELS)),
      PortInPolicy(SlotRange(0, MAX_NCHANNELS)));

  data_out_port_ = create_output_port<MultiChannelType<double>>(
      "data", MultiChannelType<double>::Capabilities(ChannelRange(1, MAX_NCHANNELS)),
      MultiChannelType<double>::Parameters(), PortOutPolicy(SlotRange(0, MAX_NCHANNELS)));
}

void MultiChannelFilter::CompleteStreamInfo() {
  // check if we have the same number of input and output slots
  if (data_in_port_->number_of_slots() != data_out_port_->number_of_slots()) {
    auto err_msg = "Number of output slots (" +
                   std::to_string(data_out_port_->number_of_slots()) +
                   ") on port '" + data_out_port_->name() +
                   "' does not match number of input slots (" +
                   std::to_string(data_in_port_->number_of_slots()) +
                   ") on port '" + data_in_port_->name() + "'.";
    throw ProcessingStreamInfoError(err_msg, name());
  }

  for (int k = 0; k < data_in_port_->number_of_slots(); ++k) {
    data_out_port_->streaminfo(k).set_stream_rate(
        data_in_port_->streaminfo(k).stream_rate());
    data_out_port_->streaminfo(k).set_parameters(
        data_in_port_->streaminfo(k).parameters());
  }
}

void MultiChannelFilter::Prepare(GlobalContext &context) {
  // realize filter for each input slot, dependent on the number of channels
  // upstream is sending
  filters_.clear();
  for (int k = 0; k < data_in_port_->number_of_slots(); ++k) {
    filters_.push_back(std::move(
        std::unique_ptr<dsp::filter::IFilter>(filter_template_->clone())));
    filters_.back()->realize(
        data_in_port_->streaminfo(k).parameters().nchannels);
  }
}

void MultiChannelFilter::Process(ProcessingContext &context) {
  MultiChannelType<double>::Data *data_in = nullptr;
  MultiChannelType<double>::Data *data_out = nullptr;
  auto nslots = data_in_port_->number_of_slots();
  decltype(nslots) k = 0;

  while (!context.terminated()) {
    // go through all slots
    for (k = 0; k < nslots; ++k) {
      // retrieve new data
      if (!data_in_port_->slot(k)->RetrieveData(data_in)) {
        break;
      }

      // claim output data buckets
      data_out = data_out_port_->slot(k)->ClaimData(false);

      // filter incoming data
      filters_[k]->process_by_channel(data_in->nsamples(), data_in->data(),
                                      data_out->data());

      data_out->set_sample_timestamps(data_in->sample_timestamps());
      data_out->CloneTimestamps(*data_in);

      // publish and release data
      data_out_port_->slot(k)->PublishData();
      data_in_port_->slot(k)->ReleaseData();
    }
  }
}

REGISTERPROCESSOR(MultiChannelFilter)