This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,51 @@
PROJECT(openvibe-plugins-sdk-file-io)
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
SET(PROJECT_VERSION_MINOR ${OV_GLOBAL_VERSION_MINOR})
SET(PROJECT_VERSION_PATCH ${OV_GLOBAL_VERSION_PATCH})
SET(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.c src/*.h src/*.hpp src/*.inl)
LIST(REMOVE_ITEM SRC_FILES
src/box-algorithms/csv/ovpCBoxAlgorithmCSVFileReader.cpp
src/box-algorithms/csv/ovpCBoxAlgorithmCSVFileWriter.cpp
src/box-algorithms/csv/ovpCBoxAlgorithmCSVFileReader.h
src/box-algorithms/csv/ovpCBoxAlgorithmCSVFileWriter.h)
INCLUDE("FindSourceRCProperties")
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
FOLDER ${PLUGINS_FOLDER}
COMPILE_FLAGS "-DOVP_Exports -DOVP_Shared -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE")
# ---------------------------------
INCLUDE("FindOpenViBE")
INCLUDE("FindOpenViBECommon")
INCLUDE("FindOpenViBEToolkit")
INCLUDE("FindOpenViBEModuleCSV")
INCLUDE("FindOpenViBEModuleEBML")
INCLUDE("FindOpenViBEModuleXML")
INCLUDE("FindOpenViBEModuleFS")
INCLUDE("FindThirdPartyBoost")
INCLUDE("FindThirdPartyXerces")
# ---------------------------------
# Target macros
# Defines target operating system, architecture and compiler
# ---------------------------------
SET_BUILD_PLATFORM()
# -----------------------------
# Install files
# -----------------------------
INSTALL(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${DIST_BINDIR}
LIBRARY DESTINATION ${DIST_LIBDIR}
ARCHIVE DESTINATION ${DIST_LIBDIR})
INSTALL(DIRECTORY box-tutorials DESTINATION ${DIST_DATADIR}/openvibe/scenarios/)
INSTALL(DIRECTORY signals DESTINATION ${DIST_DATADIR}/openvibe/scenarios/)
INSTALL(DIRECTORY electrode_sets DESTINATION ${DIST_DATADIR}/openvibe/)
@@ -0,0 +1,367 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>2.2.0</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x00004a40, 0x0000585c)</Identifier>
<Name>Continuous Oscilloscope</Name>
<AlgorithmClassIdentifier>(0x0842bcd1, 0xd53c1c89)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Matrix</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Markers</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Channel Localisation</Name>
<DefaultValue>${AdvancedViz_ChannelLocalisation}</DefaultValue>
<Value>${AdvancedViz_ChannelLocalisation}</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x8f02e3f6, 0xffb00f4b)</TypeIdentifier>
<Name>Temporal Coherence</Name>
<DefaultValue>Time Locked</DefaultValue>
<Value>Time Locked</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Time Scale</Name>
<DefaultValue>20</DefaultValue>
<Value>20</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Matrix Count</Name>
<DefaultValue>50</DefaultValue>
<Value>50</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Positive Data Only ?</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Gain</Name>
<DefaultValue>1</DefaultValue>
<Value>0.01</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Caption</Name>
<DefaultValue></DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Translucency</Name>
<DefaultValue>1</DefaultValue>
<Value>1</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x7f45a2a9, 0x7db12219)</TypeIdentifier>
<Name>Color</Name>
<DefaultValue>${AdvancedViz_DefaultColor}</DefaultValue>
<Value>${AdvancedViz_DefaultColor}</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>288</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>368</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x35390ab5, 0x7b926078)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>9</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00006ffa, 0x000071a0)</Identifier>
<Name>Temporal Filter</Name>
<AlgorithmClassIdentifier>(0xb4f9d042, 0x9d79f2e5)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Input signal</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Output signal</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x2f2c606c, 0x8512ed68)</TypeIdentifier>
<Name>Filter Method</Name>
<DefaultValue>Butterworth</DefaultValue>
<Value>Butterworth</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0xfa20178e, 0x4cba62e9)</TypeIdentifier>
<Name>Filter Type</Name>
<DefaultValue>Band Pass</DefaultValue>
<Value>Band Pass</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Filter Order</Name>
<DefaultValue>4</DefaultValue>
<Value>4</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Low Cut-off Frequency (Hz)</Name>
<DefaultValue>1</DefaultValue>
<Value>1</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>High Cut-off Frequency (Hz)</Name>
<DefaultValue>40</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Band Pass Ripple (dB)</Name>
<DefaultValue>0.5</DefaultValue>
<Value>0.5</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>128</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>320</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x27a4ceec, 0x876d6384)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>6</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x557489da, 0x7f18ab2b)</Identifier>
<Name>Generic stream reader</Name>
<AlgorithmClassIdentifier>(0x6468099f, 0x0370095a)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x403488e7, 0x565d70b6)</TypeIdentifier>
<Name>Output stream 1</Name>
</Output>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Output stream 2</Name>
</Output>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Output stream 3</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Filename</Name>
<DefaultValue></DefaultValue>
<Value>${Path_Data}/scenarios/signals/bci-motor-imagery.ov</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>32</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>352</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xf37b8e7a, 0x1bc33e4e)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc46b3d00, 0x3e0454e1)</Identifier>
<Value>(0x00000000, 0x00b124ce)</Value>
</Attribute>
</Attributes>
</Box>
</Boxes>
<Links>
<Link>
<Identifier>(0x0000003a, 0x0000396d)</Identifier>
<Source>
<BoxIdentifier>(0x557489da, 0x7f18ab2b)</BoxIdentifier>
<BoxOutputIndex>2</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00004a40, 0x0000585c)</BoxIdentifier>
<BoxInputIndex>1</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00001785, 0x00002d8f)</Identifier>
<Source>
<BoxIdentifier>(0x00006ffa, 0x000071a0)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00004a40, 0x0000585c)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x000045ee, 0x000074b2)</Identifier>
<Source>
<BoxIdentifier>(0x557489da, 0x7f18ab2b)</BoxIdentifier>
<BoxOutputIndex>1</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00006ffa, 0x000071a0)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x0000761e, 0x00005eae)</Identifier>
<Text>The &lt;i&gt;Temporal Filter&lt;/i&gt; enables
us to center data around 0 by removing
low frequencies.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>592</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>144</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x0afa52e5, 0x7e02009b)</Identifier>
<Text>The &lt;i&gt;Continuous Oscilloscope&lt;/i&gt; box displays
the content of the file.
You might need to &lt;b&gt;right click and drag up or down&lt;/b&gt;
in order to zoom to the signal.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>624</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>256</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x3198ee95, 0x3397262b)</Identifier>
<Text>You can browse each box' documentation by selecting the box and pressing &lt;b&gt;F1&lt;/b&gt;</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>480</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>384</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x52401569, 0x4c3a5e29)</Identifier>
<Text>The &lt;i&gt;&lt;b&gt;Generic Stream Reader&lt;/b&gt;&lt;/i&gt; box
reads an &lt;i&gt;OpenViBE&lt;/i&gt; file from disk and sends
its content to the following box.
The &lt;i&gt;OpenViBE&lt;/i&gt; file format can store any
stream of the NeuroRT platform.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>608</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>48</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x0000775c, 0x000078ff)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0x00004a40, 0x0000585c)","childCount":0,"identifier":"(0x00005da3, 0x00007534)","parentIdentifier":"(0xffffffff, 0xffffffff)","type":3},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":1,"identifier":"(0x0509f2db, 0x6d6aaba8)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":1},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x748521de, 0x4b35cf59)","index":0,"name":"Default tab","parentIdentifier":"(0x0509f2db, 0x6d6aaba8)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x06d9aa6d, 0x7f11c5f6)","index":0,"name":"Empty","parentIdentifier":"(0x748521de, 0x4b35cf59)","type":0}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>
@@ -0,0 +1,60 @@
/**
* \page BoxAlgorithm_CSVFileReader CSV File Reader
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Description|
This box reads a Comma Separated Values (CSV) text file. The file must be written using a specific
OpenViBE convention. The format is described in detail in \ref Doc_BoxAlgorithm_CSVFileWriter
The file can contain two streams, one for matrix-type data and one for stimulations.
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Description|
__________________________________________________________________
Outputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Outputs|
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Outputs|
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Output1|
This output can carry Signal, Streamed Matrix, Covariance, Spectrum and Feature Vector data.
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Output1|
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Output2|
This output will contain stimulations read from the file.
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Output2|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Settings|
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Settings|
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Setting1|
Path of the CSV file to read.
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Setting1|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Examples|
Example of a scenario using the CSV Reader box to read a signal file and display it using an Oscilloscope.
\image html csv-file-reader-example.png "Reading a CSV file"
\image latex csv-file-reader-example.png "Reading a CSV file" width=8cm
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileReader_Miscellaneous|
* |OVP_DocEnd_BoxAlgorithm_CSVFileReader_Miscellaneous|
*/
@@ -0,0 +1,151 @@
/**
* \page BoxAlgorithm_CSVFileWriter CSV File Writer
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Description|
This box writes incoming time series along with a stimulation stream into a text file using the
Comma Separated Values format conforming to the RFC 4180 format.
The header of the CSV file contains some additional information that enables additional features
during subsequent reading. This format is described in the \ref Doc_BoxAlgorithm_CSVFileWriter_Miscellaneous
section.
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Description|
__________________________________________________________________
Inputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Inputs|
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Inputs|
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Input1|
Time series input, this can be either a Signal, Streamed Matrix, Spectrum, Covariance Matrix or Feature Vector stream.
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Input1|
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Input2|
Stimulations to be written alongside the signal.
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Input2|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Settings|
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Settings|
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Setting1|
Path of the CSV file to be written.
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Setting1|
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Setting2|
Precision, in number of decimal digits, of the resulting data. For longer data the precision can significantly impact the file size.
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Setting2|
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Setting3|
By default this box will overwrite data in the file if it exists. If this setting is set to true, the box will append data to the file instead. If the file is empty a header will be added as well. It is up to the user to ensure herself that the data written is of the same type and dimensions.
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Setting3|
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Setting4|
If this setting is activated, only the last received matrix will be written to the file. This can be used, for example, with cumulative average box.
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Setting4|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Examples|
Example of writing a spectrum into a CSV file:
\image html csv-file-writer-example.png "Writing a CSV file"
\image latex csv-file-writer-example.png "Writing a CSV file" width=8cm
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_CSVFileWriter_Miscellaneous|
The CSV Format
## Example file containing Signal data and Stimulations
Signal file sampled at 8Hz, with epochs of 0.5s length. Note that the timestamps do not have an end time which is implicit.
In this example each x represents an arbitrary floating point value. The header contains the following rows:
- Time:8Hz - contains the timestamp of each sample, this label also encodes the original sampling rate
- Epoch - contains the number of the epoch in which each sample is contained, this allows encoding even overlapping signal
- O1, O2, Pz, P3, P4 - channels containing EEG data
- Event Id - contains a colon separated list of StimulationIds
- Event Date - contains the same number of timestamps
- Event Duration - is constructed in the same manner as Event Date
\code{.unparsed}
Time:8Hz,Epoch,O1,O2,Pz,P3,P4,Event Id,Event Date,Event Duration
0.00000,0,x,x,x,x,x,,,
0.12500,0,x,x,x,x,x,,,
0.25000,0,x,x,x,x,x,32000:32010,0.25000:0.25000,0:0
0.37500,0,x,x,x,x,x,,,
0.50000,1,x,x,x,x,x,,,
0.62500,1,x,x,x,x,x,,,
0.75000,1,x,x,x,x,x,35000,0.75250,0
0.87500,1,x,x,x,x,x,,,
\endcode
## Example file containing a three dimensional matrix
This example file contains 2x2x2 matrices produced every 0.125 seconds and spanning one second.
The labels for this matrix are:
- for first dimension "LA", "LB"
- for second dimension "1", "2"
- for third dimension "X", "Y"
\code{.unparsed}
Time:2x2x2,End Time,LA:1:X,LA:1:Y,LA:2:X,LA:2:Y,LB:1:X,...,LB:2:Y,Event Id,Event Date,Event Duration
0.00000,1.00000,x,x,x,x,x,...,x,,,
0.12500,1.12500,x,x,x,x,x,...,x,,,
0.25000,1.25000,x,x,x,x,x,...,x,,,
0.37500,1.37500,x,x,x,x,x,...,x,,,
0.50000,1.50000,x,x,x,x,x,...,x,,,
0.62500,1.62500,x,x,x,x,x,...,x,,,
0.75000,1.75000,x,x,x,x,x,...,x,,,
0.87500,1.62500,x,x,x,x,x,...,x,,,
1.00000,2.00000,x,x,x,x,x,...,x,,,
1.12500,2.12500,x,x,x,x,x,...,x,,,
\endcode
\note
A label can be an empty string. If second dimension had an empty label then the first column would have label "LA::X", if it were the third dimension the column would have label "LA:1:"
## Example file containing a spectrum
Spectrum file with 2 channels, 128Hz signal and spectra calculated on periods of 1 second every 0.125 seconds. The last element in the Time column (128) represents the original sampling rate.
\code{.unparsed}
Time:2x64:128,End Time,O1:0,O1:1.015873,...,O1:64,O2:0,...,O2:64,Event Id,Event Date,Event Duration
0.00000,1.00000,x,x,...,x,x,...,x,,,
0.12500,1.12500,x,x,...,x,x,...,x,,,
0.25000,1.25000,x,x,...,x,x,...,x,,,
0.37500,1.37500,x,x,...,x,x,...,x,,,
0.50000,1.50000,x,x,...,x,x,...,x,,,
0.62500,1.62500,x,x,...,x,x,...,x,,,
0.75000,1.75000,x,x,...,x,x,...,x,,,
0.87500,1.87500,x,x,...,x,x,...,x,,,
1.00000,2.00000,x,x,...,x,x,...,x,,,
1.12500,2.12500,x,x,...,x,x,...,x,,,
\endcode
* |OVP_DocEnd_BoxAlgorithm_CSVFileWriter_Miscellaneous|
*/
@@ -0,0 +1,57 @@
/**
* \page BoxAlgorithm_ElectrodeLocalisationFileReader Electrode localisation file reader
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ElectrodeLocalisationFileReader_Description|
* This box loads files holding the normalized coordinates of an electrode set.
* |OVP_DocEnd_BoxAlgorithm_ElectrodeLocalisationFileReader_Description|
__________________________________________________________________
Outputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ElectrodeLocalisationFileReader_Outputs|
* |OVP_DocEnd_BoxAlgorithm_ElectrodeLocalisationFileReader_Outputs|
* |OVP_DocBegin_BoxAlgorithm_ElectrodeLocalisationFileReader_Output1|
* The output channel localization information.
* |OVP_DocEnd_BoxAlgorithm_ElectrodeLocalisationFileReader_Output1|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ElectrodeLocalisationFileReader_Settings|
* |OVP_DocEnd_BoxAlgorithm_ElectrodeLocalisationFileReader_Settings|
* |OVP_DocBegin_BoxAlgorithm_ElectrodeLocalisationFileReader_Setting1|
* The normalized coordinates file.
* |OVP_DocEnd_BoxAlgorithm_ElectrodeLocalisationFileReader_Setting1|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ElectrodeLocalisationFileReader_Examples|
* A default electrode set should be included in your BRAND_NAME distribution. Look for
* it in the <tt>share/electrode_sets</tt> directory of the source tree of this plugin.
* It comes as a \ref Doc_MatrixFileFormat "text file" which is quite self explanatory,
* open it in a text editor to edit it. Electrode names are specified in the header
* section of the matrix, while actual coordinates are stored in the buffer section.
* |OVP_DocEnd_BoxAlgorithm_ElectrodeLocalisationFileReader_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ElectrodeLocalisationFileReader_Miscellaneous|
* The coordinates loaded by this box are sent once only (static coordinates, e.g. EEG), as
* opposed to regularly (dynamic coordinates, e.g. MEG).
* The supported file format is the \ref Doc_MatrixFileFormat "BRAND_NAME matrix" file format.
* Electrode coordinates must be normalized cartesian coordinates in the following frame
* of reference : X right, Y front and Z up.
* |OVP_DocEnd_BoxAlgorithm_ElectrodeLocalisationFileReader_Miscellaneous|
*/
@@ -0,0 +1,56 @@
/**
* \page BoxAlgorithm_GenericStreamReader Generic stream reader
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamReader_Description|
This box is able to read any file saved with the \ref Doc_BoxAlgorithm_GenericStreamWriter box.
It is interesting to notice that such file can contain a variable number of streams. Therefore,
the user is able to add and modify any output he wants on the box. The box does not supposes
anything on the streams contained in the file during authoring in the designer. The streams of
the file are mapped to created output at runtime in an "intelligent way" depending on there types.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamReader_Description|
__________________________________________________________________
Outputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamReader_Outputs|
This box can have as many output you want depending on the content of the file.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamReader_Outputs|
* |OVP_DocBegin_BoxAlgorithm_GenericStreamReader_Output1|
This is the default output.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamReader_Output1|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamReader_Settings|
* |OVP_DocEnd_BoxAlgorithm_GenericStreamReader_Settings|
* |OVP_DocBegin_BoxAlgorithm_GenericStreamReader_Setting1|
This setting points to the file to read. This file may contain a variable number of multiplexed
streams. Those streams will be mapped to corresponding outputs at runtime. The mapping is done in
an "intelligent way" because it reorders the streams contained in the file to match the types of
the outputs. If a stream from the file does not find a matching output, a warning is launched.
If an output does not find a matching stream from the file, a warning is also launched.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamReader_Setting1|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamReader_Examples|
* |OVP_DocEnd_BoxAlgorithm_GenericStreamReader_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamReader_Miscellaneous|
* |OVP_DocEnd_BoxAlgorithm_GenericStreamReader_Miscellaneous|
*/
@@ -0,0 +1,60 @@
/**
* \page BoxAlgorithm_GenericStreamWriter Generic stream writer
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Description|
This box is able to dump any OpenViBE stream into a binary file. In the cacse where this box
would have multiple inputs, the streams would be multiplexed in the file. Such file can
be read back with the \ref Doc_BoxAlgorithm_GenericStreamReader
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Description|
__________________________________________________________________
Inputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Inputs|
You can add any input you want to this box depending on the number of streams you want to dump.
In the cacse where this box would have multiple inputs, the streams would be multiplexed in the file.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Inputs|
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Input1|
The default input.
<b>Note: it important to correctly configure the type of the inputs</b>. That information will be
used by the \ref Doc_BoxAlgorithm_GenericStreamReader to map the contained streams to its outputs.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Input1|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Settings|
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Settings|
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Setting1|
This setting points to the file to write the streams to.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Setting1|
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Setting2|
Thanks to this setting, you can use compression on each input stream. This means that the basic
structure of the file remains uncompressed but that each stream inside this structure is compressed.
<b>Note: this is not implemented at the moment</b>.
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Setting2|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Examples|
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_GenericStreamWriter_Miscellaneous|
* |OVP_DocEnd_BoxAlgorithm_GenericStreamWriter_Miscellaneous|
*/
@@ -0,0 +1,66 @@
.. _Doc_BoxAlgorithm_CSVFileReader:
CSV File Reader
===============
.. container:: attribution
:Author:
Victor Herlin
:Company:
Mensia Technologies SA
.. image:: images/Doc_BoxAlgorithm_CSVFileReader.png
This box reads a Comma Separated Values (CSV) text file. The file must be written using a specific
OpenViBE convention. The format is described in detail in :ref:`Doc_BoxAlgorithm_CSVFileWriter`
The file can contain two streams, one for matrix-type data and one for stimulations.
Outputs
-------
.. csv-table::
:header: "Output Name", "Stream Type"
"Output stream", "Signal"
"Output stimulation", "Stimulations"
Output stream
~~~~~~~~~~~~~
This output can carry Signal, Streamed Matrix, Covariance, Spectrum and Feature Vector data.
Output stimulation
~~~~~~~~~~~~~~~~~~
This output will contain stimulations read from the file.
.. _Doc_BoxAlgorithm_CSVFileReader_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Filename", "Filename", ""
Filename
~~~~~~~~
Path of the CSV file to read.
.. _Doc_BoxAlgorithm_CSVFileReader_Examples:
Examples
--------
Example of a scenario using the CSV Reader box to read a signal file and display it using an Oscilloscope.
.. figure:: images/csv-file-reader-example.png
:alt: Reading a CSV file
:align: center
Reading a CSV file
@@ -0,0 +1,175 @@
.. _Doc_BoxAlgorithm_CSVFileWriter:
CSV File Writer
===============
.. container:: attribution
:Author:
Victor Herlin
:Company:
Mensia Technologies SA
.. image:: images/Doc_BoxAlgorithm_CSVFileWriter.png
This box writes incoming time series along with a stimulation stream into a text file using the
Comma Separated Values format conforming to the RFC 4180 format.
The header of the CSV file contains some additional information that enables additional features
during subsequent reading. This format is described in the :ref:`Doc_BoxAlgorithm_CSVFileWriter_Miscellaneous`
section.
Inputs
------
.. csv-table::
:header: "Input Name", "Stream Type"
"Input stream", "Signal"
"Stimulations stream", "Stimulations"
Input stream
~~~~~~~~~~~~
Time series input, this can be either a Signal, Streamed Matrix, Spectrum, Covariance Matrix or Feature Vector stream.
Stimulations stream
~~~~~~~~~~~~~~~~~~~
Stimulations to be written alongside the signal.
.. _Doc_BoxAlgorithm_CSVFileWriter_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Filename", "Filename", ""
"Precision", "Integer", "10"
"Append data", "Boolean", "false"
"Only last matrix", "Boolean", "false"
Filename
~~~~~~~~
Path of the CSV file to be written.
- Default value : [ *record-[$core{date}-$core{time}].csv* ]
Precision
~~~~~~~~~
Precision, in number of decimal digits, of the resulting data. For longer data the precision can significantly impact the file size.
Append data
~~~~~~~~~~~
By default this box will overwrite data in the file if it exists. If this setting is set to true, the box will append data to the file instead. If the file is empty a header will be added as well. It is up to the user to ensure herself that the data written is of the same type and dimensions.
Only last matrix
~~~~~~~~~~~~~~~~
If this setting is activated, only the last received matrix will be written to the file. This can be used, for example, with cumulative average box.
.. _Doc_BoxAlgorithm_CSVFileWriter_Examples:
Examples
--------
Example of writing a spectrum into a CSV file:
.. figure:: images/csv-file-writer-example.png
:alt: Writing a CSV file
:align: center
Writing a CSV file
.. _Doc_BoxAlgorithm_CSVFileWriter_Miscellaneous:
Miscellaneous
-------------
The CSV Format
## Example file containing Signal data and Stimulations
Signal file sampled at 8Hz, with epochs of 0.5s length. Note that the timestamps do not have an end time which is implicit.
In this example each x represents an arbitrary floating point value. The header contains the following rows:
- Time:8Hz - contains the timestamp of each sample, this label also encodes the original sampling rate
- Epoch - contains the number of the epoch in which each sample is contained, this allows encoding even overlapping signal
- O1, O2, Pz, P3, P4 - channels containing EEG data
- Event Id - contains a colon separated list of StimulationIds
- Event Date - contains the same number of timestamps
- Event Duration - is constructed in the same manner as Event Date
.. code::
Time:8Hz,Epoch,O1,O2,Pz,P3,P4,Event Id,Event Date,Event Duration
0.00000,0,x,x,x,x,x,,,
0.12500,0,x,x,x,x,x,,,
0.25000,0,x,x,x,x,x,32000:32010,0.25000:0.25000,0:0
0.37500,0,x,x,x,x,x,,,
0.50000,1,x,x,x,x,x,,,
0.62500,1,x,x,x,x,x,,,
0.75000,1,x,x,x,x,x,35000,0.75250,0
0.87500,1,x,x,x,x,x,,,
## Example file containing a three dimensional matrix
This example file contains 2x2x2 matrices produced every 0.125 seconds and spanning one second.
The labels for this matrix are:
- for first dimension "LA", "LB"
- for second dimension "1", "2"
- for third dimension "X", "Y"
.. code::
Time:2x2x2,End Time,LA:1:X,LA:1:Y,LA:2:X,LA:2:Y,LB:1:X,...,LB:2:Y,Event Id,Event Date,Event Duration
0.00000,1.00000,x,x,x,x,x,...,x,,,
0.12500,1.12500,x,x,x,x,x,...,x,,,
0.25000,1.25000,x,x,x,x,x,...,x,,,
0.37500,1.37500,x,x,x,x,x,...,x,,,
0.50000,1.50000,x,x,x,x,x,...,x,,,
0.62500,1.62500,x,x,x,x,x,...,x,,,
0.75000,1.75000,x,x,x,x,x,...,x,,,
0.87500,1.62500,x,x,x,x,x,...,x,,,
1.00000,2.00000,x,x,x,x,x,...,x,,,
1.12500,2.12500,x,x,x,x,x,...,x,,,
\note
A label can be an empty string. If second dimension had an empty label then the first column would have label "LA::X", if it were the third dimension the column would have label "LA:1:"
## Example file containing a spectrum
Spectrum file with 2 channels, 128Hz signal and spectra calculated on periods of 1 second every 0.125 seconds. The last element in the Time column (128) represents the original sampling rate.
.. code::
Time:2x64:128,End Time,O1:0,O1:1.015873,...,O1:64,O2:0,...,O2:64,Event Id,Event Date,Event Duration
0.00000,1.00000,x,x,...,x,x,...,x,,,
0.12500,1.12500,x,x,...,x,x,...,x,,,
0.25000,1.25000,x,x,...,x,x,...,x,,,
0.37500,1.37500,x,x,...,x,x,...,x,,,
0.50000,1.50000,x,x,...,x,x,...,x,,,
0.62500,1.62500,x,x,...,x,x,...,x,,,
0.75000,1.75000,x,x,...,x,x,...,x,,,
0.87500,1.87500,x,x,...,x,x,...,x,,,
1.00000,2.00000,x,x,...,x,x,...,x,,,
1.12500,2.12500,x,x,...,x,x,...,x,,,
@@ -0,0 +1,66 @@
.. _Doc_BoxAlgorithm_ElectrodeLocalisationFileReader:
Electrode localisation file reader
==================================
.. container:: attribution
:Author:
Vincent Delannoy
:Company:
INRIA/IRISA
.. image:: images/Doc_BoxAlgorithm_ElectrodeLocalisationFileReader.png
This box loads files holding the normalized coordinates of an electrode set.
Outputs
-------
.. csv-table::
:header: "Output Name", "Stream Type"
"Channel localisation", "Channel localisation"
Channel localisation
~~~~~~~~~~~~~~~~~~~~
The output channel localization information.
.. _Doc_BoxAlgorithm_ElectrodeLocalisationFileReader_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Filename", "Filename", ""
Filename
~~~~~~~~
The normalized coordinates file.
.. _Doc_BoxAlgorithm_ElectrodeLocalisationFileReader_Examples:
Examples
--------
A default electrode set should be included in your NeuroRT distribution. Look for
it in the ``share/electrode_sets`` directory of the source tree of this plugin.
It comes as a :ref:`Doc_MatrixFileFormat` "text file" which is quite self explanatory,
open it in a text editor to edit it. Electrode names are specified in the header
section of the matrix, while actual coordinates are stored in the buffer section.
.. _Doc_BoxAlgorithm_ElectrodeLocalisationFileReader_Miscellaneous:
Miscellaneous
-------------
The coordinates loaded by this box are sent once only (static coordinates, e.g. EEG), as
opposed to regularly (dynamic coordinates, e.g. MEG).
The supported file format is the :ref:`Doc_MatrixFileFormat` "NeuroRT matrix" file format.
Electrode coordinates must be normalized cartesian coordinates in the following frame
of reference : X right, Y front and Z up.
@@ -0,0 +1,57 @@
.. _Doc_BoxAlgorithm_GenericStreamReader:
Generic stream reader
=====================
.. container:: attribution
:Author:
Yann Renard
:Company:
INRIA
.. image:: images/Doc_BoxAlgorithm_GenericStreamReader.png
Generic Stream Writer box can be used to store data in the format read by this box
This box is able to read any file saved with the :ref:`Doc_BoxAlgorithm_GenericStreamWriter` box.
It is interesting to notice that such file can contain a variable number of streams. Therefore,
the user is able to add and modify any output he wants on the box. The box does not supposes
anything on the streams contained in the file during authoring in the designer. The streams of
the file are mapped to created output at runtime in an "intelligent way" depending on there types.
Outputs
-------
.. csv-table::
:header: "Output Name", "Stream Type"
"Output Signal", "Signal"
"Output Stimulations", "Stimulations"
This box can have as many output you want depending on the content of the file.
Output Signal
~~~~~~~~~~~~~
This is the default output.
.. _Doc_BoxAlgorithm_GenericStreamReader_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Filename", "Filename", ""
Filename
~~~~~~~~
This setting points to the file to read. This file may contain a variable number of multiplexed
streams. Those streams will be mapped to corresponding outputs at runtime. The mapping is done in
an "intelligent way" because it reorders the streams contained in the file to match the types of
the outputs. If a stream from the file does not find a matching output, a warning is launched.
If an output does not find a matching stream from the file, a warning is also launched.
@@ -0,0 +1,65 @@
.. _Doc_BoxAlgorithm_GenericStreamWriter:
Generic stream writer
=====================
.. container:: attribution
:Author:
Yann Renard
:Company:
INRIA
.. image:: images/Doc_BoxAlgorithm_GenericStreamWriter.png
This box is able to dump any OpenViBE stream into a binary file. In the cacse where this box
would have multiple inputs, the streams would be multiplexed in the file. Such file can
be read back with the :ref:`Doc_BoxAlgorithm_GenericStreamReader`
Inputs
------
.. csv-table::
:header: "Input Name", "Stream Type"
"Input Signal", "Signal"
"Input Stimulations", "Stimulations"
You can add any input you want to this box depending on the number of streams you want to dump.
In the cacse where this box would have multiple inputs, the streams would be multiplexed in the file.
Input Signal
~~~~~~~~~~~~
The default input.
**Note: it important to correctly configure the type of the inputs**. That information will be
used by the :ref:`Doc_BoxAlgorithm_GenericStreamReader` to map the contained streams to its outputs.
.. _Doc_BoxAlgorithm_GenericStreamWriter_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Filename", "Filename", ""
"Use compression", "Boolean", "false"
Filename
~~~~~~~~
This setting points to the file to write the streams to.
- Default value : [ *record-[$core{date}-$core{time}].ov* ]
Use compression
~~~~~~~~~~~~~~~
Thanks to this setting, you can use compression on each input stream. This means that the basic
structure of the file remains uncompressed but that each stream inside this structure is compressed.
**Note: this is not implemented at the moment**.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

@@ -0,0 +1,232 @@
[
[ "O1" "O2" "T5" "P7" "P3" "Pz" "P4" "T6" "P8" "T3" "T7" "C3" "Cz" "C4" "T4" "T8" "F7" "F3" "Fz" "F4" "F8" "Fp1" "Fp2" "P5" "P1" "P2" "P6" "C5" "C1" "C2" "C6" "F5" "F1" "F2" "F6" "M1" "M2" "Oz" "POz" "CPz" "FCz" "FFz" "Fpz" "FC1" "FC2" "CP1" "CP2" "FC3" "FC4" "CP3" "CP4" "FT3" "FT4" "TP3" "TP4" "P'1" "P'2" "Nz" "I1" "Iz" "I2" "FF3" "TP5" "OT5" "IT1" "IT2" "IP1" "IPz" "IP2" "M'1" "M'2" "TP7" "TP8" "Nez" "F3z" "F4z" ]
["theta" "phi" ]
]
[
[90 252 ]
]
[
[90 288 ]
]
[
[90 216 ]
]
[
[63.1 223.1 ]
]
[
[63.1 223.1 ]
]
[
[45 270 ]
]
[
[63.1 316.9 ]
]
[
[90 324 ]
]
[
[90 324 ]
]
[
[90 180 ]
]
[
[90 180 ]
]
[
[45 180 ]
]
[
[0 0 ]
]
[
[45 0 ]
]
[
[90 0 ]
]
[
[90 0 ]
]
[
[90 144 ]
]
[
[63.1 136.9 ]
]
[
[45 90 ]
]
[
[63.1 43.1 ]
]
[
[90 36 ]
]
[
[90 108 ]
]
[
[90 72 ]
]
[
[76.5 219.3 ]
]
[
[51.7 243.7 ]
]
[
[51.7 296.3 ]
]
[
[76.5 320.7 ]
]
[
[67.5 180 ]
]
[
[22.5 180 ]
]
[
[22.5 0 ]
]
[
[67.5 0 ]
]
[
[76.5 140.7 ]
]
[
[51.7 116.3 ]
]
[
[51.7 63.7 ]
]
[
[76.5 39.3 ]
]
[
[120 215.6 ]
]
[
[120 324.4 ]
]
[
[90 270 ]
]
[
[67.5 270 ]
]
[
[22.5 270 ]
]
[
[22.5 90 ]
]
[
[67.5 90 ]
]
[
[90 90 ]
]
[
[31.5 136.9 ]
]
[
[31.5 43.1 ]
]
[
[31.5 223.1 ]
]
[
[31.5 316.9 ]
]
[
[52.1 155.8 ]
]
[
[52.1 24.2 ]
]
[
[52.1 204.2 ]
]
[
[52.1 335.8 ]
]
[
[75.6 159.7 ]
]
[
[75.6 20.3 ]
]
[
[75.6 200.3 ]
]
[
[75.6 339.7 ]
]
[
[52 241.3 ]
]
[
[52 298.7 ]
]
[
[112.5 90 ]
]
[
[120 234.4 ]
]
[
[112.5 270 ]
]
[
[120 305.6 ]
]
[
[33.2 135.6 ]
]
[
[66.5 201.2 ]
]
[
[77.4 241.8 ]
]
[
[102.6 241.8 ]
]
[
[102.6 298.2 ]
]
[
[87.6 247 ]
]
[
[78.8 270 ]
]
[
[87.6 293 ]
]
[
[105.4 203 ]
]
[
[105.4 337 ]
]
[
[90 198 ]
]
[
[90 342 ]
]
[
[118.1 90 ]
]
[
[63.4 113 ]
]
[
[63.4 67 ]
]
@@ -0,0 +1,31 @@
#include "ovpCAlgorithmOVMatrixFileReader.h"
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
bool CAlgorithmOVMatrixFileReader::initialize()
{
ip_sFilename.initialize(getInputParameter(OVP_Algorithm_OVMatrixFileReader_InputParameterId_Filename));
op_pMatrix.initialize(getOutputParameter(OVP_Algorithm_OVMatrixFileReader_OutputParameterId_Matrix));
return true;
}
bool CAlgorithmOVMatrixFileReader::uninitialize()
{
op_pMatrix.uninitialize();
ip_sFilename.uninitialize();
return true;
}
bool CAlgorithmOVMatrixFileReader::process()
{
OV_ERROR_UNLESS_KRF(Toolkit::Matrix::loadFromTextFile(*op_pMatrix, ip_sFilename->toASCIIString()),
"Reading matrix file " << *ip_sFilename << " failed", Kernel::ErrorType::BadFileRead);
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,54 @@
#pragma once
#include "../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CAlgorithmOVMatrixFileReader final : public Toolkit::TAlgorithm<IAlgorithm>
{
public:
void release() override { delete this; }
bool initialize() override;
bool uninitialize() override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TAlgorithm<IAlgorithm>, OVP_ClassId_Algorithm_OVMatrixFileReader)
protected:
Kernel::TParameterHandler<CString*> ip_sFilename;
Kernel::TParameterHandler<CMatrix*> op_pMatrix;
};
class CAlgorithmOVMatrixFileReaderDesc final : public IAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("OpenViBE Matrix file reader"); }
CString getAuthorName() const override { return CString("Vincent Delannoy"); }
CString getAuthorCompanyName() const override { return CString("INRIA/IRISA"); }
CString getShortDescription() const override { return CString(""); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing"); }
CString getVersion() const override { return CString("1.1"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_Algorithm_OVMatrixFileReader; }
IPluginObject* create() override { return new CAlgorithmOVMatrixFileReader; }
bool getAlgorithmPrototype(Kernel::IAlgorithmProto& prototype) const override
{
prototype.addInputParameter(OVP_Algorithm_OVMatrixFileReader_InputParameterId_Filename, "Filename", Kernel::ParameterType_String);
prototype.addOutputParameter(OVP_Algorithm_OVMatrixFileReader_OutputParameterId_Matrix, "Matrix", Kernel::ParameterType_Matrix);
return true;
}
_IsDerivedFromClass_Final_(IAlgorithmDesc, OVP_ClassId_Algorithm_OVMatrixFileReaderDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,31 @@
#include "ovpCAlgorithmOVMatrixFileWriter.h"
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
bool CAlgorithmOVMatrixFileWriter::initialize()
{
ip_sFilename.initialize(getInputParameter(OVP_Algorithm_OVMatrixFileWriter_InputParameterId_Filename));
ip_pMatrix.initialize(getInputParameter(OVP_Algorithm_OVMatrixFileWriter_InputParameterId_Matrix));
return true;
}
bool CAlgorithmOVMatrixFileWriter::uninitialize()
{
ip_sFilename.uninitialize();
ip_pMatrix.uninitialize();
return true;
}
bool CAlgorithmOVMatrixFileWriter::process()
{
OV_ERROR_UNLESS_KRF(Toolkit::Matrix::saveToTextFile(*ip_pMatrix, ip_sFilename->toASCIIString()),
"Writing matrix file " << *ip_sFilename << " failed", Kernel::ErrorType::BadFileWrite);
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,54 @@
#pragma once
#include "../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CAlgorithmOVMatrixFileWriter final : public Toolkit::TAlgorithm<IAlgorithm>
{
public:
void release() override { delete this; }
bool initialize() override;
bool uninitialize() override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TAlgorithm<IAlgorithm>, OVP_ClassId_Algorithm_OVMatrixFileWriter)
protected:
Kernel::TParameterHandler<CString*> ip_sFilename;
Kernel::TParameterHandler<CMatrix*> ip_pMatrix;
};
class CAlgorithmOVMatrixFileWriterDesc final : public IAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("OpenViBE Matrix file writer"); }
CString getAuthorName() const override { return CString("Vincent Delannoy"); }
CString getAuthorCompanyName() const override { return CString("INRIA/IRISA"); }
CString getShortDescription() const override { return CString(""); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing"); }
CString getVersion() const override { return CString("1.1"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_Algorithm_OVMatrixFileWriter; }
IPluginObject* create() override { return new CAlgorithmOVMatrixFileWriter; }
bool getAlgorithmPrototype(Kernel::IAlgorithmProto& prototype) const override
{
prototype.addInputParameter(OVP_Algorithm_OVMatrixFileWriter_InputParameterId_Filename, "Filename", Kernel::ParameterType_String);
prototype.addInputParameter(OVP_Algorithm_OVMatrixFileWriter_InputParameterId_Matrix, "Matrix", Kernel::ParameterType_Matrix);
return true;
}
_IsDerivedFromClass_Final_(IAlgorithmDesc, OVP_ClassId_Algorithm_OVMatrixFileWriterDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,161 @@
#include <cstdio>
#include <cstring>
#include "ovpCAlgorithmXMLScenarioExporter.h"
//___________________________________________________________________//
// //
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
//___________________________________________________________________//
// //
CAlgorithmXMLScenarioExporter::CAlgorithmXMLScenarioExporter() { m_writer = createWriter(*this); }
CAlgorithmXMLScenarioExporter::~CAlgorithmXMLScenarioExporter() { m_writer->release(); }
void CAlgorithmXMLScenarioExporter::write(const char* str) { m_pMemoryBuffer->append(reinterpret_cast<const uint8_t*>(str), strlen(str)); }
bool CAlgorithmXMLScenarioExporter::exportStart(IMemoryBuffer& memoryBuffer, const CIdentifier& id)
{
m_pMemoryBuffer = &memoryBuffer;
CString name;
if (id == OVTK_Algorithm_ScenarioExporter_NodeId_OpenViBEScenario) { name = "OpenViBE-Scenario"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Settings) { name = "Settings"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting) { name = "Setting"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_TypeID) { name = "TypeIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_Name) { name = "Name"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_DefaultValue) { name = "DefaultValue"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_Value) { name = "Value"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Inputs) { name = "Inputs"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input) { name = "Input"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_TypeID) { name = "TypeIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_Name) { name = "Name"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_LinkedBoxID) { name = "LinkedBoxIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_LinkedBoxInputIdx) { name = "LinkedBoxInputIndex"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_LinkedBoxInputID) { name = "LinkedBoxInputIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Outputs) { name = "Outputs"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output) { name = "Output"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_TypeID) { name = "TypeIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_Name) { name = "Name"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_LinkedBoxID) { name = "LinkedBoxIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_LinkedBoxOutputIdx) { name = "LinkedBoxOutputIndex"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_LinkedBoxOutputID) { name = "LinkedBoxOutputIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_FormatVersion) { name = "FormatVersion"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Creator) { name = "Creator"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_CreatorVersion) { name = "CreatorVersion"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Boxes) { name = "Boxes"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box) { name = "Box"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Name) { name = "Name"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_AlgorithmClassIdD) { name = "AlgorithmClassIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Inputs) { name = "Inputs"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input) { name = "Input"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input_TypeID) { name = "TypeIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input_Name) { name = "Name"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Outputs) { name = "Outputs"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output) { name = "Output"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output_TypeID) { name = "TypeIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output_Name) { name = "Name"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Settings) { name = "Settings"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting) { name = "Setting"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_TypeID) { name = "TypeIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_Name) { name = "Name"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_DefaultValue) { name = "DefaultValue"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_Value) { name = "Value"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_Modifiability) { name = "Modifiability"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Attributes) { name = "Attributes"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Attribute) { name = "Attribute"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Attribute_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Box_Attribute_Value) { name = "Value"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comments) { name = "Comments"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comment) { name = "Comment"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comment_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Text) { name = "Text"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Attributes) { name = "Attributes"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Attribute) { name = "Attribute"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Attribute_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Attribute_Value) { name = "Value"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Metadata) { name = "Metadata"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry) { name = "Entry"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry_Type) { name = "Type"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry_Data) { name = "Data"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Links) { name = "Links"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link) { name = "Link"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source) { name = "Source"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source_BoxID) { name = "BoxIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source_BoxOutputIdx) { name = "BoxOutputIndex"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source_BoxOutputID) { name = "BoxOutputIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target) { name = "Target"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target_BoxID) { name = "BoxIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target_BoxInputIdx) { name = "BoxInputIndex"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target_BoxInputID) { name = "BoxInputIdentifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Attributes) { name = "Attributes"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Attribute) { name = "Attribute"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Attribute_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Link_Attribute_Value) { name = "Value"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Attributes) { name = "Attributes"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Attribute) { name = "Attribute"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Attribute_ID) { name = "Identifier"; }
else if (id == OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Attribute_Value) { name = "Value"; }
//
else { OV_ERROR_KRF("(start) Unexpected node identifier " << id.str(), Kernel::ErrorType::BadArgument); }
m_writer->openChild(name.toASCIIString());
return true;
}
bool CAlgorithmXMLScenarioExporter::exportIdentifier(IMemoryBuffer& memoryBuffer, const CIdentifier& id, const CIdentifier& value)
{
m_pMemoryBuffer = &memoryBuffer;
OV_ERROR_UNLESS_KRF(this->exportStart(memoryBuffer, id), "Exporting identifier failed", Kernel::ErrorType::Internal);
m_writer->setChildData(value.str().c_str());
this->exportStop(memoryBuffer);
return true;
}
bool CAlgorithmXMLScenarioExporter::exportString(IMemoryBuffer& memoryBuffer, const CIdentifier& id, const CString& value)
{
m_pMemoryBuffer = &memoryBuffer;
OV_ERROR_UNLESS_KRF(this->exportStart(memoryBuffer, id), "Exporting string failed", Kernel::ErrorType::Internal);
m_writer->setChildData(value.toASCIIString());
this->exportStop(memoryBuffer);
return true;
}
bool CAlgorithmXMLScenarioExporter::exportUInteger(IMemoryBuffer& memoryBuffer, const CIdentifier& id, const uint64_t value)
{
m_pMemoryBuffer = &memoryBuffer;
OV_ERROR_UNLESS_KRF(this->exportStart(memoryBuffer, id), "Exporting uint failed", Kernel::ErrorType::Internal);
m_writer->setChildData(std::to_string(value).c_str());
this->exportStop(memoryBuffer);
return true;
}
bool CAlgorithmXMLScenarioExporter::exportStop(IMemoryBuffer& memoryBuffer)
{
m_pMemoryBuffer = &memoryBuffer;
m_writer->closeChild();
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,57 @@
#pragma once
#include "../../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <xml/IWriter.h>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CAlgorithmXMLScenarioExporter final : public Toolkit::CAlgorithmScenarioExporter, public XML::IWriterCallback
{
public:
CAlgorithmXMLScenarioExporter();
~CAlgorithmXMLScenarioExporter() override;
bool exportStart(IMemoryBuffer& memoryBuffer, const CIdentifier& id) override;
bool exportIdentifier(IMemoryBuffer& memoryBuffer, const CIdentifier& id, const CIdentifier& value) override;
bool exportString(IMemoryBuffer& memoryBuffer, const CIdentifier& id, const CString& value) override;
bool exportUInteger(IMemoryBuffer& memoryBuffer, const CIdentifier& id, uint64_t value) override;
bool exportStop(IMemoryBuffer& memoryBuffer) override;
_IsDerivedFromClass_Final_(Toolkit::CAlgorithmScenarioExporter, OVP_ClassId_Algorithm_XMLScenarioExporter)
protected:
void write(const char* str) override; // XML::IWriterCallback
XML::IWriter* m_writer = nullptr;
IMemoryBuffer* m_pMemoryBuffer = nullptr;
};
class CAlgorithmXMLScenarioExporterDesc final : public Toolkit::CAlgorithmScenarioExporterDesc
{
public:
void release() override { }
CString getName() const override { return CString("XML Scenario exporter"); }
CString getAuthorName() const override { return CString("Yann Renard"); }
CString getAuthorCompanyName() const override { return CString("INRIA/IRISA"); }
CString getShortDescription() const override { return CString("A sample XML scenario exporter"); }
CString getDetailedDescription() const override { return CString("This scenario exporter uses simple XML format to output the scenario"); }
CString getCategory() const override { return CString("File reading and writing/XML Scenario"); }
CString getVersion() const override { return CString("1.0"); }
// virtual CString getFileExtension() const { return CString("xml;XML"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_Algorithm_XMLScenarioExporter; }
IPluginObject* create() override { return new CAlgorithmXMLScenarioExporter(); }
_IsDerivedFromClass_Final_(Toolkit::CAlgorithmScenarioExporterDesc, OVP_ClassId_Algorithm_XMLScenarioExporterDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,469 @@
#include "ovpCAlgorithmXMLScenarioImporter.h"
#include <iostream>
#include <cstdlib>
#include <string>
#include <memory>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/validators/common/Grammar.hpp>
XERCES_CPP_NAMESPACE_USE
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
namespace {
class _AutoBind_
{
public:
explicit _AutoBind_(const std::string& value) : m_value(value) { }
operator CString() const { return CString(m_value.c_str()); }
operator CIdentifier() const
{
CIdentifier res;
res.fromString(m_value.c_str());
return res;
}
operator size_t() { return atoi(m_value.c_str()); }
protected:
const std::string& m_value;
};
std::string xercesToString(const XMLCh* xercesString)
{
const std::unique_ptr<char[]> charArray(XMLString::transcode(xercesString));
return std::string(charArray.get());
}
class CErrorHandler final : public HandlerBase
{
public:
explicit CErrorHandler(Kernel::IAlgorithmContext& algorithmCtx)
: m_algorithmContext(algorithmCtx) { }
void fatalError(const SAXParseException& exception) override { this->error(exception); }
void error(const SAXParseException& exception) override
{
// we just issue a trace here because the calling method
// implements a fallback mechanism and we don't want to populate
// the error manager if the importer returns gracefully.
m_algorithmContext.getLogManager() << Kernel::LogLevel_Trace << "Failed to validate xml: error [" << xercesToString(exception.getMessage())
<< "], line number [" << size_t(exception.getLineNumber()) << "]" << "\n";
}
void warning(const SAXParseException& exception) override
{
OV_WARNING("Warning while validating xml: warning [" << xercesToString(exception.getMessage()) << "], line number ["
<< size_t(exception.getLineNumber()) << "]", m_algorithmContext.getLogManager());
}
private:
Kernel::IAlgorithmContext& m_algorithmContext;
};
} //namespace
CAlgorithmXMLScenarioImporter::CAlgorithmXMLScenarioImporter() { m_reader = createReader(*this); }
CAlgorithmXMLScenarioImporter::~CAlgorithmXMLScenarioImporter() { m_reader->release(); }
void CAlgorithmXMLScenarioImporter::openChild(const char* name, const char** /*attributeName*/, const char** /*attributeValue*/, const size_t /*nAttribute*/)
{
m_nodes.push(name);
std::string& top = m_nodes.top();
if (top == "OpenViBE-Scenario" && m_status == EParsingStatus::Nothing)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_OpenViBEScenario);
}
else if (top == "Attribute" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::ScenarioAttribute;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Attribute);
}
else if (top == "Setting" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::ScenarioSetting;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting);
}
else if (top == "Input" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::ScenarioInput;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input);
}
else if (top == "Output" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::ScenarioOutput;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output);
}
else if (top == "Box" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::Box;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Box);
}
else if (top == "Input" && m_status == EParsingStatus::Box)
{
m_status = EParsingStatus::BoxInput;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input);
}
else if (top == "Output" && m_status == EParsingStatus::Box)
{
m_status = EParsingStatus::BoxOutput;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output);
}
else if (top == "Setting" && m_status == EParsingStatus::Box)
{
m_status = EParsingStatus::BoxSetting;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting);
}
else if (top == "Attribute" && m_status == EParsingStatus::Box)
{
m_status = EParsingStatus::BoxAttribute;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Attribute);
}
else if (top == "Comment" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::Comment;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Comment);
}
else if (top == "Attribute" && m_status == EParsingStatus::Comment)
{
m_status = EParsingStatus::CommentAttribute;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Attribute);
}
else if (top == "Entry" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::MetadataEntry;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry);
}
else if (top == "Link" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::Link;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Link);
}
else if (top == "Source" && m_status == EParsingStatus::Link)
{
m_status = EParsingStatus::LinkSource;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source);
}
else if (top == "Target" && m_status == EParsingStatus::Link)
{
m_status = EParsingStatus::LinkTarget;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target);
}
else if (top == "Attribute" && m_status == EParsingStatus::Link)
{
m_status = EParsingStatus::LinkAttribute;
m_ctx->processStart(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Attribute);
}
}
void CAlgorithmXMLScenarioImporter::processChildData(const char* data)
{
std::string& top = m_nodes.top();
switch (m_status)
{
case EParsingStatus::Box:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_ID, _AutoBind_(data)); }
if (top == "AlgorithmClassIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_AlgorithmClassIdD, _AutoBind_(data)); }
if (top == "Name") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Name, _AutoBind_(data)); }
break;
case EParsingStatus::BoxInput:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input_ID, _AutoBind_(data)); }
if (top == "TypeIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input_TypeID, _AutoBind_(data)); }
if (top == "Name") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Input_Name, _AutoBind_(data)); }
break;
case EParsingStatus::BoxOutput:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output_ID, _AutoBind_(data)); }
if (top == "TypeIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output_TypeID, _AutoBind_(data)); }
if (top == "Name") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Output_Name, _AutoBind_(data)); }
break;
case EParsingStatus::BoxSetting:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_ID, _AutoBind_(data)); }
if (top == "TypeIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_TypeID, _AutoBind_(data)); }
if (top == "Name") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_Name, _AutoBind_(data)); }
if (top == "DefaultValue") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_DefaultValue, _AutoBind_(data)); }
if (top == "Value") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_Value, _AutoBind_(data)); }
if (top == "Modifiability") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Setting_Modifiability, _AutoBind_(data)); }
break;
case EParsingStatus::BoxAttribute:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Attribute_ID, _AutoBind_(data)); }
if (top == "Value") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Box_Attribute_Value, _AutoBind_(data)); }
break;
case EParsingStatus::Comment:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Comment_ID, _AutoBind_(data)); }
if (top == "Text") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Text, _AutoBind_(data)); }
break;
case EParsingStatus::MetadataEntry:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry_ID, _AutoBind_(data)); }
if (top == "Type") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry_Type, _AutoBind_(data)); }
if (top == "Data") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_MetadataEntry_Data, _AutoBind_(data)); }
break;
case EParsingStatus::CommentAttribute:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Attribute_ID, _AutoBind_(data)); }
if (top == "Value") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Comment_Attribute_Value, _AutoBind_(data)); }
break;
case EParsingStatus::Link:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Link_ID, _AutoBind_(data)); }
break;
case EParsingStatus::LinkSource:
if (top == "BoxIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source_BoxID, _AutoBind_(data)); }
if (top == "BoxOutputIndex") { m_ctx->processUInteger(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source_BoxOutputIdx, _AutoBind_(data)); }
if (top == "BoxOutputIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Source_BoxOutputID, _AutoBind_(data)); }
break;
case EParsingStatus::LinkTarget:
if (top == "BoxIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target_BoxID, _AutoBind_(data)); }
if (top == "BoxInputIndex") { m_ctx->processUInteger(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target_BoxInputIdx, _AutoBind_(data)); }
if (top == "BoxInputIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Target_BoxInputID, _AutoBind_(data)); }
break;
case EParsingStatus::LinkAttribute:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Attribute_ID, _AutoBind_(data)); }
if (top == "Value") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Link_Attribute_Value, _AutoBind_(data)); }
break;
case EParsingStatus::ScenarioSetting:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_ID, _AutoBind_(data)); }
if (top == "TypeIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_TypeID, _AutoBind_(data)); }
if (top == "Name") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_Name, _AutoBind_(data)); }
if (top == "DefaultValue") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_DefaultValue, _AutoBind_(data)); }
if (top == "Value") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Setting_Value, _AutoBind_(data)); }
break;
case EParsingStatus::ScenarioInput:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_ID, _AutoBind_(data)); }
if (top == "TypeIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_TypeID, _AutoBind_(data)); }
if (top == "Name") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_Name, _AutoBind_(data)); }
if (top == "LinkedBoxIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_LinkedBoxID, _AutoBind_(data)); }
if (top == "LinkedBoxInputIndex")
{
m_ctx->processUInteger(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_LinkedBoxInputIdx, _AutoBind_(data));
}
if (top == "LinkedBoxInputIdentifier")
{
m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Input_LinkedBoxInputID, _AutoBind_(data));
}
break;
case EParsingStatus::ScenarioOutput:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_ID, _AutoBind_(data)); }
if (top == "TypeIdentifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_TypeID, _AutoBind_(data)); }
if (top == "Name") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_Name, _AutoBind_(data)); }
if (top == "LinkedBoxIdentifier")
{
m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_LinkedBoxID, _AutoBind_(data));
}
if (top == "LinkedBoxOutputIndex")
{
m_ctx->processUInteger(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_LinkedBoxOutputIdx, _AutoBind_(data));
}
if (top == "LinkedBoxOutputIdentifier")
{
m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Output_LinkedBoxOutputID, _AutoBind_(data));
}
break;
case EParsingStatus::ScenarioAttribute:
if (top == "Identifier") { m_ctx->processIdentifier(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Attribute_ID, _AutoBind_(data)); }
if (top == "Value") { m_ctx->processString(OVTK_Algorithm_ScenarioExporter_NodeId_Scenario_Attribute_Value, _AutoBind_(data)); }
break;
default: break;
}
}
void CAlgorithmXMLScenarioImporter::closeChild()
{
std::string& top = m_nodes.top();
if (top == "OpenViBE-Scenario" && m_status == EParsingStatus::Scenario)
{
m_status = EParsingStatus::Nothing;
m_ctx->processStop();
}
else if (top == "Setting" && m_status == EParsingStatus::ScenarioSetting)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Input" && m_status == EParsingStatus::ScenarioInput)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Output" && m_status == EParsingStatus::ScenarioOutput)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Attribute" && m_status == EParsingStatus::ScenarioAttribute)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Box" && m_status == EParsingStatus::Box)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Input" && m_status == EParsingStatus::BoxInput)
{
m_status = EParsingStatus::Box;
m_ctx->processStop();
}
else if (top == "Output" && m_status == EParsingStatus::BoxOutput)
{
m_status = EParsingStatus::Box;
m_ctx->processStop();
}
else if (top == "Setting" && m_status == EParsingStatus::BoxSetting)
{
m_status = EParsingStatus::Box;
m_ctx->processStop();
}
else if (top == "Attribute" && m_status == EParsingStatus::BoxAttribute)
{
m_status = EParsingStatus::Box;
m_ctx->processStop();
}
else if (top == "Comment" && m_status == EParsingStatus::Comment)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Attribute" && m_status == EParsingStatus::CommentAttribute)
{
m_status = EParsingStatus::Comment;
m_ctx->processStop();
}
else if (top == "Entry" && m_status == EParsingStatus::MetadataEntry)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Link" && m_status == EParsingStatus::Link)
{
m_status = EParsingStatus::Scenario;
m_ctx->processStop();
}
else if (top == "Source" && m_status == EParsingStatus::LinkSource)
{
m_status = EParsingStatus::Link;
m_ctx->processStop();
}
else if (top == "Target" && m_status == EParsingStatus::LinkTarget)
{
m_status = EParsingStatus::Link;
m_ctx->processStop();
}
else if (top == "Attribute" && m_status == EParsingStatus::LinkAttribute)
{
m_status = EParsingStatus::Link;
m_ctx->processStop();
}
m_nodes.pop();
}
bool CAlgorithmXMLScenarioImporter::validateXML(const unsigned char* buffer, const size_t size)
{
// implementation of the fallback mechanism
// error manager is used to differentiate errors from invalid xml
this->getErrorManager().releaseErrors();
if (this->validateXMLAgainstSchema((Directories::getDataDir() + "/kernel/openvibe-scenario-v2.xsd"), buffer, size)) { return true; }
if (this->getErrorManager().hasError())
{
// this is not a validation error thus we return directly
return false;
}
if (this->validateXMLAgainstSchema((Directories::getDataDir() + "/kernel/openvibe-scenario-v1.xsd"), buffer, size))
{
this->getLogManager() << Kernel::LogLevel_Trace <<
"Importing scenario with legacy format: v1 scenario might be deprecated in the future so upgrade to v2 format when possible\n";
return true;
}
if (this->getErrorManager().hasError())
{
// this is not a validation error thus we return directly
return false;
}
if (this->validateXMLAgainstSchema((Directories::getDataDir() + "/kernel/openvibe-scenario-legacy.xsd"), buffer, size))
{
OV_WARNING_K("Importing scenario with legacy format: legacy scenario might be deprecated in the future so upgrade to v2 format when possible");
return true;
}
if (this->getErrorManager().hasError())
{
// this is not a validation error thus we return directly
return false;
}
OV_ERROR_KRF("Failed to validate scenario against XSD schemas", Kernel::ErrorType::BadXMLSchemaValidation);
}
bool CAlgorithmXMLScenarioImporter::validateXMLAgainstSchema(const char* validationSchema, const unsigned char* buffer, const size_t size)
{
this->getLogManager() << Kernel::LogLevel_Trace << "Validating XML against schema [" << validationSchema << "]\n";
size_t errorCount;
XMLPlatformUtils::Initialize();
{ // scope the content here to ensure unique_ptr contents are destroyed before the call to XMLPlatformUtils::Terminate();
const std::unique_ptr<MemBufInputSource> xercesBuffer(new MemBufInputSource(buffer, size, "xml memory buffer"));
std::unique_ptr<XercesDOMParser> parser(new XercesDOMParser());
parser->setValidationScheme(XercesDOMParser::Val_Always);
parser->setDoNamespaces(true);
parser->setDoSchema(true);
parser->setValidationConstraintFatal(true);
parser->setValidationSchemaFullChecking(true);
parser->setExternalNoNamespaceSchemaLocation(validationSchema);
const std::unique_ptr<ErrorHandler> errorHandler(new CErrorHandler(this->getAlgorithmContext()));
parser->setErrorHandler(errorHandler.get());
parser->parse(*xercesBuffer);
errorCount = parser->getErrorCount();
}
XMLPlatformUtils::Terminate();
return (errorCount == 0);
}
bool CAlgorithmXMLScenarioImporter::import(IAlgorithmScenarioImporterContext& rContext, const IMemoryBuffer& memoryBuffer)
{
m_ctx = &rContext;
if (!this->validateXML(memoryBuffer.getDirectPointer(), memoryBuffer.getSize())) { return false; } // error handling is handled in validateXML
return m_reader->processData(memoryBuffer.getDirectPointer(), memoryBuffer.getSize());
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,71 @@
#pragma once
#include "../../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <xml/IReader.h>
#include <stack>
#include <string>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CAlgorithmXMLScenarioImporter final : public Toolkit::CAlgorithmScenarioImporter, public XML::IReaderCallback
{
public:
CAlgorithmXMLScenarioImporter();
~CAlgorithmXMLScenarioImporter() override;
bool import(IAlgorithmScenarioImporterContext& rContext, const IMemoryBuffer& memoryBuffer) override;
void openChild(const char* name, const char** attributeName, const char** sAttributeValue, const size_t nAttribute)
override; // XML::IReaderCallback
void processChildData(const char* data) override; // XML::IReaderCallback
void closeChild() override; // XML::IReaderCallback
_IsDerivedFromClass_Final_(Toolkit::CAlgorithmScenarioImporter, OVP_ClassId_Algorithm_XMLScenarioImporter)
protected:
enum class EParsingStatus
{
Nothing,
Scenario, ScenarioAttribute, ScenarioInput, ScenarioOutput, ScenarioSetting,
Box, BoxInput, BoxOutput, BoxSetting, BoxAttribute,
Comment, CommentAttribute,
MetadataEntry,
Link, LinkSource, LinkTarget, LinkAttribute
};
bool validateXML(const unsigned char* buffer, size_t size);
bool validateXMLAgainstSchema(const char* validationSchema, const unsigned char* buffer, size_t size);
IAlgorithmScenarioImporterContext* m_ctx = nullptr;
EParsingStatus m_status = EParsingStatus::Nothing;
XML::IReader* m_reader = nullptr;
std::stack<std::string> m_nodes;
};
class CAlgorithmXMLScenarioImporterDesc final : public Toolkit::CAlgorithmScenarioImporterDesc
{
public:
void release() override { }
CString getName() const override { return CString("XML Scenario importer"); }
CString getAuthorName() const override { return CString("Yann Renard"); }
CString getAuthorCompanyName() const override { return CString("INRIA/IRISA"); }
CString getShortDescription() const override { return CString("A sample XML scenario importer"); }
CString getDetailedDescription() const override { return CString("This scenario importer uses simple XML format to input the scenario"); }
CString getCategory() const override { return CString("Samples"); }
CString getVersion() const override { return CString("1.0"); }
// virtual CString getFileExtension() const { return CString("xml;XML"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_Algorithm_XMLScenarioImporter; }
IPluginObject* create() override { return new CAlgorithmXMLScenarioImporter(); }
_IsDerivedFromClass_Final_(Toolkit::CAlgorithmScenarioImporterDesc, OVP_ClassId_Algorithm_XMLScenarioImporterDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,572 @@
#include "ovpCBoxAlgorithmCSVFileReader.h"
#include <iostream>
#include <sstream>
#include <map>
#include <vector>
#include <cmath> // std::ceil() on Linux
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
namespace {
std::vector<std::string> split(const std::string& sString, const std::string& c)
{
std::vector<std::string> result;
size_t i = 0;
size_t j;
while ((j = sString.find(c, i)) != std::string::npos)
{
result.push_back(std::string(sString, i, j - i));
i = j + c.size();
}
//the last element without the \n character
result.push_back(std::string(sString, i, sString.size() - 1 - i));
return result;
}
void clearMatrix(std::vector<std::vector<std::string>>& vMatrix)
{
for (size_t i = 0; i < vMatrix.size(); ++i) { vMatrix[i].clear(); }
vMatrix.clear();
}
} // namespace
bool CBoxAlgorithmCSVFileReader::initialize()
{
m_sampling = 0;
m_encoder = nullptr;
this->getStaticBoxContext().getOutputType(0, m_typeID);
m_filename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
const CString token = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
m_separator = token.toASCIIString();
m_doNotUseFileTime = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
m_samplesPerBuffer = 1;
if (m_typeID == OV_TypeId_ChannelLocalisation) { m_channelsPerBuffer = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3); }
else if (m_typeID != OV_TypeId_Stimulations && m_typeID != OV_TypeId_Spectrum)
{
m_samplesPerBuffer = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3);
}
m_nextTime = 0.;
m_startTime = 0;
m_endTime = 0;
return true;
}
bool CBoxAlgorithmCSVFileReader::uninitialize()
{
if (m_file)
{
fclose(m_file);
m_file = nullptr;
}
if (m_encoder)
{
m_encoder->uninitialize();
delete m_encoder;
m_encoder = nullptr;
}
return true;
}
bool CBoxAlgorithmCSVFileReader::initializeFile()
{
//open file, we don't open as binary as that gives us \r\n on Windows as line-endings and leaves a dangling char after split. CSV files should be text.
m_file = fopen(m_filename.toASCIIString(), "r");
OV_ERROR_UNLESS_KRF(m_file, "Error opening file [" << m_filename << "] for reading", Kernel::ErrorType::BadFileRead);
// simulate RAII through closure
const auto releaseResources = [&]()
{
fclose(m_file);
m_file = nullptr;
};
//read the header
char line[BUFFER_LEN];
char* result = fgets(line, BUFFER_LEN, m_file);
if (nullptr == result)
{
releaseResources();
OV_ERROR_KRF("Error reading data from file", Kernel::ErrorType::BadParsing);
}
m_headerFiles = split(std::string(line), m_separator);
m_nCol = m_headerFiles.size();
if (m_typeID == OV_TypeId_ChannelLocalisation)
{
m_encoder = new Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmCSVFileReader>(*this, 0);
//number of column without the column contains the dynamic parameter
//m_nCol-=1;
m_realProcess = &CBoxAlgorithmCSVFileReader::processChannelLocalisation;
}
else if (m_typeID == OV_TypeId_FeatureVector)
{
m_encoder = new Toolkit::TFeatureVectorEncoder<CBoxAlgorithmCSVFileReader>(*this, 0);
m_realProcess = &CBoxAlgorithmCSVFileReader::processFeatureVector;
m_samplesPerBuffer = 1;
}
else if (m_typeID == OV_TypeId_Spectrum)
{
m_encoder = new Toolkit::TSpectrumEncoder<CBoxAlgorithmCSVFileReader>(*this, 0);
m_realProcess = &CBoxAlgorithmCSVFileReader::processSpectrum;
//number of column without columns contains min max frequency bands parameters
m_nCol -= 2;
}
else if (m_typeID == OV_TypeId_Signal)
{
m_encoder = new Toolkit::TSignalEncoder<CBoxAlgorithmCSVFileReader>(*this, 0);
m_realProcess = &CBoxAlgorithmCSVFileReader::processSignal;
//find the sampling rate
result = fgets(line, BUFFER_LEN, m_file);
if (nullptr == result)
{
releaseResources();
OV_ERROR_KRF("Error reading sampling rate from file", Kernel::ErrorType::BadParsing);
}
std::vector<std::string> parsed = split(std::string(line), m_separator);
if ((m_nCol - 1) >= parsed.size())
{
releaseResources();
OV_ERROR_KRF("Error reading columns (not enough columns found) from file", Kernel::ErrorType::BadParsing);
}
const double sampling = double(atof(parsed[m_nCol - 1].c_str()));
if (ceil(sampling) != sampling)
{
releaseResources();
OV_ERROR_KRF("Invalid fractional sampling rate (" << sampling << ") in file", Kernel::ErrorType::BadValue);
}
m_sampling = uint64_t(sampling);
if (m_sampling == 0)
{
releaseResources();
OV_ERROR_KRF("Invalid NULL sampling rate in file", Kernel::ErrorType::BadValue);
}
// Skip the header
rewind(m_file);
result = fgets(line, BUFFER_LEN, m_file);
if (nullptr == result)
{
releaseResources();
OV_ERROR_KRF("Error reading data from file", Kernel::ErrorType::BadParsing);
}
//number of column without the column contains the sampling rate parameters
m_nCol -= 1;
}
else if (m_typeID == OV_TypeId_StreamedMatrix)
{
m_encoder = new Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmCSVFileReader>(*this, 0);
m_realProcess = &CBoxAlgorithmCSVFileReader::processStreamedMatrix;
}
else if (m_typeID == OV_TypeId_Stimulations)
{
m_encoder = new Toolkit::TStimulationEncoder<CBoxAlgorithmCSVFileReader>(*this, 0);
m_realProcess = &CBoxAlgorithmCSVFileReader::processStimulation;
}
else
{
releaseResources();
OV_ERROR_KRF("Invalid input type identifier " << this->getTypeManager().getTypeName(m_typeID) << " in file ", Kernel::ErrorType::BadValue);
}
return true;
}
bool CBoxAlgorithmCSVFileReader::processClock(Kernel::CMessageClock& /*msg*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmCSVFileReader::process()
{
if (m_file == nullptr) { OV_ERROR_UNLESS_KRF(initializeFile(), "Error reading data from csv file " << m_filename, Kernel::ErrorType::Internal); }
//line buffer
char line[BUFFER_LEN];
const double currentTime = CTime(getPlayerContext().getCurrentTime()).toSeconds();
//if no line was read, read the first data line.
if (m_lastLineSplits.empty())
{
//next line
size_t nSamples = 0;
while (!feof(m_file) && nSamples < m_samplesPerBuffer && fgets(line, BUFFER_LEN, m_file) != nullptr)
{
m_lastLineSplits = split(std::string(line), m_separator);
nSamples++;
if (m_typeID != OV_TypeId_Stimulations
&& m_typeID != OV_TypeId_Spectrum
&& m_typeID != OV_TypeId_ChannelLocalisation) { m_dataMatrices.push_back(m_lastLineSplits); }
}
if ((m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_Signal)
&& feof(m_file) && nSamples < m_samplesPerBuffer)
{
// Last chunk will be partial, zero the whole output matrix...
CMatrix* iMatrix = static_cast<Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputMatrix();
iMatrix->resetBuffer();
}
}
bool somethingToSend = (!m_lastLineSplits.empty()) && atof(m_lastLineSplits[0].c_str()) < currentTime;
somethingToSend |= (m_typeID == OV_TypeId_Stimulations); // we always send a stim chunk, even if empty
if (m_typeID == OV_TypeId_Stimulations || m_typeID == OV_TypeId_ChannelLocalisation || m_typeID == OV_TypeId_Spectrum)
{
while (!m_lastLineSplits.empty() && atof(m_lastLineSplits[0].c_str()) < currentTime)
{
m_dataMatrices.push_back(m_lastLineSplits);
somethingToSend = true;
if (!feof(m_file) && fgets(line, BUFFER_LEN, m_file) != nullptr) { m_lastLineSplits = split(std::string(line), m_separator); }
else { m_lastLineSplits.clear(); }
}
}
//convert data to the good output type
if (somethingToSend)
{
// Encode the data
OV_ERROR_UNLESS_KRF((this->*m_realProcess)(), "Error encoding data from csv file " << m_filename << " into the right output format",
Kernel::ErrorType::Internal);
//for the stimulation, the line contents in m_vLastLineSplit isn't processed.
if (m_typeID != OV_TypeId_Stimulations && m_typeID != OV_TypeId_Spectrum && m_typeID != OV_TypeId_ChannelLocalisation) { m_lastLineSplits.clear(); }
//clear the Data Matrix.
clearMatrix(m_dataMatrices);
}
return true;
}
bool CBoxAlgorithmCSVFileReader::processStreamedMatrix()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
CMatrix* iMatrix = static_cast<Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputMatrix();
//Header
if (!m_headerSent)
{
iMatrix->resize(m_nCol - 1, m_samplesPerBuffer);
for (size_t i = 1; i < m_nCol; ++i) { iMatrix->setDimensionLabel(0, i - 1, m_headerFiles[i].c_str()); }
m_encoder->encodeHeader();
m_headerSent = true;
boxContext.markOutputAsReadyToSend(0, 0, 0);
}
OV_ERROR_UNLESS_KRF(convertVectorDataToMatrix(iMatrix), "Error converting vector data to streamed matrix", Kernel::ErrorType::Internal);
m_encoder->encodeBuffer();
if (m_doNotUseFileTime)
{
m_startTime = m_endTime;
m_endTime = this->getPlayerContext().getCurrentTime();
}
else
{
m_startTime = CTime(atof(m_dataMatrices[0][0].c_str())).time();
m_endTime = CTime(atof(m_dataMatrices.back()[0].c_str())).time();
}
boxContext.markOutputAsReadyToSend(0, m_startTime, m_endTime);
return true;
}
bool CBoxAlgorithmCSVFileReader::processStimulation()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
//Header
if (!m_headerSent)
{
m_encoder->encodeHeader();
m_headerSent = true;
boxContext.markOutputAsReadyToSend(0, 0, 0);
}
IStimulationSet* ip_stimSet = static_cast<Toolkit::TStimulationEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputStimulationSet();
ip_stimSet->clear();
for (size_t i = 0; i < m_dataMatrices.size(); ++i)
{
OV_ERROR_UNLESS_KRF(m_dataMatrices[i].size() == 3, "Invalid data row length: must be 3 for stimulation date, index and duration",
Kernel::ErrorType::BadParsing);
const uint64_t date = CTime(atof(m_dataMatrices[i][0].c_str())).time();
const uint64_t id = uint64_t(atof(m_dataMatrices[i][1].c_str()));
const uint64_t duration = CTime(atof(m_dataMatrices[i][2].c_str())).time();
ip_stimSet->appendStimulation(id, date, duration);
}
m_encoder->encodeBuffer();
// Never use file time
m_startTime = m_endTime;
m_endTime = this->getPlayerContext().getCurrentTime();
boxContext.markOutputAsReadyToSend(0, m_startTime, m_endTime);
return true;
}
bool CBoxAlgorithmCSVFileReader::processSignal()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
CMatrix* iMatrix = static_cast<Toolkit::TSignalEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputMatrix();
//Header
if (!m_headerSent)
{
// This is the first chunk, find out the start time from the file
// (to keep time chunks continuous, start time is previous end time, hence set end time)
if (!m_doNotUseFileTime) { m_endTime = CTime(atof(m_dataMatrices[0][0].c_str())).time(); }
iMatrix->resize(m_nCol - 1, m_samplesPerBuffer);
for (size_t i = 1; i < m_nCol; ++i) { iMatrix->setDimensionLabel(0, i - 1, m_headerFiles[i].c_str()); }
static_cast<Toolkit::TSignalEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputSamplingRate() = m_sampling;
m_encoder->encodeHeader();
m_headerSent = true;
this->getDynamicBoxContext().markOutputAsReadyToSend(0, 0, 0);
}
OV_ERROR_UNLESS_KRF(convertVectorDataToMatrix(iMatrix), "Error converting vector data to signal", Kernel::ErrorType::Internal);
// this->getLogManager() << Kernel::LogLevel_Info << "Cols from header " << m_nCol << "\n";
// this->getLogManager() << Kernel::LogLevel_Info << "InMatrix " << (m_dataMatrices.size() > 0 ? m_dataMatrices[0].size() : 0) << " outMatrix " << iMatrix->getDimensionSize(0) << "\n";
m_encoder->encodeBuffer();
if (m_doNotUseFileTime)
{
// We use time dictated by the sampling rate
m_startTime = m_endTime; // previous time end is current time start
m_endTime = m_startTime + CTime(m_sampling, m_samplesPerBuffer).time();
}
else
{
// We use time suggested by the last sample of the chunk
m_startTime = CTime(atof(m_dataMatrices[0][0].c_str())).time();
m_endTime = CTime(atof(m_dataMatrices.back()[0].c_str())).time();
}
boxContext.markOutputAsReadyToSend(0, m_startTime, m_endTime);
return true;
}
bool CBoxAlgorithmCSVFileReader::processChannelLocalisation()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
CMatrix* iMatrix = static_cast<Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputMatrix();
if (!m_headerSent)
{
iMatrix->resize(m_nCol - 1, m_samplesPerBuffer);
for (size_t i = 1; i < m_nCol; ++i) { iMatrix->setDimensionLabel(0, i - 1, m_headerFiles[i].c_str()); }
static_cast<Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputDynamic() = false;
//atoi(m_dataMatrices[0][m_nCol].c_str());
m_encoder->encodeHeader();
boxContext.markOutputAsReadyToSend(0, 0, 0);
m_headerSent = true;
}
std::vector<std::vector<std::string>> channelBloc;
for (size_t i = 0; i < m_dataMatrices.size(); ++i) { channelBloc.push_back(m_dataMatrices[i]); }
//clear matrix
clearMatrix(m_dataMatrices);
for (size_t i = 0; i < channelBloc.size(); ++i)
{
m_dataMatrices.push_back(channelBloc[i]);
//send the current bloc if the next data hasn't the same date
if (i >= channelBloc.size() - 1 || channelBloc[(i + 1)][0] != m_dataMatrices[0][0])
{
OV_ERROR_UNLESS_KRF(convertVectorDataToMatrix(iMatrix), "Error converting vector data to channel localisation", Kernel::ErrorType::Internal);
m_encoder->encodeBuffer();
const uint64_t date = CTime(atof(m_dataMatrices[0][0].c_str())).time();
boxContext.markOutputAsReadyToSend(0, date, date);
//clear matrix
clearMatrix(m_dataMatrices);
}
}
//clear matrix
clearMatrix(channelBloc);
return true;
}
bool CBoxAlgorithmCSVFileReader::processFeatureVector()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
CMatrix* matrix = static_cast<Toolkit::TFeatureVectorEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputMatrix();
//Header
if (!m_headerSent)
{
// in this case we need to transpose it
CMatrix* iMatrix = static_cast<Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputMatrix();
iMatrix->resize(m_nCol - 1);
for (size_t i = 1; i < m_nCol; ++i) { iMatrix->setDimensionLabel(0, i - 1, m_headerFiles[i].c_str()); }
m_encoder->encodeHeader();
boxContext.markOutputAsReadyToSend(0, 0, 0);
m_headerSent = true;
}
// Each vector has to be sent separately
for (size_t i = 0; i < m_dataMatrices.size(); ++i)
{
OV_ERROR_UNLESS_KRF(m_dataMatrices[i].size() == m_nCol,
"Unexpected number of elements" << "(got " << uint64_t(m_dataMatrices[i].size()) << ", expected " << m_nCol << ")",
Kernel::ErrorType::BadParsing);
for (size_t j = 0; j < m_nCol - 1; ++j) { matrix->getBuffer()[j] = atof(m_dataMatrices[i][j + 1].c_str()); }
m_encoder->encodeBuffer();
const uint64_t date = CTime(atof(m_dataMatrices[i][0].c_str())).time();
boxContext.markOutputAsReadyToSend(0, date, date);
}
clearMatrix(m_dataMatrices);
return true;
}
bool CBoxAlgorithmCSVFileReader::processSpectrum()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
CMatrix* iMatrix = static_cast<Toolkit::TSpectrumEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputMatrix();
CMatrix* iFrequencyAbscissa = static_cast<Toolkit::TSpectrumEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputFrequencyAbscissa();
//Header
if (!m_headerSent)
{
iMatrix->resize(m_nCol - 1, m_dataMatrices.size());
for (size_t i = 1; i < m_nCol; ++i) { iMatrix->setDimensionLabel(0, i - 1, m_headerFiles[i].c_str()); }
iFrequencyAbscissa->resize(m_dataMatrices.size());
if (m_dataMatrices.size() > 1)
{
for (size_t i = 0; i < m_dataMatrices.size(); ++i)
{
const double curFrequencyAbscissa = std::stod(m_dataMatrices[i][m_nCol]) + double(i) / (m_dataMatrices.size() - 1)
* (std::stod(m_dataMatrices[i][m_nCol + 1]) - std::stod(m_dataMatrices[i][m_nCol]));
iFrequencyAbscissa->getBuffer()[i] = curFrequencyAbscissa;
std::stringstream label;
label << curFrequencyAbscissa;
iFrequencyAbscissa->setDimensionLabel(0, i, label.str().c_str());
}
}
else { iFrequencyAbscissa->getBuffer()[0] = 0; }
static_cast<Toolkit::TSpectrumEncoder<CBoxAlgorithmCSVFileReader>*>(m_encoder)->getInputSamplingRate() = uint64_t(
m_dataMatrices.size() / (stod(m_dataMatrices[m_dataMatrices.size() - 1][m_nCol]) - stod(m_dataMatrices[0][m_nCol])));
m_headerSent = true;
m_encoder->encodeHeader();
boxContext.markOutputAsReadyToSend(0, 0, 0);
}
std::vector<std::vector<std::string>> spectrumBloc;
for (size_t i = 0; i < m_dataMatrices.size(); ++i) { spectrumBloc.push_back(m_dataMatrices[i]); }
//clear matrix
clearMatrix(m_dataMatrices);
for (size_t i = 0; i < spectrumBloc.size(); ++i)
{
m_dataMatrices.push_back(spectrumBloc[i]);
//send the current bloc if the next data hasn't the same date
if (i >= spectrumBloc.size() - 1 || spectrumBloc[i + 1][0] != m_dataMatrices[0][0])
{
OV_ERROR_UNLESS_KRF(convertVectorDataToMatrix(iMatrix), "Error converting vector data to spectrum", Kernel::ErrorType::Internal);
m_encoder->encodeBuffer();
const uint64_t date = CTime(std::stod(m_dataMatrices[0][0])).time();
boxContext.markOutputAsReadyToSend(0, date - 1, date);
//clear matrix
clearMatrix(m_dataMatrices);
}
}
//clear matrix
clearMatrix(spectrumBloc);
return true;
}
bool CBoxAlgorithmCSVFileReader::convertVectorDataToMatrix(CMatrix* matrix)
{
// note: Chunk size shouldn't change after encoding header, do not mess with it here, even if the input has different size
// We accept partial data, but not buffer overruns ...
OV_ERROR_UNLESS_KRF(matrix->getDimensionSize(1) >= m_dataMatrices.size() && matrix->getDimensionSize(0) >= (m_nCol-1),
"Matrix size incompatibility, data suggests " << m_nCol-1 << "x" << m_dataMatrices.size()
<< ", expected at most " << matrix->getDimensionSize(0) << "x" << matrix->getDimensionSize(0), Kernel::ErrorType::Overflow);
std::stringstream ss;
for (size_t i = 0; i < m_dataMatrices.size(); ++i)
{
ss << "at time (" << m_dataMatrices[i][0].c_str() << "):";
for (size_t j = 0; j < m_nCol - 1; ++j)
{
matrix->getBuffer()[j * matrix->getDimensionSize(1) + i] = std::stod(m_dataMatrices[i][j + 1]);
ss << matrix->getBuffer()[j * matrix->getDimensionSize(1) + i] << ";";
}
ss << "\n";
}
getLogManager() << Kernel::LogLevel_Debug << "Matrix:\n" << ss.str();
getLogManager() << Kernel::LogLevel_Debug << "Matrix:\n" << ss.str();
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,155 @@
#pragma once
#include "../../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <iostream>
#include <cstdio>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CBoxAlgorithmCSVFileReader final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
CBoxAlgorithmCSVFileReader() {}
void release() override { delete this; }
uint64_t getClockFrequency() override { return 128LL << 32; } // the box clock frequency
bool initialize() override;
bool uninitialize() override;
bool processClock(Kernel::CMessageClock& msg) override;
bool process() override;
bool processStreamedMatrix();
bool processStimulation();
bool processSignal();
bool processChannelLocalisation();
bool processFeatureVector();
bool processSpectrum();
bool convertVectorDataToMatrix(CMatrix* matrix);
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_CSVFileReader)
protected:
bool initializeFile();
FILE* m_file = nullptr;
std::string m_separator;
bool m_doNotUseFileTime = false;
CString m_filename;
CIdentifier m_typeID = CIdentifier::undefined();
size_t m_nCol = 0;
size_t m_sampling = 0;
size_t m_samplesPerBuffer = 0;
size_t m_channelsPerBuffer = 0;
bool (CBoxAlgorithmCSVFileReader::*m_realProcess)() = nullptr;
Toolkit::TEncoder<CBoxAlgorithmCSVFileReader>* m_encoder = nullptr;
bool m_headerSent = false;
std::vector<std::string> m_lastLineSplits;
std::vector<std::string> m_headerFiles;
std::vector<std::vector<std::string>> m_dataMatrices;
double m_nextTime = 0;
uint64_t m_startTime = 0;
uint64_t m_endTime = 0;
static const size_t BUFFER_LEN = 16384; // Side-effect: a maximum allowed length for a line of a CSV file
};
class CBoxAlgorithmCSVFileReaderListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool onOutputTypeChanged(Kernel::IBox& box, const size_t index) override
{
CIdentifier typeID = CIdentifier::undefined();
box.getOutputType(index, typeID);
if (typeID == OV_TypeId_Spectrum)
{
box.setSettingName(3, "Unused parameter");
box.setSettingValue(3, "0");
}
else if (typeID == OV_TypeId_ChannelLocalisation)
{
box.setSettingName(3, "Channels number");
box.setSettingValue(3, "32");
}
else if (typeID == OV_TypeId_FeatureVector)
{
box.setSettingName(3, "Unused parameter");
box.setSettingValue(3, "0");
}
else if (typeID == OV_TypeId_StreamedMatrix)
{
box.setSettingName(3, "Samples per buffer");
box.setSettingValue(3, "32");
}
else if (typeID == OV_TypeId_Stimulations)
{
box.setSettingName(3, "Unused parameter");
box.setSettingValue(3, "0");
}
else
{
box.setOutputType(index, OV_TypeId_Signal);
box.setSettingName(3, "Samples per buffer");
box.setSettingValue(3, "32");
OV_ERROR_KRF("Unsupported stream type " << typeID.str(), Kernel::ErrorType::BadOutput);
}
return true;
}
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmCSVFileReaderDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("CSV File Reader (Deprecated)"); }
CString getAuthorName() const override { return CString("Baptiste Payan"); }
CString getAuthorCompanyName() const override { return CString("INRIA"); }
CString getShortDescription() const override { return CString("Read signal in a CSV (text based) file"); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing/CSV"); }
CString getVersion() const override { return CString("1.0"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_CSVFileReader; }
IPluginObject* create() override { return new CBoxAlgorithmCSVFileReader; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmCSVFileReaderListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addOutput("Output stream", OV_TypeId_Signal);
prototype.addSetting("Filename", OV_TypeId_Filename, "");
prototype.addSetting("Column separator", OV_TypeId_String, ";");
prototype.addSetting("Don't use the file time",OV_TypeId_Boolean, "false");
prototype.addSetting("Samples per buffer", OV_TypeId_Integer, "32");
prototype.addFlag(Kernel::BoxFlag_CanModifyOutput);
prototype.addOutputSupport(OV_TypeId_StreamedMatrix);
prototype.addOutputSupport(OV_TypeId_FeatureVector);
prototype.addOutputSupport(OV_TypeId_ChannelLocalisation);
prototype.addOutputSupport(OV_TypeId_Signal);
prototype.addOutputSupport(OV_TypeId_Spectrum);
prototype.addOutputSupport(OV_TypeId_Stimulations);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_CSVFileReaderDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,258 @@
#include "ovpCBoxAlgorithmCSVFileWriter.h"
#include <string>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
bool CBoxAlgorithmCSVFileWriter::initialize()
{
this->getStaticBoxContext().getInputType(0, m_typeID);
m_separator = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
if (this->getTypeManager().isDerivedFromStream(m_typeID, OV_TypeId_StreamedMatrix))
{
if (m_typeID == OV_TypeId_Signal)
{
m_decoder = new Toolkit::TSignalDecoder<CBoxAlgorithmCSVFileWriter>();
m_decoder->initialize(*this, 0);
}
//else if(m_typeID==OV_TypeId_Spectrum)
//{
// m_decoder=new Toolkit::TSpectrumDecoder < CBoxAlgorithmCSVFileWriter >();
// m_decoder->initialize(*this,0);
//}
else if (m_typeID == OV_TypeId_FeatureVector)
{
m_decoder = new Toolkit::TFeatureVectorDecoder<CBoxAlgorithmCSVFileWriter>();
m_decoder->initialize(*this, 0);
}
else
{
if (m_typeID != OV_TypeId_StreamedMatrix)
{
this->getLogManager() << Kernel::LogLevel_Info << "Input is a type derived from matrix that the box doesn't recognize, decoding as Streamed Matrix\n";
}
m_decoder = new Toolkit::TStreamedMatrixDecoder<CBoxAlgorithmCSVFileWriter>();
m_decoder->initialize(*this, 0);
}
m_realProcess = &CBoxAlgorithmCSVFileWriter::processStreamedMatrix;
}
else if (m_typeID == OV_TypeId_Stimulations)
{
m_decoder = new Toolkit::TStimulationDecoder<CBoxAlgorithmCSVFileWriter>();
m_decoder->initialize(*this, 0);
m_realProcess = &CBoxAlgorithmCSVFileWriter::processStimulation;
}
else { OV_ERROR_KRF("Invalid input type identifier " << this->getTypeManager().getTypeName(m_typeID), Kernel::ErrorType::BadInput); }
m_nSample = 0;
m_firstBuffer = true;
m_headerReceived = false;
return true;
}
bool CBoxAlgorithmCSVFileWriter::uninitialize()
{
if (m_fileStream.is_open()) { m_fileStream.close(); }
if (m_decoder)
{
m_decoder->uninitialize();
delete m_decoder;
}
return true;
}
bool CBoxAlgorithmCSVFileWriter::initializeFile()
{
const CString filename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
const uint64_t precision = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
m_fileStream.open(filename.toASCIIString(), std::ios::trunc);
OV_ERROR_UNLESS_KRF(m_fileStream.is_open(), "Error opening file [" << filename << "] for writing", Kernel::ErrorType::BadFileWrite);
m_fileStream << std::scientific;
m_fileStream.precision(std::streamsize(precision));
return true;
}
bool CBoxAlgorithmCSVFileWriter::processInput(const size_t /*index*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmCSVFileWriter::process()
{
if (!m_fileStream.is_open()) { if (!initializeFile()) { return false; } }
return (this->*m_realProcess)();
}
bool CBoxAlgorithmCSVFileWriter::processStreamedMatrix()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
{
const uint64_t tStart = boxContext.getInputChunkStartTime(0, i);
const uint64_t tEnd = boxContext.getInputChunkEndTime(0, i);
m_decoder->decode(i);
if (m_decoder->isHeaderReceived())
{
if (!m_headerReceived)
{
m_headerReceived = true;
const CMatrix* matrix = static_cast<Toolkit::TStreamedMatrixDecoder<CBoxAlgorithmCSVFileWriter>*>(m_decoder)->getOutputMatrix();
OV_ERROR_UNLESS_KRF(matrix->getDimensionCount() == 1 || matrix->getDimensionCount() == 2,
"Invalid input matrix: must have 1 or 2 dimensions", Kernel::ErrorType::BadInput);
if (matrix->getDimensionCount() == 1 || m_typeID == OV_TypeId_FeatureVector)
{
// The matrix is a vector, make a matrix to represent it. This [n X 1] will get written as a single row due to transpose later
m_oMatrix.resize(matrix->getDimensionSize(0), 1);
for (size_t j = 0; j < matrix->getDimensionSize(0); ++j) { m_oMatrix.setDimensionLabel(0, j, matrix->getDimensionLabel(0, j)); }
}
else
{
// As-is
m_oMatrix.copyDescription(*matrix);
}
// std::cout<<&m_Matrix<<" "<<&op_pMatrix<<"\n";
m_fileStream << "Time (s)";
for (size_t c = 0; c < m_oMatrix.getDimensionSize(0); ++c)
{
std::string label(m_oMatrix.getDimensionLabel(0, c));
while (label.length() > 0 && label[label.length() - 1] == ' ') { label.erase(label.length() - 1); }
m_fileStream << m_separator.toASCIIString() << label;
}
if (m_typeID == OV_TypeId_Signal) { m_fileStream << m_separator.toASCIIString() << "Sampling Rate"; }
else if (m_typeID == OV_TypeId_Spectrum)
{
m_fileStream << m_separator << "Min frequency band";
m_fileStream << m_separator << "Max frequency band";
}
else { }
m_fileStream << "\n";
}
else { OV_ERROR_KRF("Multiple streamed matrix headers received", Kernel::ErrorType::BadInput); }
}
if (m_decoder->isBufferReceived())
{
const CMatrix* matrix = static_cast<Toolkit::TStreamedMatrixDecoder<CBoxAlgorithmCSVFileWriter>*>(m_decoder)->getOutputMatrix();
const size_t nChannel = m_oMatrix.getDimensionSize(0);
const size_t nSample = m_oMatrix.getDimensionSize(1);
//this->getLogManager() << Kernel::LogLevel_Info << " dimsIn " << matrix->getDimensionSize(0) << "," << matrix->getDimensionSize(1) << "\n";
//this->getLogManager() << Kernel::LogLevel_Info << " dimsBuf " << m_oMatrix.getDimensionSize(0) << "," << m_oMatrix.getDimensionSize(1) << "\n";
for (size_t s = 0; s < nSample; ++s)
{
if (m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_FeatureVector) { m_fileStream << CTime(tStart).toSeconds(); }
else if (m_typeID == OV_TypeId_Signal)
{
const uint64_t frequency = static_cast<Toolkit::TSignalDecoder<CBoxAlgorithmCSVFileWriter>*>(m_decoder)->
getOutputSamplingRate();
const uint64_t timeOfNthSample = CTime(frequency, s).time(); // assuming chunk start is 0
const uint64_t sampleTime = tStart + timeOfNthSample;
m_fileStream << CTime(sampleTime).toSeconds();
}
else if (m_typeID == OV_TypeId_Spectrum) { m_fileStream << CTime(tEnd).toSeconds(); }
for (size_t c = 0; c < nChannel; ++c) { m_fileStream << m_separator.toASCIIString() << matrix->getBuffer()[c * nSample + s]; }
if (m_firstBuffer)
{
if (m_typeID == OV_TypeId_Signal)
{
const uint64_t frequency = static_cast<Toolkit::TSignalDecoder<CBoxAlgorithmCSVFileWriter>*>(m_decoder)->
getOutputSamplingRate();
m_fileStream << m_separator.toASCIIString() << uint64_t(frequency);
m_firstBuffer = false;
}
else if (m_typeID == OV_TypeId_Spectrum)
{
// This should not be supported anymore
// This is not the correct formula
const CMatrix* freq = static_cast<Toolkit::TSpectrumDecoder<CBoxAlgorithmCSVFileWriter>*>(m_decoder)->
getOutputFrequencyAbscissa();
const double half = s > 0 ? (freq->getBuffer()[s] - freq->getBuffer()[s - 1]) / 2.0
: (freq->getBuffer()[s + 1] - freq->getBuffer()[s]) / 2.0;
m_fileStream << m_separator.toASCIIString() << (freq->getBuffer()[s] - half);
m_fileStream << m_separator.toASCIIString() << (freq->getBuffer()[s] + half);
}
else { }
}
else
{
if (m_typeID == OV_TypeId_Signal) { m_fileStream << m_separator.toASCIIString(); }
else if (m_typeID == OV_TypeId_Spectrum) { m_fileStream << m_separator.toASCIIString() << m_separator.toASCIIString(); }
else { }
}
m_fileStream << "\n";
}
m_nSample += nSample;
m_firstBuffer = false;
}
if (m_decoder->isEndReceived()) { }
boxContext.markInputAsDeprecated(0, i);
}
return true;
}
bool CBoxAlgorithmCSVFileWriter::processStimulation()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
{
m_decoder->decode(i);
if (m_decoder->isHeaderReceived())
{
if (!m_headerReceived)
{
m_headerReceived = true;
m_fileStream << "Time (s)" << m_separator.toASCIIString() << "Identifier" << m_separator.toASCIIString() << "Duration\n";
}
else { OV_ERROR_KRF("Multiple stimulation headers received", Kernel::ErrorType::BadInput); }
}
if (m_decoder->isBufferReceived())
{
const IStimulationSet* stimSet = static_cast<Toolkit::TStimulationDecoder<CBoxAlgorithmCSVFileWriter>*>(m_decoder)->
getOutputStimulationSet();
for (size_t j = 0; j < stimSet->getStimulationCount(); ++j)
{
m_fileStream << CTime(stimSet->getStimulationDate(j)).toSeconds() << m_separator.toASCIIString()
<< stimSet->getStimulationIdentifier(j) << m_separator.toASCIIString()
<< CTime(stimSet->getStimulationDuration(j)).toSeconds() << "\n";
}
}
if (m_decoder->isEndReceived()) { }
boxContext.markInputAsDeprecated(0, i);
}
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,96 @@
#pragma once
#include "../../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <cstdio>
#include <iostream>
#include <fstream>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CBoxAlgorithmCSVFileWriter final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
CBoxAlgorithmCSVFileWriter() { }
void release() override { delete this; }
bool initialize() override;
bool uninitialize() override;
bool processInput(const size_t index) override;
bool process() override;
bool processStreamedMatrix();
bool processStimulation();
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_CSVFileWriter)
protected:
bool initializeFile();
std::ofstream m_fileStream;
CString m_separator;
CIdentifier m_typeID = CIdentifier::undefined();
bool m_firstBuffer = false;
bool (CBoxAlgorithmCSVFileWriter::*m_realProcess)() = nullptr;
Toolkit::TDecoder<CBoxAlgorithmCSVFileWriter>* m_decoder = nullptr;
CMatrix m_oMatrix; // This represents the properties of the input, no data
uint64_t m_nSample = 0;
bool m_headerReceived = false;
};
class CBoxAlgorithmCSVFileWriterListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmCSVFileWriterDesc final : public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("CSV File Writer (Deprecated)"); }
CString getAuthorName() const override { return CString("Yann Renard"); }
CString getAuthorCompanyName() const override { return CString("INRIA"); }
CString getShortDescription() const override { return CString("Writes signal in a CSV (text based) file"); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing/CSV"); }
CString getVersion() const override { return CString("1.0"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_CSVFileWriter; }
IPluginObject* create() override { return new CBoxAlgorithmCSVFileWriter; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmCSVFileWriterListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Input stream", OV_TypeId_Signal);
prototype.addSetting("Filename", OV_TypeId_Filename, "record-[$core{date}-$core{time}].csv");
prototype.addSetting("Column separator", OV_TypeId_String, ";");
prototype.addSetting("Precision", OV_TypeId_Integer, "10");
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
prototype.addInputSupport(OV_TypeId_Signal);
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
prototype.addInputSupport(OV_TypeId_Spectrum);
prototype.addInputSupport(OV_TypeId_Stimulations);
prototype.addInputSupport(OV_TypeId_FeatureVector);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_CSVFileWriterDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,311 @@
#include "ovpCBoxAlgorithmOVCSVFileReader.h"
#include <sstream>
#include <map>
#include <algorithm>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
bool CBoxAlgorithmOVCSVFileReader::initialize()
{
m_sampling = 0;
m_isHeaderSent = false;
m_isStimulationHeaderSent = false;
this->getStaticBoxContext().getOutputType(0, m_typeID);
const CString filename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
OV_ERROR_UNLESS_KRF(m_readerLib->openFile(filename.toASCIIString(), CSV::EFileAccessMode::Read),
(CSV::ICSVHandler::getLogError(m_readerLib->getLastLogError()) + (m_readerLib->getLastErrorString().empty() ? "" : ". Details: " +
m_readerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
m_nSamplePerBuffer = 1;
if (m_typeID == OV_TypeId_Signal)
{
m_algorithmEncoder = new Toolkit::TSignalEncoder<CBoxAlgorithmOVCSVFileReader>(*this, 0);
m_readerLib->setFormatType(CSV::EStreamType::Signal);
}
else if (m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_CovarianceMatrix)
{
m_algorithmEncoder = new Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmOVCSVFileReader>(*this, 0);
m_readerLib->setFormatType(CSV::EStreamType::StreamedMatrix);
}
else if (m_typeID == OV_TypeId_FeatureVector)
{
m_algorithmEncoder = new Toolkit::TFeatureVectorEncoder<CBoxAlgorithmOVCSVFileReader>(*this, 0);
m_readerLib->setFormatType(CSV::EStreamType::FeatureVector);
}
else if (m_typeID == OV_TypeId_Spectrum)
{
m_algorithmEncoder = new Toolkit::TSpectrumEncoder<CBoxAlgorithmOVCSVFileReader>(*this, 0);
m_readerLib->setFormatType(CSV::EStreamType::Spectrum);
}
else { OV_ERROR_KRF("Output is a type derived from matrix that the box doesn't recognize support", Kernel::ErrorType::BadInput); }
OV_ERROR_UNLESS_KRF(m_stimEncoder.initialize(*this, 1), "Error during stimulation encoder initialize", Kernel::ErrorType::Internal);
const char* msg = (CSV::ICSVHandler::getLogError(m_readerLib->getLastLogError()) + (m_readerLib->getLastErrorString().empty() ? ""
: ". Details: " + m_readerLib->getLastErrorString())).c_str();
if (m_typeID == OV_TypeId_Signal)
{
OV_ERROR_UNLESS_KRF(m_readerLib->getSignalInformation(m_channelNames, m_sampling, m_nSamplePerBuffer), msg, Kernel::ErrorType::Internal);
}
else if (m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_CovarianceMatrix)
{
OV_ERROR_UNLESS_KRF(m_readerLib->getStreamedMatrixInformation(m_dimSizes, m_channelNames), msg, Kernel::ErrorType::Internal);
}
else if (m_typeID == OV_TypeId_FeatureVector)
{
OV_ERROR_UNLESS_KRF(m_readerLib->getFeatureVectorInformation(m_channelNames), msg, Kernel::ErrorType::Internal);
}
else if (m_typeID == OV_TypeId_Spectrum)
{
OV_ERROR_UNLESS_KRF(m_readerLib->getSpectrumInformation(m_channelNames, m_frequencyAbscissa, m_sampling), msg, Kernel::ErrorType::Internal);
}
return true;
}
bool CBoxAlgorithmOVCSVFileReader::uninitialize()
{
m_channelNames.clear();
m_dimSizes.clear();
m_frequencyAbscissa.clear();
m_algorithmEncoder.uninitialize();
OV_ERROR_UNLESS_KRF(m_stimEncoder.uninitialize(), "Failed to uninitialize stimulation encoder", Kernel::ErrorType::Internal);
return true;
}
bool CBoxAlgorithmOVCSVFileReader::processClock(Kernel::CMessageClock& /*msg*/)
{
OV_ERROR_UNLESS_KRF(getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess(), "Failed to mark clock algorithm as ready to process",
Kernel::ErrorType::Internal);
return true;
}
bool CBoxAlgorithmOVCSVFileReader::process()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
CMatrix* matrix = m_algorithmEncoder.getInputMatrix();
// encode Header if not already encoded
if (!m_isHeaderSent)
{
if (m_typeID == OV_TypeId_Signal)
{
matrix->resize(m_channelNames.size(), m_nSamplePerBuffer);
size_t index = 0;
for (const std::string& channelName : m_channelNames)
{
OV_FATAL_UNLESS_K(matrix->setDimensionLabel(0, index++, channelName.c_str()), "Failed to set dimension label", Kernel::ErrorType::Internal);
}
m_algorithmEncoder.getInputSamplingRate() = m_sampling;
}
else if (m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_CovarianceMatrix)
{
OV_FATAL_UNLESS_K(matrix->setDimensionCount(m_dimSizes.size()), "Failed to set dimension count", Kernel::ErrorType::Internal);
size_t prevDimSize = 0;
for (size_t d1 = 0; d1 < m_dimSizes.size(); ++d1)
{
OV_FATAL_UNLESS_K(matrix->setDimensionSize(d1, m_dimSizes[d1]), "Failed to set dimension size " << d1 + 1, Kernel::ErrorType::Internal);
for (size_t d2 = 0; d2 < m_dimSizes[d1]; ++d2)
{
OV_FATAL_UNLESS_K(matrix->setDimensionLabel(d1, d2, m_channelNames[prevDimSize + d2].c_str()), "Failed to set dimension label",
Kernel::ErrorType::Internal);
}
prevDimSize += m_dimSizes[d1];
}
}
else if (m_typeID == OV_TypeId_FeatureVector)
{
matrix->resize(m_channelNames.size());
size_t index = 0;
for (const std::string& channelName : m_channelNames)
{
OV_FATAL_UNLESS_K(matrix->setDimensionLabel(0, index++, channelName.c_str()), "Failed to set dimension label", Kernel::ErrorType::Internal);
}
}
else if (m_typeID == OV_TypeId_Spectrum)
{
CMatrix* frequencyAbscissaMatrix = m_algorithmEncoder.getInputFrequencyAbcissa();
matrix->resize(m_channelNames.size(), m_frequencyAbscissa.size());
frequencyAbscissaMatrix->resize(m_frequencyAbscissa.size());
size_t index = 0;
for (const std::string& channelName : m_channelNames)
{
OV_FATAL_UNLESS_K(matrix->setDimensionLabel(0, index++, channelName.c_str()), "Failed to set dimension label", Kernel::ErrorType::Internal);
}
index = 0;
for (const double& frequencyAbscissaValue : m_frequencyAbscissa)
{
frequencyAbscissaMatrix->getBuffer()[index] = frequencyAbscissaValue;
OV_FATAL_UNLESS_K(matrix->setDimensionLabel(1, index++, std::to_string(frequencyAbscissaValue).c_str()), "Failed to set dimension label",
Kernel::ErrorType::Internal);
}
m_algorithmEncoder.getInputSamplingRate() = m_sampling;
}
OV_ERROR_UNLESS_KRF(m_algorithmEncoder.encodeHeader(), "Failed to encode signal header", Kernel::ErrorType::Internal);
m_isHeaderSent = true;
OV_ERROR_UNLESS_KRF(boxContext.markOutputAsReadyToSend(0, 0, 0), "Failed to mark signal header as ready to send", Kernel::ErrorType::Internal);
}
const double currentTime = CTime(this->getPlayerContext().getCurrentTime()).toSeconds();
if (!m_readerLib->hasDataToRead() && m_savedChunks.empty()) { return true; }
// Fill the chunk buffer if there is no enough data.
if ((m_savedChunks.empty() || m_savedChunks.back().startTime < currentTime) && m_readerLib->hasDataToRead())
{
do
{
std::vector<CSV::SMatrixChunk> matrixChunk;
std::vector<CSV::SStimulationChunk> stimulationChunk;
OV_ERROR_UNLESS_KRF(m_readerLib->readSamplesAndEventsFromFile(1, matrixChunk, stimulationChunk),
(CSV::ICSVHandler::getLogError(m_readerLib->getLastLogError()) + (m_readerLib->getLastErrorString().empty() ? "" : ". Details: "
+ m_readerLib->getLastErrorString())).c_str(),
Kernel::ErrorType::Internal);
m_savedChunks.insert(m_savedChunks.end(), matrixChunk.begin(), matrixChunk.end());
m_savedStimulations.insert(m_savedStimulations.end(), stimulationChunk.begin(), stimulationChunk.end());
} while (!m_savedChunks.empty() && m_savedChunks.back().startTime < currentTime && m_readerLib->hasDataToRead());
}
if (!m_savedChunks.empty())
{
const double chunkStartTime = m_savedChunks.cbegin()->startTime;
const double chunkEndTime = m_savedChunks.back().endTime;
// send stimulations chunk even if there is no stimulations, chunks have to be continued
OV_ERROR_UNLESS_KRF(this->processStimulation(chunkStartTime, chunkEndTime), "Error during stimulation process", Kernel::ErrorType::Internal);
size_t chunksToRemove = 0;
for (const CSV::SMatrixChunk& chunk : m_savedChunks)
{
if (currentTime > chunk.startTime)
{
// move read matrix into buffer to encode
std::move(chunk.matrix.begin(), chunk.matrix.end(), matrix->getBuffer());
OV_ERROR_UNLESS_KRF(m_algorithmEncoder.encodeBuffer(), "Failed to encode signal buffer", Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(
boxContext.markOutputAsReadyToSend(0, CTime(chunk.startTime).time(), CTime(chunk.endTime).time()),
"Failed to mark signal output as ready to send",
Kernel::ErrorType::Internal);
chunksToRemove++;
}
else { break; }
}
// If there is no more data to send, we push the end.
if (m_savedChunks.size() == chunksToRemove && !m_readerLib->hasDataToRead())
{
OV_ERROR_UNLESS_KRF(m_algorithmEncoder.encodeEnd(), "Failed to encode end.", Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(
boxContext.markOutputAsReadyToSend(0, CTime(m_savedChunks.back().startTime).time(), CTime(m_savedChunks.back().endTime).time()),
"Failed to mark signal output as ready to send", Kernel::ErrorType::Internal);
}
if (chunksToRemove != 0) { m_savedChunks.erase(m_savedChunks.begin(), m_savedChunks.begin() + chunksToRemove); }
}
return true;
}
bool CBoxAlgorithmOVCSVFileReader::processStimulation(const double startTime, const double endTime)
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
if (!m_isStimulationHeaderSent)
{
OV_ERROR_UNLESS_KRF(m_stimEncoder.encodeHeader(), "Failed to encode stimulation header", Kernel::ErrorType::Internal);
m_isStimulationHeaderSent = true;
OV_ERROR_UNLESS_KRF(boxContext.markOutputAsReadyToSend(1, 0, 0), "Failed to mark stimulation header as ready to send", Kernel::ErrorType::Internal);
}
IStimulationSet* stimulationSet = m_stimEncoder.getInputStimulationSet();
stimulationSet->clear();
const uint64_t stimulationChunkStartTime = m_lastStimulationDate;
const uint64_t currentTime = getPlayerContext().getCurrentTime();
if (m_savedStimulations.empty())
{
if (currentTime > m_lastStimulationDate)
{
m_lastStimulationDate = currentTime;
OV_ERROR_UNLESS_KRF(m_stimEncoder.encodeBuffer(), "Failed to encode stimulation buffer", Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(boxContext.markOutputAsReadyToSend(1, stimulationChunkStartTime, currentTime),
"Failed to mark stimulation output as ready to send", Kernel::ErrorType::Internal);
}
}
else
{
auto it = m_savedStimulations.begin();
for (; it != m_savedStimulations.end(); ++it)
{
const double stimulationDate = it->date;
if (startTime <= stimulationDate && stimulationDate <= endTime)
{
stimulationSet->appendStimulation(it->id, CTime(it->date).time(), CTime(it->duration).time());
m_lastStimulationDate = CTime(it->date).time();
}
else
{
const std::string message = "The stimulation is not synced with the stream and will be ignored: [Value: "
+ std::to_string(it->id) + " | Date: " + std::to_string(it->date) +
" | Duration: " + std::to_string(it->duration) + "]";
OV_WARNING_K(message.c_str());
}
}
if (it != m_savedStimulations.begin()) { m_savedStimulations.erase(m_savedStimulations.begin(), it); }
OV_ERROR_UNLESS_KRF(m_stimEncoder.encodeBuffer(), "Failed to encode stimulation buffer", Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(boxContext.markOutputAsReadyToSend(1, stimulationChunkStartTime, m_lastStimulationDate),
"Failed to mark stimulation output as ready to send", Kernel::ErrorType::Internal);
// If there is no more data to send, we push the end.
if (m_savedStimulations.empty() && !m_readerLib->hasDataToRead())
{
OV_ERROR_UNLESS_KRF(m_algorithmEncoder.encodeEnd(), "Failed to encode end.", Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(boxContext.markOutputAsReadyToSend(1, stimulationChunkStartTime, currentTime),
"Failed to mark signal output as ready to send", Kernel::ErrorType::Internal);
}
}
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,117 @@
#pragma once
#include "../../ovp_defines.h"
#include <cstdio>
#include <memory>
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include "csv/ovICSV.h"
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CBoxAlgorithmOVCSVFileReader final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
CBoxAlgorithmOVCSVFileReader() : m_readerLib(CSV::createCSVHandler(), CSV::releaseCSVHandler) { }
void release() override { delete this; }
uint64_t getClockFrequency() override { return 128LL << 32; }
bool initialize() override;
bool uninitialize() override;
bool processClock(Kernel::CMessageClock& msg) override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_OVCSVFileReader)
private:
bool processStimulation(double startTime, double endTime);
std::unique_ptr<CSV::ICSVHandler, decltype(&CSV::releaseCSVHandler)> m_readerLib;
Toolkit::TGenericEncoder<CBoxAlgorithmOVCSVFileReader> m_algorithmEncoder;
Toolkit::TStimulationEncoder<CBoxAlgorithmOVCSVFileReader> m_stimEncoder;
std::deque<CSV::SMatrixChunk> m_savedChunks;
std::deque<CSV::SStimulationChunk> m_savedStimulations;
uint64_t m_lastStimulationDate = 0;
CIdentifier m_typeID = CIdentifier::undefined();
std::vector<std::string> m_channelNames;
std::vector<size_t> m_dimSizes;
size_t m_sampling = 0;
size_t m_nSamplePerBuffer = 0;
bool m_isHeaderSent = false;
bool m_isStimulationHeaderSent = false;
std::vector<double> m_frequencyAbscissa;
};
class CBoxAlgorithmOVCSVFileReaderListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool onOutputTypeChanged(Kernel::IBox& box, const size_t index) override
{
CIdentifier typeID = CIdentifier::undefined();
box.getOutputType(index, typeID);
if (index == 0 && typeID == OV_TypeId_Stimulations)
{
OV_ERROR_UNLESS_KRF(box.setOutputType(index, OV_TypeId_Signal), "Failed to reset output type to signal", Kernel::ErrorType::Internal);
}
else if (index == 1 && typeID != OV_TypeId_Stimulations)
{
OV_ERROR_UNLESS_KRF(box.setOutputType(index, OV_TypeId_Stimulations), "Failed to reset output type to stimulations", Kernel::ErrorType::Internal);
}
else if (index > 1) { OV_ERROR_UNLESS_KRF(false, "The index of the output does not exist", Kernel::ErrorType::Internal); }
return true;
}
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmOVCSVFileReaderDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("CSV File Reader"); }
CString getAuthorName() const override { return CString("Victor Herlin"); }
CString getAuthorCompanyName() const override { return CString("Mensia Technologies SA"); }
CString getShortDescription() const override { return CString("Read signal in a CSV (text based) file"); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing/CSV"); }
CString getVersion() const override { return CString("1.1"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.1.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.3.3"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_OVCSVFileReader; }
IPluginObject* create() override { return new CBoxAlgorithmOVCSVFileReader; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmOVCSVFileReaderListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& BoxAlgorithmPrototype) const override
{
BoxAlgorithmPrototype.addOutput("Output stream", OV_TypeId_Signal);
BoxAlgorithmPrototype.addOutput("Output stimulation", OV_TypeId_Stimulations);
BoxAlgorithmPrototype.addSetting("Filename", OV_TypeId_Filename, "");
BoxAlgorithmPrototype.addFlag(Kernel::BoxFlag_CanModifyOutput);
BoxAlgorithmPrototype.addOutputSupport(OV_TypeId_Signal);
BoxAlgorithmPrototype.addOutputSupport(OV_TypeId_Spectrum);
BoxAlgorithmPrototype.addOutputSupport(OV_TypeId_FeatureVector);
BoxAlgorithmPrototype.addOutputSupport(OV_TypeId_StreamedMatrix);
BoxAlgorithmPrototype.addOutputSupport(OV_TypeId_CovarianceMatrix);
BoxAlgorithmPrototype.addOutputSupport(OV_TypeId_Stimulations);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_OVCSVFileReaderDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,337 @@
#include "ovpCBoxAlgorithmOVCSVFileWriter.h"
#include <fs/Files.h>
#include <string>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
CBoxAlgorithmOVCSVFileWriter::CBoxAlgorithmOVCSVFileWriter()
: m_writerLib(CSV::createCSVHandler(), CSV::releaseCSVHandler) {}
bool CBoxAlgorithmOVCSVFileWriter::initialize()
{
m_isFileOpen = false;
m_epoch = 0;
OV_ERROR_UNLESS_KRF(this->getStaticBoxContext().getInputType(0, m_typeID), "Error while getting input type", Kernel::ErrorType::Internal);
if (m_typeID == OV_TypeId_Signal)
{
m_writerLib->setFormatType(CSV::EStreamType::Signal);
m_streamDecoder = new Toolkit::TSignalDecoder<CBoxAlgorithmOVCSVFileWriter>(*this, 0);
}
else if (m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_CovarianceMatrix)
{
m_writerLib->setFormatType(CSV::EStreamType::StreamedMatrix);
m_streamDecoder = new Toolkit::TStreamedMatrixDecoder<CBoxAlgorithmOVCSVFileWriter>(*this, 0);
}
else if (m_typeID == OV_TypeId_FeatureVector)
{
m_writerLib->setFormatType(CSV::EStreamType::FeatureVector);
m_streamDecoder = new Toolkit::TFeatureVectorDecoder<CBoxAlgorithmOVCSVFileWriter>(*this, 0);
}
else if (m_typeID == OV_TypeId_Spectrum)
{
m_writerLib->setFormatType(CSV::EStreamType::Spectrum);
m_streamDecoder = new Toolkit::TSpectrumDecoder<CBoxAlgorithmOVCSVFileWriter>(*this, 0);
}
else { OV_ERROR_KRF("Input is a type derived from matrix that the box doesn't recognize", Kernel::ErrorType::BadInput); }
OV_ERROR_UNLESS_KRF(m_stimDecoder.initialize(*this, 1), "Error while stimulation decoder initialization", Kernel::ErrorType::Internal);
const CString filename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
m_writerLib->setOutputFloatPrecision(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1));
m_appendData = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
m_lastMatrixOnly = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3);
m_writerLib->setLastMatrixOnlyMode(m_lastMatrixOnly);
if (!m_appendData)
{
OV_ERROR_UNLESS_KRF(m_writerLib->openFile(filename.toASCIIString(), CSV::EFileAccessMode::Write),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
m_writeHeader = true;
}
else
{
FILE* file = FS::Files::open(filename, "r");
if (file)
{
fseek(file, 0, SEEK_END);
m_writeHeader = ftell(file) == 0;
fclose(file);
}
OV_ERROR_UNLESS_KRF(m_writerLib->openFile(filename.toASCIIString(), CSV::EFileAccessMode::Append),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
m_isHeaderReceived = false;
return true;
}
bool CBoxAlgorithmOVCSVFileWriter::uninitialize()
{
m_streamDecoder.uninitialize();
m_stimDecoder.uninitialize();
OV_ERROR_UNLESS_KRF(m_writerLib->noEventsUntilDate(std::numeric_limits<double>::max()),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" : "Details: "
+ m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(m_writerLib->writeAllDataToFile(),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" : "Details: "
+ m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(m_writerLib->closeFile(),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" : "Details: "
+ m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
return true;
}
bool CBoxAlgorithmOVCSVFileWriter::processInput(const size_t /*index*/)
{
OV_ERROR_UNLESS_KRF(getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess(), "Error while marking algorithm as ready to process", Kernel::ErrorType::Internal);
return true;
}
bool CBoxAlgorithmOVCSVFileWriter::process()
{
OV_ERROR_UNLESS_KRF(this->processStreamedMatrix(), "Error have been thrown during streamed matrix process", Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(this->processStimulation(), "Error have been thrown during stimulation process", Kernel::ErrorType::Internal);
// write into the library
if (!m_lastMatrixOnly)
{
OV_ERROR_UNLESS_KRF(m_writerLib->writeDataToFile(),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
return true;
}
bool CBoxAlgorithmOVCSVFileWriter::processStreamedMatrix()
{
Kernel::IBoxIO& dynamicBoxContext = this->getDynamicBoxContext();
for (size_t i = 0; i < dynamicBoxContext.getInputChunkCount(0); ++i)
{
OV_ERROR_UNLESS_KRF(m_streamDecoder.decode(i), "Failed to decode chunk", Kernel::ErrorType::Internal);
// represents the properties of the input, no data
const CMatrix* matrix = m_streamDecoder.getOutputMatrix();
if (m_streamDecoder.isHeaderReceived())
{
OV_ERROR_UNLESS_KRF(!m_isHeaderReceived, "Multiple streamed matrix headers received", Kernel::ErrorType::BadInput);
m_isHeaderReceived = true;
if (m_typeID == OV_TypeId_Signal)
{
OV_ERROR_UNLESS_KRF(m_streamDecoder.getOutputSamplingRate() != 0, "Sampling rate can not be 0", Kernel::ErrorType::BadInput);
std::vector<std::string> dimensionLabels;
for (size_t j = 0; j < matrix->getDimensionSize(0); ++j) { dimensionLabels.push_back(matrix->getDimensionLabel(0, j)); }
OV_ERROR_UNLESS_KRF(
m_writerLib->setSignalInformation(dimensionLabels, m_streamDecoder.getOutputSamplingRate(), matrix->getDimensionSize(1)),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" : "Details: " +
m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
if (m_writeHeader)
{
OV_ERROR_UNLESS_KRF(m_writerLib->writeHeaderToFile(),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ?
"" : "Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
}
else if (m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_CovarianceMatrix)
{
std::vector<std::string> dimensionLabels;
std::vector<size_t> dimensionSizes;
for (size_t d1 = 0; d1 < matrix->getDimensionCount(); ++d1)
{
dimensionSizes.push_back(matrix->getDimensionSize(d1));
for (size_t d2 = 0; d2 < matrix->getDimensionSize(d1); ++d2) { dimensionLabels.push_back(matrix->getDimensionLabel(d1, d2)); }
}
OV_ERROR_UNLESS_KRF(m_writerLib->setStreamedMatrixInformation(dimensionSizes, dimensionLabels),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
if (m_writeHeader)
{
OV_ERROR_UNLESS_KRF(m_writerLib->writeHeaderToFile(),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ?
"" : "Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
}
else if (m_typeID == OV_TypeId_FeatureVector)
{
std::vector<std::string> channelsLabels;
for (size_t j = 0; j < matrix->getDimensionSize(0); ++j) { channelsLabels.push_back(matrix->getDimensionLabel(0, j)); }
OV_ERROR_UNLESS_KRF(m_writerLib->setFeatureVectorInformation(channelsLabels),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
if (m_writeHeader)
{
OV_ERROR_UNLESS_KRF(m_writerLib->writeHeaderToFile(),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ?
"" : "Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
}
else if (m_typeID == OV_TypeId_Spectrum)
{
const CMatrix* frequencyAbscissaMatrix = m_streamDecoder.getOutputFrequencyAbcissa();
std::vector<std::string> channelsLabels;
std::vector<double> frequencyAbscissa;
for (size_t j = 0; j < matrix->getDimensionSize(0); ++j) { channelsLabels.push_back(matrix->getDimensionLabel(0, j)); }
for (size_t j = 0; j < frequencyAbscissaMatrix->getDimensionSize(0); ++j)
{
frequencyAbscissa.push_back(frequencyAbscissaMatrix->getBuffer()[j]);
}
OV_ERROR_UNLESS_KRF(m_writerLib->setSpectrumInformation(channelsLabels, frequencyAbscissa, m_streamDecoder.getOutputSamplingRate()),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
if (m_writeHeader)
{
OV_ERROR_UNLESS_KRF(m_writerLib->writeHeaderToFile(),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ?
"" : "Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
}
}
if (m_streamDecoder.isBufferReceived())
{
const CMatrix* imatrix = m_streamDecoder.getOutputMatrix();
if (m_typeID == OV_TypeId_Signal)
{
const uint64_t sampling = m_streamDecoder.getOutputSamplingRate();
const uint64_t chunkStartTime = dynamicBoxContext.getInputChunkStartTime(0, i);
const size_t nChannel = matrix->getDimensionSize(0);
const size_t nSample = matrix->getDimensionSize(1);
for (size_t sampleIndex = 0; sampleIndex < nSample; ++sampleIndex)
{
std::vector<double> matrixValues;
// get starting and ending time
const uint64_t timeOfNthSample = CTime(sampling, sampleIndex).time(); // assuming chunk start is 0
const uint64_t sampleTime = chunkStartTime + timeOfNthSample;
const double startTime = CTime(sampleTime).toSeconds();
const uint64_t timeOfNthAndOneSample = CTime(sampling, sampleIndex + 1).time();
const double endTime = CTime(chunkStartTime + timeOfNthAndOneSample).toSeconds();
// get matrix values
for (size_t channelIndex = 0; channelIndex < nChannel; ++channelIndex)
{
matrixValues.push_back(imatrix->getBuffer()[channelIndex * nSample + sampleIndex]);
}
// add sample to the library
OV_ERROR_UNLESS_KRF(m_writerLib->addSample({ startTime, endTime, matrixValues, m_epoch }),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ?
"" : "Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
}
else if (m_typeID == OV_TypeId_StreamedMatrix || m_typeID == OV_TypeId_CovarianceMatrix)
{
const double startTime = CTime(dynamicBoxContext.getInputChunkStartTime(0, i)).toSeconds();
const double endTime = CTime(dynamicBoxContext.getInputChunkEndTime(0, i)).toSeconds();
const std::vector<double> streamedMatrixValues(matrix->getBuffer(), matrix->getBuffer() + matrix->getBufferElementCount());
OV_ERROR_UNLESS_KRF(m_writerLib->addSample({ startTime, endTime, streamedMatrixValues, m_epoch }),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
else if (m_typeID == OV_TypeId_FeatureVector)
{
const double startTime = CTime(dynamicBoxContext.getInputChunkStartTime(0, i)).toSeconds();
const double endTime = CTime(dynamicBoxContext.getInputChunkEndTime(0, i)).toSeconds();
const CMatrix* zmatrix = m_streamDecoder.getOutputMatrix();
const std::vector<double> streamedMatrixValues(zmatrix->getBuffer(), zmatrix->getBuffer() + zmatrix->getBufferElementCount());
OV_ERROR_UNLESS_KRF(m_writerLib->addSample({ startTime, endTime, streamedMatrixValues, m_epoch }),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
else if (m_typeID == OV_TypeId_Spectrum)
{
const double startTime = CTime(dynamicBoxContext.getInputChunkStartTime(0, i)).toSeconds();
const double endTime = CTime(dynamicBoxContext.getInputChunkEndTime(0, i)).toSeconds();
const std::vector<double> streamedMatrixValues(matrix->getBuffer(), matrix->getBuffer() + matrix->getBufferElementCount());
OV_ERROR_UNLESS_KRF(m_writerLib->addSample({ startTime, endTime, streamedMatrixValues, m_epoch }),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
m_epoch++;
}
OV_ERROR_UNLESS_KRF(dynamicBoxContext.markInputAsDeprecated(0, i), "Fail to mark input as deprecated", Kernel::ErrorType::Internal);
}
return true;
}
bool CBoxAlgorithmOVCSVFileWriter::processStimulation()
{
Kernel::IBoxIO& dynamicBoxContext = this->getDynamicBoxContext();
// add every stimulation received
for (size_t i = 0; i < dynamicBoxContext.getInputChunkCount(1); ++i)
{
OV_ERROR_UNLESS_KRF(m_stimDecoder.decode(i), "Failed to decode stimulation chunk", Kernel::ErrorType::Internal);
if (m_stimDecoder.isBufferReceived())
{
const IStimulationSet* stimulationSet = m_stimDecoder.getOutputStimulationSet();
// for each stimulation, get its informations
for (size_t j = 0; j < stimulationSet->getStimulationCount(); ++j)
{
OV_ERROR_UNLESS_KRF(m_writerLib->addEvent({ stimulationSet->getStimulationIdentifier(j),
CTime(stimulationSet->getStimulationDate(j)).toSeconds(),
CTime(stimulationSet->getStimulationDuration(j)).toSeconds() }),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" :
"Details: " + m_writerLib->getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
// set NoEventUntilDate to prevent time that will be empty of stimulations until the end of the last chunk
OV_ERROR_UNLESS_KRF(
m_writerLib->noEventsUntilDate(CTime(dynamicBoxContext.getInputChunkEndTime(1, (dynamicBoxContext.getInputChunkCount(1) - 1))).toSeconds()),
(CSV::ICSVHandler::getLogError(m_writerLib->getLastLogError()) + (m_writerLib->getLastErrorString().empty() ? "" : "Details: " + m_writerLib->
getLastErrorString())).c_str(), Kernel::ErrorType::Internal);
}
OV_ERROR_UNLESS_KRF(dynamicBoxContext.markInputAsDeprecated(1, i), "Failed to mark stimulations input as deprecated", Kernel::ErrorType::Internal);
}
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,113 @@
#pragma once
#include "../../ovp_defines.h"
#include <cstdio>
#include <memory>
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include "csv/ovICSV.h"
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CBoxAlgorithmOVCSVFileWriter final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
CBoxAlgorithmOVCSVFileWriter();
void release() override { delete this; }
bool initialize() override;
bool uninitialize() override;
bool processInput(const size_t index) override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_OVCSVFileWriter)
private:
bool processStreamedMatrix();
bool processStimulation();
std::unique_ptr<CSV::ICSVHandler, decltype(&CSV::releaseCSVHandler)> m_writerLib;
CIdentifier m_typeID = CIdentifier::undefined();
Toolkit::TGenericDecoder<CBoxAlgorithmOVCSVFileWriter> m_streamDecoder;
Toolkit::TStimulationDecoder<CBoxAlgorithmOVCSVFileWriter> m_stimDecoder;
uint64_t m_epoch = 0;
bool m_isHeaderReceived = false;
bool m_isFileOpen = false;
bool m_appendData = false;
bool m_lastMatrixOnly = false;
bool m_writeHeader = true;
};
class CBoxAlgorithmOVCSVFileWriterListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool onInputTypeChanged(Kernel::IBox& box, const size_t index) override
{
if (index == 1)
{
CIdentifier typeID = CIdentifier::undefined();
box.getInputType(1, typeID);
if (typeID != OV_TypeId_Stimulations)
{
box.setInputType(1, OV_TypeId_Stimulations);
return true;
}
}
return true;
}
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmOVCSVFileWriterDesc final : public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("CSV File Writer"); }
CString getAuthorName() const override { return CString("Victor Herlin"); }
CString getAuthorCompanyName() const override { return CString("Mensia Technologies SA"); }
CString getShortDescription() const override { return CString("Writes signal in a CSV (text based) file"); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing/CSV"); }
CString getVersion() const override { return CString("1.0"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.1.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.1.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_OVCSVFileWriter; }
IPluginObject* create() override { return new CBoxAlgorithmOVCSVFileWriter; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmOVCSVFileWriterListener; }
void releaseBoxListener(IBoxListener* boxListener) const override { delete boxListener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Input stream", OV_TypeId_Signal);
prototype.addInput("Stimulations stream", OV_TypeId_Stimulations);
prototype.addSetting("Filename", OV_TypeId_Filename, "record-[$core{date}-$core{time}].csv");
prototype.addSetting("Precision", OV_TypeId_Integer, "10");
prototype.addSetting("Append data", OV_TypeId_Boolean, "false");
prototype.addSetting("Only last matrix", OV_TypeId_Boolean, "false");
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
prototype.addInputSupport(OV_TypeId_Signal);
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
prototype.addInputSupport(OV_TypeId_Spectrum);
prototype.addInputSupport(OV_TypeId_FeatureVector);
prototype.addInputSupport(OV_TypeId_CovarianceMatrix);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_OVCSVFileWriterDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,268 @@
#include "ovpCBoxAlgorithmGenericStreamReader.h"
#include <iostream>
#include <limits>
#include <fs/Files.h>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
CBoxAlgorithmGenericStreamReader::CBoxAlgorithmGenericStreamReader() : m_reader(*this) {}
uint64_t CBoxAlgorithmGenericStreamReader::getClockFrequency() { return 128LL << 32; } // the box clock frequency
bool CBoxAlgorithmGenericStreamReader::initialize()
{
m_filename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
m_pending = false;
m_streamIdxToOutputIdxs.clear();
m_streamIdxToTypeIDs.clear();
return true;
}
bool CBoxAlgorithmGenericStreamReader::uninitialize()
{
if (m_file)
{
fclose(m_file);
m_file = nullptr;
}
return true;
}
bool CBoxAlgorithmGenericStreamReader::initializeFile()
{
m_file = FS::Files::open(m_filename.toASCIIString(), "rb");
OV_ERROR_UNLESS_KRF(m_file, "Error opening file [" << m_filename << "] for reading", Kernel::ErrorType::BadFileRead);
return true;
}
bool CBoxAlgorithmGenericStreamReader::processClock(Kernel::CMessageClock& /*msg*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmGenericStreamReader::process()
{
if (m_file == nullptr) { if (!initializeFile()) { return false; } }
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
const size_t nInput = this->getStaticBoxContext().getOutputCount();
const uint64_t time = this->getPlayerContext().getCurrentTime();
bool finished = false;
while (!finished && (!feof(m_file) || m_pending))
{
if (m_pending)
{
if (m_endTime <= time)
{
OV_ERROR_UNLESS_KRF(m_outputIdx < nInput,
"Stream index " << m_outputIdx << " can not be output from this box because it does not have enough outputs",
Kernel::ErrorType::BadOutput);
boxContext.getOutputChunk(m_outputIdx)->append(m_pendingChunk);
boxContext.markOutputAsReadyToSend(m_outputIdx, m_startTime, m_endTime);
m_pending = false;
}
else { finished = true; }
}
else
{
bool justStarted = true;
while (!feof(m_file) && m_reader.getCurrentNodeID() == EBML::CIdentifier())
{
uint8_t byte;
const size_t s = fread(&byte, sizeof(uint8_t), 1, m_file);
OV_ERROR_UNLESS_KRF(s == 1 || justStarted, "Unexpected EOF in " << m_filename, Kernel::ErrorType::BadParsing);
m_reader.processData(&byte, sizeof(byte));
justStarted = false;
}
if (!feof(m_file) && m_reader.getCurrentNodeSize() != 0)
{
m_swap.setSize(m_reader.getCurrentNodeSize(), true);
const size_t s = size_t(fread(m_swap.getDirectPointer(), sizeof(uint8_t), size_t(m_swap.getSize()), m_file));
OV_ERROR_UNLESS_KRF(s == m_swap.getSize(), "Unexpected EOF in " << m_filename, Kernel::ErrorType::BadParsing);
m_pendingChunk.setSize(0, true);
m_startTime = std::numeric_limits<uint64_t>::max();
m_endTime = std::numeric_limits<uint64_t>::max();
m_outputIdx = std::numeric_limits<size_t>::max();
m_reader.processData(m_swap.getDirectPointer(), m_swap.getSize());
}
}
}
return true;
}
bool CBoxAlgorithmGenericStreamReader::isMasterChild(const EBML::CIdentifier& identifier)
{
if (identifier == EBML_Identifier_Header) { return true; }
if (identifier == OVP_NodeId_OpenViBEStream_Header) { return true; }
if (identifier == OVP_NodeId_OpenViBEStream_Header_Compression) { return false; }
if (identifier == OVP_NodeId_OpenViBEStream_Header_StreamType) { return false; }
if (identifier == OVP_NodeId_OpenViBEStream_Buffer) { return true; }
if (identifier == OVP_NodeId_OpenViBEStream_Buffer_StreamIndex) { return false; }
if (identifier == OVP_NodeId_OpenViBEStream_Buffer_StartTime) { return false; }
if (identifier == OVP_NodeId_OpenViBEStream_Buffer_EndTime) { return false; }
if (identifier == OVP_NodeId_OpenViBEStream_Buffer_Content) { return false; }
return false;
}
void CBoxAlgorithmGenericStreamReader::openChild(const EBML::CIdentifier& identifier)
{
m_nodes.push(identifier);
EBML::CIdentifier& top = m_nodes.top();
if (top == EBML_Identifier_Header) { m_hasEBMLHeader = true; }
if (top == OVP_NodeId_OpenViBEStream_Header)
{
if (!m_hasEBMLHeader)
{
this->getLogManager() << Kernel::LogLevel_Info << "The file " << m_filename << " uses an outdated (but still compatible) version of the .ov file format\n";
}
}
if (top == OVP_NodeId_OpenViBEStream_Header)
{
m_streamIdxToOutputIdxs.clear();
m_streamIdxToTypeIDs.clear();
}
}
void CBoxAlgorithmGenericStreamReader::processChildData(const void* buffer, const size_t size)
{
EBML::CIdentifier& top = m_nodes.top();
// Uncomment this when ebml version will be used
//if(top == EBML_Identifier_EBMLVersion) { const uint64_t versionNumber=(uint64_t)m_readerHelper.getUInt(buffer, size); }
if (top == OVP_NodeId_OpenViBEStream_Header_Compression)
{
if (m_readerHelper.getUInt(buffer, size) != 0) { OV_WARNING_K("Impossible to use compression as it is not yet implemented"); }
}
if (top == OVP_NodeId_OpenViBEStream_Header_StreamType) { m_streamIdxToTypeIDs[m_streamIdxToTypeIDs.size()] = m_readerHelper.getUInt(buffer, size); }
if (top == OVP_NodeId_OpenViBEStream_Buffer_StreamIndex)
{
const size_t streamIdx = size_t(m_readerHelper.getUInt(buffer, size));
if (m_streamIdxToTypeIDs.find(streamIdx) != m_streamIdxToTypeIDs.end()) { m_outputIdx = m_streamIdxToOutputIdxs[streamIdx]; }
}
if (top == OVP_NodeId_OpenViBEStream_Buffer_StartTime) { m_startTime = m_readerHelper.getUInt(buffer, size); }
if (top == OVP_NodeId_OpenViBEStream_Buffer_EndTime) { m_endTime = m_readerHelper.getUInt(buffer, size); }
if (top == OVP_NodeId_OpenViBEStream_Buffer_Content)
{
m_pendingChunk.setSize(0, true);
m_pendingChunk.append(reinterpret_cast<const uint8_t*>(buffer), size);
}
}
void CBoxAlgorithmGenericStreamReader::closeChild()
{
EBML::CIdentifier& top = m_nodes.top();
if (top == OVP_NodeId_OpenViBEStream_Header)
{
const Kernel::IBox& boxContext = this->getStaticBoxContext();
std::map<size_t, size_t> outputIndexToStreamIdx;
bool lostStreams = false;
bool lastOutputs = false;
// Go on each stream of the file
for (auto it = m_streamIdxToTypeIDs.begin(); it != m_streamIdxToTypeIDs.end(); ++it)
{
CIdentifier typeID;
size_t index = std::numeric_limits<size_t>::max();
// Find the first box output with this type that has no file stream connected
for (size_t i = 0; i < boxContext.getOutputCount() && index == std::numeric_limits<size_t>::max(); ++i)
{
if (boxContext.getOutputType(i, typeID))
{
if (outputIndexToStreamIdx.find(i) == outputIndexToStreamIdx.end())
{
if (typeID == it->second)
{
//const CString typeName = this->getTypeManager().getTypeName(it->second);
index = i;
}
}
}
}
// In case no suitable output was found, see if we can downcast some type
for (size_t i = 0; i < boxContext.getOutputCount() && index == std::numeric_limits<size_t>::max(); ++i)
{
if (boxContext.getOutputType(i, typeID))
{
if (outputIndexToStreamIdx.find(i) == outputIndexToStreamIdx.end())
{
if (this->getTypeManager().isDerivedFromStream(it->second, typeID))
{
const CString srcTypeName = this->getTypeManager().getTypeName(it->second);
const CString dstTypeName = this->getTypeManager().getTypeName(typeID);
this->getLogManager() << Kernel::LogLevel_Info << "Note: downcasting output " << i + 1 << " from " << srcTypeName
<< " to " << dstTypeName << ", as there is no exactly type-matching output connector.\n";
index = i;
}
}
}
}
// In case it was not found
if (index == std::numeric_limits<size_t>::max())
{
CString typeName = this->getTypeManager().getTypeName(it->second);
OV_WARNING_K("No free output connector for stream " << it->first << " of type " << it->second << " (" << typeName << ")");
m_streamIdxToOutputIdxs[it->first] = std::numeric_limits<size_t>::max();
lostStreams = true;
}
else
{
m_streamIdxToOutputIdxs[it->first] = index;
outputIndexToStreamIdx[index] = it->first;
}
}
// Warns for output with no stream connected to them
for (size_t i = 0; i < boxContext.getOutputCount(); ++i)
{
if (outputIndexToStreamIdx.find(i) == outputIndexToStreamIdx.end())
{
OV_WARNING_K("No stream candidate in file for output " << i+1);
lastOutputs = true;
}
}
// When both outputs and streams were lost, there most probably was a damn mistake
OV_ERROR_UNLESS_KRV(!lastOutputs || !lostStreams, "Invalid configuration: missing output for stream(s) and missing stream for output(s)",
Kernel::ErrorType::BadConfig);
}
if (top == OVP_NodeId_OpenViBEStream_Buffer)
{
m_pending = ((m_outputIdx != std::numeric_limits<size_t>::max()) &&
(m_startTime != std::numeric_limits<uint64_t>::max()) &&
(m_endTime != std::numeric_limits<uint64_t>::max()));
}
m_nodes.pop();
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,135 @@
#pragma once
#include "../../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <ebml/CReader.h>
#include <ebml/CReaderHelper.h>
#include <stack>
#include <map>
#include <cstdio>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CBoxAlgorithmGenericStreamReader final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>, public EBML::IReaderCallback
{
public:
CBoxAlgorithmGenericStreamReader();
void release() override { delete this; }
uint64_t getClockFrequency() override;
bool initialize() override;
bool uninitialize() override;
bool processClock(Kernel::CMessageClock& msg) override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_GenericStreamReader)
protected:
CString m_filename;
EBML::CReader m_reader;
EBML::CReaderHelper m_readerHelper;
CMemoryBuffer m_swap;
CMemoryBuffer m_pendingChunk;
uint64_t m_startTime = 0;
uint64_t m_endTime = 0;
size_t m_outputIdx = 0;
bool m_pending = false;
bool m_hasEBMLHeader = false;
FILE* m_file = nullptr;
std::stack<EBML::CIdentifier> m_nodes;
std::map<size_t, size_t> m_streamIdxToOutputIdxs;
std::map<size_t, CIdentifier> m_streamIdxToTypeIDs;
private:
bool initializeFile();
bool isMasterChild(const EBML::CIdentifier& identifier) override;
void openChild(const EBML::CIdentifier& identifier) override;
void processChildData(const void* buffer, const size_t size) override;
void closeChild() override;
};
class CBoxAlgorithmGenericStreamReaderListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool check(Kernel::IBox& box) const
{
for (size_t i = 0; i < box.getOutputCount(); ++i) { box.setOutputName(i, ("Output stream " + std::to_string(i + 1)).c_str()); }
return true;
}
bool onDefaultInitialized(Kernel::IBox& box) override
{
box.setOutputName(0, "Output Signal");
box.setOutputType(0, OV_TypeId_Signal);
box.addOutput("Output Stimulations", OV_TypeId_Stimulations);
return true;
}
bool onOutputAdded(Kernel::IBox& box, const size_t index) override
{
box.setOutputType(index, OV_TypeId_EBMLStream);
this->check(box);
return true;
}
bool onOutputRemoved(Kernel::IBox& box, const size_t /*index*/) override
{
this->check(box);
return true;
}
bool onOutputTypeChanged(Kernel::IBox& box, const size_t /*index*/) override
{
this->check(box);
return true;
}
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmGenericStreamReaderDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("Generic stream reader"); }
CString getAuthorName() const override { return CString("Yann Renard"); }
CString getAuthorCompanyName() const override { return CString("INRIA"); }
CString getShortDescription() const override { return CString("Reads OpenViBE streams saved in the .ov format"); }
CString getDetailedDescription() const override { return CString("Generic Stream Writer box can be used to store data in the format read by this box"); }
CString getCategory() const override { return CString("File reading and writing/OpenViBE"); }
CString getVersion() const override { return CString("1.0"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_GenericStreamReader; }
IPluginObject* create() override { return new CBoxAlgorithmGenericStreamReader; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmGenericStreamReaderListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addOutput("Output stream 1", OV_TypeId_EBMLStream);
prototype.addSetting("Filename", OV_TypeId_Filename, "");
prototype.addFlag(Kernel::BoxFlag_CanAddOutput);
prototype.addFlag(Kernel::BoxFlag_CanModifyOutput);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_GenericStreamReaderDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,127 @@
#include "ovpCBoxAlgorithmGenericStreamWriter.h"
#include <fs/Files.h>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
CBoxAlgorithmGenericStreamWriter::CBoxAlgorithmGenericStreamWriter() : m_writer(*this) {}
bool CBoxAlgorithmGenericStreamWriter::initialize()
{
m_filename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
const bool compression = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
if (compression) { OV_WARNING_K("Impossible to use compression as it is not yet implemented"); }
return true;
}
bool CBoxAlgorithmGenericStreamWriter::uninitialize()
{
if (m_file.is_open()) { m_file.close(); }
return true;
}
bool CBoxAlgorithmGenericStreamWriter::generateFileHeader()
{
const Kernel::IBox& boxContext = this->getStaticBoxContext();
m_swap.setSize(0, true);
m_writerHelper.connect(&m_writer);
m_writerHelper.openChild(EBML_Identifier_Header);
m_writerHelper.openChild(EBML_Identifier_DocType);
m_writerHelper.setStr("OpenViBE_Stream_File");
m_writerHelper.closeChild();
m_writerHelper.openChild(EBML_Identifier_EBMLVersion);
m_writerHelper.setUInt(1);
m_writerHelper.closeChild();
m_writerHelper.openChild(EBML_Identifier_EBMLIdLength);
m_writerHelper.setUInt(10);
m_writerHelper.closeChild();
m_writerHelper.closeChild();
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Header);
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Header_Compression);
m_writerHelper.setUInt(0 /* compression flag */);
m_writerHelper.closeChild();
for (size_t i = 0; i < boxContext.getInputCount(); ++i)
{
CIdentifier id;
boxContext.getInputType(i, id);
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Header_StreamType);
m_writerHelper.setUInt(id.id());
m_writerHelper.closeChild();
}
m_writerHelper.closeChild();
m_writerHelper.disconnect();
FS::Files::openOFStream(m_file, m_filename.toASCIIString(), std::ios::binary | std::ios::trunc);
OV_ERROR_UNLESS_KRF(m_file.good(), "Error opening file [" << m_filename << "] for writing", Kernel::ErrorType::BadFileWrite);
m_file.write(reinterpret_cast<const char*>(m_swap.getDirectPointer()), std::streamsize(m_swap.getSize()));
m_isHeaderGenerate = true;
return true;
}
bool CBoxAlgorithmGenericStreamWriter::processInput(const size_t /*index*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmGenericStreamWriter::process()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
const size_t nInput = this->getStaticBoxContext().getInputCount();
if (!m_isHeaderGenerate) { if (!generateFileHeader()) { return false; } }
m_swap.setSize(0, true);
for (size_t i = 0; i < nInput; ++i)
{
for (size_t j = 0; j < boxContext.getInputChunkCount(i); ++j)
{
m_writerHelper.connect(&m_writer);
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Buffer);
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Buffer_StreamIndex);
m_writerHelper.setUInt(i);
m_writerHelper.closeChild();
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Buffer_StartTime);
m_writerHelper.setUInt(boxContext.getInputChunkStartTime(i, j));
m_writerHelper.closeChild();
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Buffer_EndTime);
m_writerHelper.setUInt(boxContext.getInputChunkEndTime(i, j));
m_writerHelper.closeChild();
m_writerHelper.openChild(OVP_NodeId_OpenViBEStream_Buffer_Content);
m_writerHelper.setBinary(boxContext.getInputChunk(i, j)->getDirectPointer(), boxContext.getInputChunk(i, j)->getSize());
m_writerHelper.closeChild();
m_writerHelper.closeChild();
m_writerHelper.disconnect();
boxContext.markInputAsDeprecated(i, j);
}
}
if (m_swap.getSize() != 0)
{
m_file.write(reinterpret_cast<const char*>(m_swap.getDirectPointer()), std::streamsize(m_swap.getSize()));
OV_ERROR_UNLESS_KRF(m_file.good(), "Error opening file [" << m_filename << "] for writing", Kernel::ErrorType::BadFileWrite);
}
return true;
}
void CBoxAlgorithmGenericStreamWriter::write(const void* buffer, const size_t size) { m_swap.append(reinterpret_cast<const uint8_t*>(buffer), size); }
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,125 @@
#pragma once
#include "../../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <ebml/CWriter.h>
#include <ebml/CWriterHelper.h>
#include <cstdio>
#include <fstream>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CBoxAlgorithmGenericStreamWriter final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>, public EBML::IWriterCallback
{
public:
CBoxAlgorithmGenericStreamWriter();
void release() override { delete this; }
bool initialize() override;
bool uninitialize() override;
bool processInput(const size_t index) override;
bool process() override;
bool generateFileHeader();
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_GenericStreamWriter)
protected:
bool m_isHeaderGenerate = false;
CString m_filename;
EBML::CWriter m_writer;
EBML::CWriterHelper m_writerHelper;
private:
void write(const void* buffer, const size_t size) override;
CMemoryBuffer m_swap;
std::ofstream m_file;
};
class CBoxAlgorithmGenericStreamWriterListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
//it seems the only purpose of the check was to give a name when adding an input
//without it, the input configuration dialog display random characters in the name field
//the check is unnecessary when removing/changing inputs and on already named inputs
bool check(Kernel::IBox& box)
{
const size_t i = box.getInputCount() - 1;
//only check last input (we assume previous inputs have benn named, how could they not?)
box.setInputName(i, ("Input stream " + std::to_string(i + 1)).c_str());
//for (i=0; i<box.getInputCount(); ++i) { box.setInputName(i, ("Input stream " + std::to_string(i + 1)).c_str()); }
return true;
}
bool onDefaultInitialized(Kernel::IBox& box) override
{
box.setInputName(0, "Input Signal");
box.setInputType(0, OV_TypeId_Signal);
box.addInput("Input Stimulations", OV_TypeId_Stimulations);
return true;
}
bool onInputAdded(Kernel::IBox& box, const size_t index) override
{
box.setInputType(index, OV_TypeId_EBMLStream);
this->check(box);
return true;
}
bool onInputRemoved(Kernel::IBox& /*box*/, const size_t /*index*/) override
{
//this->check(box);
return true;
}
bool onInputTypeChanged(Kernel::IBox& /*box*/, const size_t /*index*/) override
{
//this->check(box);
return true;
}
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmGenericStreamWriterDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("Generic stream writer"); }
CString getAuthorName() const override { return CString("Yann Renard"); }
CString getAuthorCompanyName() const override { return CString("INRIA"); }
CString getShortDescription() const override { return CString("Writes any number of streams into an .ov file"); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing/OpenViBE"); }
CString getVersion() const override { return CString("1.0"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_GenericStreamWriter; }
IPluginObject* create() override { return new CBoxAlgorithmGenericStreamWriter; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmGenericStreamWriterListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Input stream 1", OV_TypeId_EBMLStream);
prototype.addSetting("Filename", OV_TypeId_Filename, "record-[$core{date}-$core{time}].ov");
prototype.addSetting("Use compression", OV_TypeId_Boolean, "false");
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_GenericStreamWriterDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,125 @@
#include "ovpCBoxAlgorithmElectrodeLocalizationFileReader.h"
#include "../algorithms/ovpCAlgorithmOVMatrixFileReader.h"
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
uint64_t CBoxAlgorithmElectrodeLocalisationFileReader::getClockFrequency() { return uint64_t(1LL) << 32; }
bool CBoxAlgorithmElectrodeLocalisationFileReader::initialize()
{
m_headerSent = false;
m_bufferSent = false;
// Creates algorithms
m_pOVMatrixFileReader = &getAlgorithmManager().getAlgorithm(getAlgorithmManager().createAlgorithm(OVP_ClassId_Algorithm_OVMatrixFileReader));
m_encoder = new Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmElectrodeLocalisationFileReader>;
m_pOVMatrixFileReader->initialize();
m_encoder->initialize(*this, 0);
//*
// OVMatrix file reader parameters
Kernel::TParameterHandler<CString*> ip_sFilename(m_pOVMatrixFileReader->getInputParameter(OVP_Algorithm_OVMatrixFileReader_InputParameterId_Filename));
/*
Kernel::TParameterHandler<CMatrix*> op_pMatrix(m_pOVMatrixFileReader->getOutputParameter(OVP_Algorithm_OVMatrixFileReader_OutputParameterId_Matrix));
// Channel localisation parameters
Kernel::TParameterHandler<bool> ip_bDynamic(m_encoder->getInputParameter(OVP_GD_Algorithm_ChannelLocalisationEncoder_InputParameterId_Dynamic));
Kernel::TParameterHandler<CMatrix*> ip_pMatrix(m_encoder->getInputParameter(OVP_GD_Algorithm_ChannelLocalisationEncoder_InputParameterId_Matrix));
// Configure parameters
ip_bDynamic = false;
ip_pMatrix.setReferenceTarget(op_pMatrix);
//*/
m_encoder->getInputDynamic() = false;
// Configures settings according to box
m_filename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
*ip_sFilename = m_filename;
return true;
}
bool CBoxAlgorithmElectrodeLocalisationFileReader::uninitialize()
{
//m_pOVMatrixFileReader->process(OVP_Algorithm_OVMatrixFileReader_InputTriggerId_Close);
m_pOVMatrixFileReader->uninitialize();
getAlgorithmManager().releaseAlgorithm(*m_pOVMatrixFileReader);
if (m_encoder)
{
m_encoder->uninitialize();
delete m_encoder;
}
return true;
}
bool CBoxAlgorithmElectrodeLocalisationFileReader::processClock(Kernel::CMessageClock& /*msg*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmElectrodeLocalisationFileReader::process()
{
if (m_headerSent == true && m_bufferSent == true) { return true; }
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
// Channel localisation stream encoder parameters
Kernel::TParameterHandler<CMatrix*> op_pMatrix(m_pOVMatrixFileReader->getOutputParameter(OVP_Algorithm_OVMatrixFileReader_OutputParameterId_Matrix));
m_pOVMatrixFileReader->process(/*OVP_Algorithm_OVMatrixFileReader_InputTriggerId_Next*/);
//ensure matrix is 2 dimensional and that dimension sizes are correct
OV_ERROR_UNLESS_KRF(op_pMatrix->getDimensionCount() == 2 && op_pMatrix->getDimensionSize(1) == 3,
"Wrong format for electrode localisation matrix loaded from file " << m_filename, Kernel::ErrorType::BadParsing);
if (m_headerSent == false)
{
// Connects parameters to memory buffer
//op_channelLocalisationMemoryBuffer = boxContext.getOutputChunk(0);
//open file and load matrix dimensions
// m_pOVMatrixFileReader->process(OVP_Algorithm_BrainampFileReader_InputTriggerId_Open);
// Produces header
CMatrix* iMatrix = m_encoder->getInputMatrix();
iMatrix->copy(*op_pMatrix);
m_encoder->encodeHeader();
// Sends header
boxContext.markOutputAsReadyToSend(0, 0, 0);
m_headerSent = true;
}
if (m_bufferSent == false /*&&
m_pOVMatrixFileReader->isOutputTriggerActive(OVP_Algorithm_OVMatrixFileReader_OutputTriggerId_DataProduced)*/)
{
// Connects parameters to memory buffer
CMatrix* iMatrix = m_encoder->getInputMatrix();
iMatrix->copy(*op_pMatrix);
// Produces buffer
m_encoder->encodeBuffer();
// Sends buffer
boxContext.markOutputAsReadyToSend(0, 0/*op_CurrentStartTime*/, 0/*op_CurrentEndTime*/);
m_bufferSent = true;
}
return true;
}
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,66 @@
#pragma once
#include "../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
class CBoxAlgorithmElectrodeLocalisationFileReader final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
void release() override { delete this; }
uint64_t getClockFrequency() override;
bool initialize() override;
bool uninitialize() override;
bool processClock(Kernel::CMessageClock& msg) override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_ElectrodeLocalisationFileReader)
protected:
Kernel::IAlgorithmProxy* m_pOVMatrixFileReader = nullptr;
Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmElectrodeLocalisationFileReader>* m_encoder = nullptr;
CString m_filename;
bool m_headerSent = false;
bool m_bufferSent = false;
};
class CBoxAlgorithmElectrodeLocalisationFileReaderDesc final : public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("Electrode localisation file reader"); }
CString getAuthorName() const override { return CString("Vincent Delannoy"); }
CString getAuthorCompanyName() const override { return CString("INRIA/IRISA"); }
CString getShortDescription() const override { return CString("Loads files containing the normalized coordinates of an electrode set"); }
CString getDetailedDescription() const override { return CString(""); }
CString getCategory() const override { return CString("File reading and writing/OpenViBE"); }
CString getVersion() const override { return CString("1.0"); }
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_ElectrodeLocalisationFileReader; }
IPluginObject* create() override { return new CBoxAlgorithmElectrodeLocalisationFileReader; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
// Adds box outputs
prototype.addOutput("Channel localisation", OV_TypeId_ChannelLocalisation);
// Adds settings
prototype.addSetting("Filename", OV_TypeId_Filename, "");
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_ElectrodeLocalisationFileReaderDesc)
};
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,56 @@
#pragma once
// Boxes
//---------------------------------------------------------------------------------------------------
#define OVP_ClassId_Algorithm_OVMatrixFileReader OpenViBE::CIdentifier(0x10661A33, 0x0B0F44A7)
#define OVP_ClassId_Algorithm_OVMatrixFileReaderDesc OpenViBE::CIdentifier(0x0E873B5E, 0x0A287FCB)
#define OVP_ClassId_Algorithm_OVMatrixFileWriter OpenViBE::CIdentifier(0x739158FC, 0x1E8240CC)
#define OVP_ClassId_Algorithm_OVMatrixFileWriterDesc OpenViBE::CIdentifier(0x44CF6DD0, 0x329D47F9)
#define OVP_ClassId_Algorithm_XMLScenarioExporter OpenViBE::CIdentifier(0x53693531, 0xB136CF3F)
#define OVP_ClassId_Algorithm_XMLScenarioExporterDesc OpenViBE::CIdentifier(0x9709C9FA, 0xF126F74E)
#define OVP_ClassId_Algorithm_XMLScenarioImporter OpenViBE::CIdentifier(0xE80C3EA2, 0x149C4A05)
#define OVP_ClassId_Algorithm_XMLScenarioImporterDesc OpenViBE::CIdentifier(0xFF25D456, 0x721FCC57)
#define OVP_ClassId_BoxAlgorithm_CSVFileReaderDesc OpenViBE::CIdentifier(0x193F22E9, 0x26A67233)
#define OVP_ClassId_BoxAlgorithm_CSVFileReader OpenViBE::CIdentifier(0x641D0717, 0x02884107)
#define OVP_ClassId_BoxAlgorithm_CSVFileWriter OpenViBE::CIdentifier(0x2C9312F1, 0x2D6613E5)
#define OVP_ClassId_BoxAlgorithm_CSVFileWriterDesc OpenViBE::CIdentifier(0x65075FF7, 0x2B555E97)
#define OVP_ClassId_BoxAlgorithm_ElectrodeLocalisationFileReader OpenViBE::CIdentifier(0x40704155, 0x19C50E8F)
#define OVP_ClassId_BoxAlgorithm_ElectrodeLocalisationFileReaderDesc OpenViBE::CIdentifier(0x4796613F, 0x653A48D5)
#define OVP_ClassId_BoxAlgorithm_GenericStreamReader OpenViBE::CIdentifier(0x6468099F, 0x0370095A)
#define OVP_ClassId_BoxAlgorithm_GenericStreamReaderDesc OpenViBE::CIdentifier(0x1F1E3A53, 0x6CA07237)
#define OVP_ClassId_BoxAlgorithm_GenericStreamWriter OpenViBE::CIdentifier(0x09C92218, 0x7C1216F8)
#define OVP_ClassId_BoxAlgorithm_GenericStreamWriterDesc OpenViBE::CIdentifier(0x50AB506A, 0x54804437)
#define OVP_ClassId_BoxAlgorithm_OVCSVFileReader OpenViBE::CIdentifier(0x336A3D9A, 0x753F1BA4)
#define OVP_ClassId_BoxAlgorithm_OVCSVFileReaderDesc OpenViBE::CIdentifier(0x584E1948, 0x65E91650)
#define OVP_ClassId_BoxAlgorithm_OVCSVFileWriter OpenViBE::CIdentifier(0x428375E8, 0x325F2DB9)
#define OVP_ClassId_BoxAlgorithm_OVCSVFileWriterDesc OpenViBE::CIdentifier(0x4B5C1D8F, 0x570E45FD)
// Type definitions
//---------------------------------------------------------------------------------------------------
#define OVP_NodeId_OpenViBEStream_Header EBML::CIdentifier(0xF59505AB, 0x3684C8D8)
#define OVP_NodeId_OpenViBEStream_Header_Compression EBML::CIdentifier(0x40358769, 0x166380D1)
#define OVP_NodeId_OpenViBEStream_Header_StreamType EBML::CIdentifier(0x732EC1D1, 0xFE904087)
#define OVP_NodeId_OpenViBEStream_Header_ChannelType OVP_NodeId_OpenViBEStream_Header_StreamType // deprecated old name
#define OVP_NodeId_OpenViBEStream_Buffer EBML::CIdentifier(0x2E60AD18, 0x87A29BDF)
#define OVP_NodeId_OpenViBEStream_Buffer_StreamIndex EBML::CIdentifier(0x30A56D8A, 0xB9C12238)
#define OVP_NodeId_OpenViBEStream_Buffer_ChannelIndex OVP_NodeId_OpenViBEStream_Buffer_StreamIndex // deprecated old name
#define OVP_NodeId_OpenViBEStream_Buffer_StartTime EBML::CIdentifier(0x093E6A0A, 0xC5A9467B)
#define OVP_NodeId_OpenViBEStream_Buffer_EndTime EBML::CIdentifier(0x8B5CCCD9, 0xC5024F29)
#define OVP_NodeId_OpenViBEStream_Buffer_Content EBML::CIdentifier(0x8D4B0BE8, 0x7051265C)
// Global defines
//---------------------------------------------------------------------------------------------------
#ifdef TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
#include "ovp_global_defines.h"
#endif // TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
#define OVP_Algorithm_OVMatrixFileReader_InputParameterId_Filename OpenViBE::CIdentifier(0x28F87B29, 0x0B09737E)
#define OVP_Algorithm_OVMatrixFileReader_OutputParameterId_Matrix OpenViBE::CIdentifier(0x2F9521E0, 0x027D789F)
#define OVP_Algorithm_OVMatrixFileReader_InputTriggerId_Open OpenViBE::CIdentifier(0x2F996376, 0x2A942485)
#define OVP_Algorithm_OVMatrixFileReader_InputTriggerId_Load OpenViBE::CIdentifier(0x22841807, 0x102D681C)
#define OVP_Algorithm_OVMatrixFileReader_InputTriggerId_Close OpenViBE::CIdentifier(0x7FDE77DA, 0x384A0B3D)
#define OVP_Algorithm_OVMatrixFileReader_OutputTriggerId_Error OpenViBE::CIdentifier(0x6D4F2F4B, 0x05EC6CB9)
#define OVP_Algorithm_OVMatrixFileReader_OutputTriggerId_DataProduced OpenViBE::CIdentifier(0x76F46051, 0x003B6FE8)
#define OVP_Algorithm_OVMatrixFileWriter_InputParameterId_Filename OpenViBE::CIdentifier(0x330D2D0B, 0x175271E6)
#define OVP_Algorithm_OVMatrixFileWriter_InputParameterId_Matrix OpenViBE::CIdentifier(0x6F6402EE, 0x493044F3)
@@ -0,0 +1,52 @@
#include "ovp_defines.h"
#include "algorithms/ovpCAlgorithmOVMatrixFileReader.h"
#include "algorithms/ovpCAlgorithmOVMatrixFileWriter.h"
#include "algorithms/xml-scenario/ovpCAlgorithmXMLScenarioExporter.h"
#include "algorithms/xml-scenario/ovpCAlgorithmXMLScenarioImporter.h"
#include "box-algorithms/csv/ovpCBoxAlgorithmCSVFileWriter.h"
#include "box-algorithms/csv/ovpCBoxAlgorithmCSVFileReader.h"
#include "box-algorithms/openvibe/ovpCBoxAlgorithmGenericStreamReader.h"
#include "box-algorithms/openvibe/ovpCBoxAlgorithmGenericStreamWriter.h"
#include "box-algorithms/ovpCBoxAlgorithmElectrodeLocalizationFileReader.h"
#include "box-algorithms/csv/ovpCBoxAlgorithmOVCSVFileWriter.h"
#include "box-algorithms/csv/ovpCBoxAlgorithmOVCSVFileReader.h"
namespace OpenViBE {
namespace Plugins {
namespace FileIO {
OVP_Declare_Begin()
OVP_Declare_New(CAlgorithmOVMatrixFileReaderDesc)
OVP_Declare_New(CAlgorithmOVMatrixFileWriterDesc)
OVP_Declare_New(CAlgorithmXMLScenarioExporterDesc)
OVP_Declare_New(CAlgorithmXMLScenarioImporterDesc)
OVP_Declare_New(CBoxAlgorithmCSVFileWriterDesc)
OVP_Declare_New(CBoxAlgorithmCSVFileReaderDesc)
OVP_Declare_New(CBoxAlgorithmGenericStreamReaderDesc)
OVP_Declare_New(CBoxAlgorithmGenericStreamWriterDesc)
OVP_Declare_New(CBoxAlgorithmElectrodeLocalisationFileReaderDesc)
OVP_Declare_New(CBoxAlgorithmOVCSVFileWriterDesc)
OVP_Declare_New(CBoxAlgorithmOVCSVFileReaderDesc)
context.getScenarioManager().registerScenarioImporter(OV_ScenarioImportContext_SchedulerMetaboxImport, ".mxb", OVP_ClassId_Algorithm_XMLScenarioImporter);
context.getScenarioManager().registerScenarioImporter(OV_ScenarioImportContext_SchedulerMetaboxImport, ".xml", OVP_ClassId_Algorithm_XMLScenarioImporter);
context.getConfigurationManager().createConfigurationToken("ScenarioFileNameExtension.xml", "OpenViBE XML Scenario");
context.getConfigurationManager().createConfigurationToken("ScenarioFileNameExtension.mxs", "Mensia XML Scenario");
context.getConfigurationManager().createConfigurationToken("ScenarioFileNameExtension.mxb", "Mensia XML Component");
OVP_Declare_End()
} // namespace FileIO
} // namespace Plugins
} // namespace OpenViBE