diff --git a/src/TactileStimulation/ovpCBoxAlgorithmTactileStimulator.cpp b/src/TactileStimulation/ovpCBoxAlgorithmTactileStimulator.cpp new file mode 100644 index 0000000..003076f --- /dev/null +++ b/src/TactileStimulation/ovpCBoxAlgorithmTactileStimulator.cpp @@ -0,0 +1,128 @@ +///------------------------------------------------------------------------------------------------- +/// +/// \file ovpCBoxAlgorithmTactileStimulator.cpp +/// \brief Functions of the Box Tactile Stimulator. +/// \author Tobias Baumann (TH-Nürnberg). +/// \version 1.0. +/// \date Mon Feb 21 14:59:56 2022. +/// \copyright GNU Affero General Public License v3.0. +/// +///------------------------------------------------------------------------------------------------- + +//includes +#include "ovpCBoxAlgorithmTactileStimulation.h" + +using namespace OpenViBE; +using namespace /*OpenViBE::*/Kernel; +using namespace /*OpenViBE::*/Plugins; +using namespace /*OpenViBE::Plugins::*/Tactilebci; + +bool CBoxAlgorithmTactileStimulation::initialize() +{ + m_input0Decoder.initialize(*this, 0); + m_output0Encoder.initialize(*this, 0); + + // If you need to retrieve setting values, use the FSettingValueAutoCast function. + // For example : + // - CString setting at index 0 in the setting list : + // CString sSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0); + // - unsigned int64 setting at index 1 in the setting list : + // uint64_t uiSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1); + // - double setting at index 2 in the setting list : + // double doubleSettingValue = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2); + // ... + + return true; +} +/*******************************************************************************/ + +bool CBoxAlgorithmTactileStimulation::uninitialize() +{ + m_input0Decoder.uninitialize(); + m_output0Encoder.uninitialize(); + + return true; +} +/*******************************************************************************/ + + +bool CBoxAlgorithmTactileStimulation::process() +{ + + // the static box context describes the box inputs, outputs, settings structures + const IBox& staticBoxContext=this->getStaticBoxContext(); + // the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks) + IBoxIO& boxContext = this->getDynamicBoxContext(); + + // here is some useful functions: + // - To get input/output/setting count: + // staticBoxContext.getInputCount(); + // staticBoxContext.getOutputCount(); + + // - To get the number of chunks currently available on a particular input : + // boxContext.getInputChunkCount(input_index) + + // - To send an output chunk : + // boxContext.markOutputAsReadyToSend(output_index, chunk_start_time, chunk_end_time); + + + // A typical process iteration may look like this. + // This example only iterate over the first input of type Signal, and output a modified Signal. + // thus, the box uses 1 decoder (m_signalDecoder) and 1 encoder (m_signalEncoder) + /* + IBoxIO& boxContext = this->getDynamicBoxContext(); + + //iterate over all chunk on input 0 + for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i) + { + // decode the chunk i + m_signalDecoder.decode(i); + // the decoder may have decoded 3 different parts : the header, a buffer or the end of stream. + if(m_signalDecoder.isHeaderReceived()) + { + // Header received. This happens only once when pressing "play". For example with a StreamedMatrix input, you now know the dimension count, sizes, and labels of the matrix + // ... maybe do some process ... + + // Pass the header to the next boxes, by encoding a header on the output 0: + m_signalEncoder.encodeHeader(0); + // send the output chunk containing the header. The dates are the same as the input chunk: + boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i)); + } + if(m_signalDecoder.isBufferReceived()) + { + // Buffer received. For example the signal values + // Access to the buffer can be done thanks to : + CMatrix* matrix = m_signalDecoder.getOutputMatrix(); // the StreamedMatrix of samples. + uint64_t frequency = m_signalDecoder.getOutputSamplingRate(); // the sampling rate of the signal + + // ... do some process on the matrix ... + + // Encode the output buffer : + m_signalEncoder.encodeBuffer(0); + // and send it to the next boxes : + boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i)); + + } + if(m_signalDecoder.isEndReceived()) + { + // End of stream received. This happens only once when pressing "stop". Just pass it to the next boxes so they receive the message : + m_signalEncoder.encodeEnd(0); + boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i)); + } + + // The current input chunk has been processed, and automaticcaly discarded. + // you don't need to call "boxContext.markInputAsDeprecated(0, i);" + } + */ + + // check the official developer documentation webpage for more example and information : + + // Tutorials: + // http://openvibe.inria.fr/documentation/#Developer+Documentation + // Codec Toolkit page : + // http://openvibe.inria.fr/codec-toolkit-references/ + + // Feel free to ask experienced developers on the forum (http://openvibe.inria.fr/forum) and IRC (#openvibe on irc.freenode.net). + + return true; +} diff --git a/src/TactileStimulation/ovpCBoxAlgorithmTactileStimulator.h b/src/TactileStimulation/ovpCBoxAlgorithmTactileStimulator.h new file mode 100644 index 0000000..207b654 --- /dev/null +++ b/src/TactileStimulation/ovpCBoxAlgorithmTactileStimulator.h @@ -0,0 +1,107 @@ +///------------------------------------------------------------------------------------------------- +/// +/// \file ovpCBoxAlgorithmTactileStimulator.h +/// \brief Classes of the Box Tactile Stimulator. +/// \author Tobias Baumann (TH-Nürnberg). +/// \version 1.0. +/// \date Mon Feb 21 14:59:56 2022. +/// \copyright GNU Affero General Public License v3.0. +/// +///------------------------------------------------------------------------------------------------- + +//includes +#pragma once + +#include "../ovp_defines.h" +#include +#include +#include + +namespace OpenViBE +{ + namespace Plugins + { + namespace Tactilebci + { + /// The class CBoxAlgorithmTactileStimulator describes the box Tactile Stimulator. + class CBoxAlgorithmTactileStimulation final : virtual public Toolkit::TBoxAlgorithm + { + public: + void release() override { delete this; } + + bool initialize() override; + bool uninitialize() override; + + //Here is the different process callbacks possible + // - On clock ticks : + //bool processClock(Kernel::CMessageClock& msg) override; + // - On new input received (the most common behaviour for signal processing) : + //bool processInput(const size_t index) override; + + // If you want to use processClock, you must provide the clock frequency. + //uint64_t getClockFrequency() override; + + bool process() override; + + // As we do with any class in openvibe, we use the macro below to associate this box to an unique identifier. + // The inheritance information is also made available, as we provide the superclass Toolkit::TBoxAlgorithm < IBoxAlgorithm > + _IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm, OVP_ClassId_BoxAlgorithm_TactileStimulation) + + protected: + // Input decoder: + Toolkit::TStimulationDecoder m_input0Decoder; + // Output decoder: + Toolkit::TStimulationEncoder m_output0Encoder; + + }; + + /// Descriptor of the box Tactile Stimulator. + class CBoxAlgorithmTactileStimulationDesc final : virtual public IBoxAlgorithmDesc + { + public: + + void release() override { } + + CString getName() const override { return CString("Tactile Stimulation"); } + CString getAuthorName() const override { return CString("Tobias Baumann"); } + CString getAuthorCompanyName() const override { return CString("TH-Nürnberg"); } + CString getShortDescription() const override { return CString("Controls the Tactilos on the Lattepanda GPIOs"); } + CString getDetailedDescription() const override { return CString(""); } + CString getCategory() const override { return CString("TactileBCI"); } + CString getVersion() const override { return CString("1.0"); } + CString getStockItemName() const override { return CString("gtk-network"); } + + CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_TactileStimulator; } + IPluginObject* create() override { return new CBoxAlgorithmTactileStimulator; } + + /* + IBoxListener* createBoxListener() const override { return new CBoxAlgorithmTactileStimulatorListener; } + void releaseBoxListener(IBoxListener* listener) const override { delete listener; } + */ + bool getBoxPrototype(Kernel::IBoxProto& prototype) const override + { + prototype.addInput("StimInput",OV_TypeId_Stimulations); + + //prototype.addFlag(Kernel::BoxFlag_CanModifyInput); + //prototype.addFlag(Kernel::BoxFlag_CanAddInput); + + prototype.addOutput("StimOutput",OV_TypeId_Stimulations); + + //prototype.addFlag(Kernel::BoxFlag_CanModifyOutput); + //prototype.addFlag(Kernel::BoxFlag_CanAddOutput); + + //No setting specified.To add settings use : + //prototype.addSetting("SettingName",OV_TypeId_XXXX,"default value"); + + //prototype.addFlag(Kernel::BoxFlag_CanModifySetting); + //prototype.addFlag(Kernel::BoxFlag_CanAddSetting); + + prototype.addFlag(OV_AttributeId_Box_FlagIsUnstable); + + return true; + } + _IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_TactileStimulationDesc) + }; + } // namespace Tactilebci + } // namespace Plugins +} // namespace OpenViBE