init
@@ -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 <i>Temporal Filter</i> 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 <i>Continuous Oscilloscope</i> box displays
|
||||
the content of the file.
|
||||
|
||||
You might need to <b>right click and drag up or down</b>
|
||||
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 <b>F1</b></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 <i><b>Generic Stream Reader</b></i> box
|
||||
reads an <i>OpenViBE</i> file from disk and sends
|
||||
its content to the following box.
|
||||
The <i>OpenViBE</i> 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**.
|
||||
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
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
|
||||