This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,42 @@
PROJECT(openvibe-plugins-sdk-tools)
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/*.h src/*.hpp src/*.inl)
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")
INCLUDE("FindOpenViBE")
INCLUDE("FindOpenViBECommon")
INCLUDE("FindOpenViBEToolkit")
INCLUDE("FindOpenViBEModuleEBML")
INCLUDE("FindOpenViBEModuleSystem")
INCLUDE("FindOpenViBEModuleFS")
INCLUDE("FindOpenViBEModuleSocket")
INCLUDE("FindOpenViBEModuleCommunication")
# ---------------------------------
# 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 share/ DESTINATION ${DIST_DATADIR}/openvibe/plugins/tools)
INSTALL(DIRECTORY box-tutorials DESTINATION ${DIST_DATADIR}/openvibe/scenarios/)
@@ -0,0 +1,520 @@
<OpenViBE-Scenario>
<FormatVersion>1</FormatVersion>
<Creator>OpenVIBE</Creator>
<CreatorVersion>0.4.99</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x14bf05c0, 0x09128ae5)</Identifier>
<Name>External Processing</Name>
<AlgorithmClassIdentifier>(0x15422959, 0x16304449)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>New input</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>New input</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>New output</Name>
</Output>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>New output</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Launch third party program</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Executable path</Name>
<DefaultValue></DefaultValue>
<Value>${Path_Bin}/sdk-examples-communication-client-filter</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Arguments</Name>
<DefaultValue></DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Port</Name>
<DefaultValue>59595</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Automatic connection identifier</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Custom connection identifier</Name>
<DefaultValue></DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Incoming connection timeout</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Generator</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>176</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>528</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x6410533a, 0x11ff9fa8)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>8</Value>
</Attribute>
<Attribute>
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x1b8eb320, 0x35920803)</Identifier>
<Name>Time signal</Name>
<AlgorithmClassIdentifier>(0x28a5e7ff, 0x530095de)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Generated signal</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Sampling frequency</Name>
<DefaultValue>512</DefaultValue>
<Value>512</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Generated epoch sample count</Name>
<DefaultValue>32</DefaultValue>
<Value>32</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>32</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>464</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x9e5ca01e, 0x30a4d8c3)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x2b2c676e, 0x1f9f8ed4)</Identifier>
<Name>Simple DSP</Name>
<AlgorithmClassIdentifier>(0x00e26fa1, 0x1dbab1b2)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Input - A</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Output</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Equation</Name>
<DefaultValue>x</DefaultValue>
<Value>sin(x)</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>96</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>464</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x21889dc4, 0x1126497e)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x6a37098c, 0x4353fccf)</Identifier>
<Name>Clock stimulator</Name>
<AlgorithmClassIdentifier>(0x4f756d3f, 0x29ff0b96)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Generated stimulations</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Interstimulation interval (in sec)</Name>
<DefaultValue>1.0</DefaultValue>
<Value>1.0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
<Name>Stimulation</Name>
<DefaultValue>OVTK_StimulationId_Label_00</DefaultValue>
<Value>OVTK_StimulationId_Label_00</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>80</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>576</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x27b3ee3c, 0xc50527e6)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x6db580a4, 0x2710c742)</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>1</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>256</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>528</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>
</Boxes>
<Links>
<Link>
<Identifier>(0x47d63853, 0x410bf5fe)</Identifier>
<Source>
<BoxIdentifier>(0x14bf05c0, 0x09128ae5)</BoxIdentifier>
<BoxOutputIndex>1</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x6db580a4, 0x2710c742)</BoxIdentifier>
<BoxInputIndex>1</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x4c81cafe, 0x0de678a1)</Identifier>
<Source>
<BoxIdentifier>(0x1b8eb320, 0x35920803)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x2b2c676e, 0x1f9f8ed4)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x5135bc4a, 0x1edcc7ee)</Identifier>
<Source>
<BoxIdentifier>(0x14bf05c0, 0x09128ae5)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x6db580a4, 0x2710c742)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x58190761, 0x23a1c7ca)</Identifier>
<Source>
<BoxIdentifier>(0x2b2c676e, 0x1f9f8ed4)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x14bf05c0, 0x09128ae5)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x63ab5412, 0x051c9cde)</Identifier>
<Source>
<BoxIdentifier>(0x6a37098c, 0x4353fccf)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x14bf05c0, 0x09128ae5)</BoxIdentifier>
<BoxInputIndex>1</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x09b97cf8, 0x27678b7b)</Identifier>
<Text>Illustration of the usage of the &lt;b&gt;External Processing Box&lt;/b&gt;.
This box launches an external program and connects to it via TCP/IP.
This particular example uses the example program given with the OpenViBE SDK,
it will take any number of inputs and echo them on respective outputs.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>160</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>80</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x1fbd3f8e, 0x02fc93b2)</Identifier>
<Text>Important options the box takes are:
&lt;b&gt;Launch Third Party Program&lt;/b&gt; - OpenViBE will start the
external program by itself if this setting is true.
&lt;b&gt;Executable Path&lt;/b&gt; - Program to launch. The path can
be an absolute path to a program, or a name of a program
in system PATH.
&lt;b&gt;Arguments&lt;/b&gt; - Arguments to pass to the external program.
&lt;b&gt;Port&lt;/b&gt; - The port through which the program will communicate
with openvibe. If the program is launched by OpenViBE this port will
be automatically passed to it using argument &lt;tt&gt;--port &amp;lt;port&amp;gt;&lt;/tt&gt;
If the port is set to 0, an available one will be chosen automatically.
&lt;b&gt;Generator&lt;/b&gt; - Should be set to true if the box does not need to
process data synchronously. This usually means that it does not have
any inputs.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>160</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>352</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x205c8363, 0x19b5e92f)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0x6db580a4, 0x2710c742)","childCount":0,"identifier":"(0x3e899070, 0x3969c924)","parentIdentifier":"(0xffffffff, 0xffffffff)","type":3},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":1,"identifier":"(0x51e57212, 0x2ea425c0)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":1},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x1aaa3685, 0x1ce16371)","index":0,"name":"Default tab","parentIdentifier":"(0x51e57212, 0x2ea425c0)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x11475ce0, 0x64227efd)","index":0,"name":"Empty","parentIdentifier":"(0x1aaa3685, 0x1ce16371)","type":0}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>
@@ -0,0 +1,608 @@
<OpenViBE-Scenario>
<FormatVersion>1</FormatVersion>
<Creator>OpenVIBE</Creator>
<CreatorVersion>0.4.99</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x14bf05c0, 0x09128ae5)</Identifier>
<Name>External Processing</Name>
<AlgorithmClassIdentifier>(0x15422959, 0x16304449)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>New output</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Launch third party program</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Executable path</Name>
<DefaultValue></DefaultValue>
<Value>${Path_Bin}/sdk-examples-communication-client-generator</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Arguments</Name>
<DefaultValue></DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Port</Name>
<DefaultValue>59595</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Automatic connection identifier</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Custom connection identifier</Name>
<DefaultValue></DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Incoming connection timeout</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Generator</Name>
<DefaultValue>false</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Channel Count</Name>
<DefaultValue>4</DefaultValue>
<Value>4</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Sampling Rate</Name>
<DefaultValue>128</DefaultValue>
<Value>128</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Samples Per Buffer</Name>
<DefaultValue>16</DefaultValue>
<Value>16</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Amount of Samples to Generate</Name>
<DefaultValue>512</DefaultValue>
<Value>512</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>160</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>512</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x6410533a, 0x11ff9fa8)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>8</Value>
</Attribute>
<Attribute>
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x14bf05c0, 0x09128ae6)</Identifier>
<Name>External Processing</Name>
<AlgorithmClassIdentifier>(0x15422959, 0x16304449)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>New output</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Launch third party program</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Executable path</Name>
<DefaultValue></DefaultValue>
<Value>${Path_Bin}/sdk-examples-communication-client-generator</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Arguments</Name>
<DefaultValue></DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Port</Name>
<DefaultValue>59595</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Automatic connection identifier</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Custom connection identifier</Name>
<DefaultValue></DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Incoming connection timeout</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Generator</Name>
<DefaultValue>false</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Channel Count</Name>
<DefaultValue>4</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Sampling Rate</Name>
<DefaultValue>128</DefaultValue>
<Value>128</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Samples Per Buffer</Name>
<DefaultValue>16</DefaultValue>
<Value>16</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Amount of Samples to Generate</Name>
<DefaultValue>512</DefaultValue>
<Value>512</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>160</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>720</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x6410533a, 0x11ff9fa8)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>8</Value>
</Attribute>
<Attribute>
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x6db580a4, 0x2710c742)</Identifier>
<Name>4 Channels</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>1</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>240</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>512</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>(0x6db580a4, 0x2710c743)</Identifier>
<Name>5 Channels</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>1</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>240</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>720</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>
</Boxes>
<Links>
<Link>
<Identifier>(0x5135bc4a, 0x1edcc7ee)</Identifier>
<Source>
<BoxIdentifier>(0x14bf05c0, 0x09128ae5)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x6db580a4, 0x2710c742)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x5135bc4a, 0x1edcc7ef)</Identifier>
<Source>
<BoxIdentifier>(0x14bf05c0, 0x09128ae6)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x6db580a4, 0x2710c743)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x020f409a, 0x2e82d6c9)</Identifier>
<Text>The generator example program can take the following settings:
&lt;b&gt;Channel Count&lt;/b&gt;
&lt;b&gt;Sampling Rate&lt;/b&gt;
&lt;b&gt;Samples Per Buffer&lt;/b&gt;
&lt;b&gt;Samples To Generate&lt;/b&gt; - The program will stop after this many samples
</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>640</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>400</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x09b97cf8, 0x27678b7b)</Identifier>
<Text>Illustration of the usage of the &lt;b&gt;External Processing Box&lt;/b&gt;.
This box launches an external program and connects to it via TCP/IP.
This particular example uses the &lt;b&gt;generator&lt;/b&gt; example program given with the OpenViBE SDK.
It will generate several sinus signals with a custom sampling rate and epoching.
Optionally it can stop generating samples after a period of time.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>144</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>80</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x1fbd3f8e, 0x02fc93b2)</Identifier>
<Text>Important options the box takes are:
&lt;b&gt;Launch Third Party Program&lt;/b&gt; - OpenViBE will start the
external program by itself if this setting is true.
&lt;b&gt;Executable Path&lt;/b&gt; - Program to launch. The path can
be an absolute path to a program, or a name of a program
in system PATH.
&lt;b&gt;Arguments&lt;/b&gt; - Arguments to pass to the external program.
&lt;b&gt;Port&lt;/b&gt; - The port through which the program will communicate
with openvibe. If the program is launched by OpenViBE this port will
be automatically passed to it using argument &lt;tt&gt;--port &amp;lt;port&amp;gt;&lt;/tt&gt;
If the port is set to 0, an available one will be chosen automatically.
&lt;b&gt;Generator&lt;/b&gt; - Should be set to true if the box does not need to
process data synchronously. This usually means that it does not have
any inputs. In this scenario this is the case!</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>192</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>368</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x205c8363, 0x19b5e92f)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":490,"identifier":"(0x51e57212, 0x2ea425c0)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":791},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x1aaa3685, 0x1ce16371)","index":0,"name":"Default tab","parentIdentifier":"(0x51e57212, 0x2ea425c0)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":2,"dividerPosition":383,"identifier":"(0x3def082e, 0x180223c7)","index":0,"maxDividerPosition":771,"name":"Horizontal split","parentIdentifier":"(0x1aaa3685, 0x1ce16371)","type":5},{"boxIdentifier":"(0x6db580a4, 0x2710c742)","childCount":0,"identifier":"(0x3e899070, 0x3969c924)","index":0,"parentIdentifier":"(0x3def082e, 0x180223c7)","type":3},{"boxIdentifier":"(0x6db580a4, 0x2710c743)","childCount":0,"identifier":"(0x4de25e08, 0x488b872b)","index":1,"parentIdentifier":"(0x3def082e, 0x180223c7)","type":3}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>
@@ -0,0 +1,192 @@
/**
* \page BoxAlgorithm_EBMLStreamSpy EBML stream spy
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Description|
* The purpose of this box is to spy an EBML stream and decode
* its structure to the log manager. In order to do so, the box
* has to know a list of expected EBML node identifiers and EBML
* node types. If you don't know what EBML is, you should check
* the \ref Doc_WhatIsEBML page. The list of expected node
* identifiers and types is collected from a configuration file.
* Also, the author is able to chose which log level to use
* in order to output the information.
*
* Such box is mostly usefull for debug purpose. It allows
* a developper to check what arrives to a box in a human
* readable way.
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Description|
__________________________________________________________________
Inputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Inputs|
* This box can receive as many input as necessary. All the inputs
* will be of type \ref Doc_Streams_EBMLStream in order to
* be parsed by this the reader.
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Inputs|
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Input1|
* This is the default input of this box.
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Input1|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Settings|
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Settings|
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Setting1|
* This first setting indicates where to find the configuration file.
* The box comes with a default configuration file containing all the
* default node identifiers of BRAND_NAME. You should extend this
* configuration in order to add your own EBML nodes in case you
* have created new EBML stream types.
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Setting1|
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Setting2|
* This second settings indicates what log level will be used to
* print the EBML stream structure.
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Setting2|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Examples|
* As an example, we could connect an EBML stream spy to a sinus
* oscillator. Leave the default sinus oscillator settings to their
* default, except the sample count per buffer can be set to 8 for the
* example. Chose an appropriate log level for the EBML stream spy and
* press 'start'. You will probably notice that a lot of text is sent
* to the log manager, making the use of this box difficult in real time.
* Once again, consider it as a debugging box.
*
* The output should look like this :
\verbatim
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x00000000),(0x00000000, 0x00000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x002b395f, 0x108adfae)]-[name:OVTK_NodeId_Header]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cdd0f7, 0x46b0278d)]-[name:OVTK_NodeId_Header_StreamType]-[type:uinteger]-[value:0 (0x0)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x006f5a08, 0x7796ebc5)]-[name:OVTK_NodeId_Header_StreamVersion]-[type:uinteger]-[value:0 (0x0)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x007855de, 0x3748d375)]-[name:OVTK_NodeId_Header_Signal]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00141c43, 0x0c37006b)]-[name:OVTK_NodeId_Header_Signal_Sampling]-[type:uinteger]-[value:512 (0x200)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x0072f560, 0x7ed2cbed)]-[name:OVTK_NodeId_Header_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x003febd4, 0x2725d428)]-[name:OVTK_NodeId_Header_StreamedMatrix_DimensionCount]-[type:uinteger]-[value:2 (0x2)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x0000e3c0, 0x3a7d5141)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x001302f7, 0x36d8438a)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Size]-[type:uinteger]-[value:4 (0x4)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 0]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 1]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 2]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 3]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x0000e3c0, 0x3a7d5141)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x001302f7, 0x36d8438a)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Size]-[type:uinteger]-[value:8 (0x8)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x00000000),(0x00000000, 0x04000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cf2101, 0x02375310)]-[name:OVTK_NodeId_Buffer]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00120663, 0x08fbc165)]-[name:OVTK_NodeId_Buffer_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00b18c10, 0x427d098c)]-[name:OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer]-[type:binary]-[bytes:256 (0x100)]
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x04000000),(0x00000000, 0x08000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cf2101, 0x02375310)]-[name:OVTK_NodeId_Buffer]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00120663, 0x08fbc165)]-[name:OVTK_NodeId_Buffer_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00b18c10, 0x427d098c)]-[name:OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer]-[type:binary]-[bytes:256 (0x100)]
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x08000000),(0x00000000, 0x0c000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cf2101, 0x02375310)]-[name:OVTK_NodeId_Buffer]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00120663, 0x08fbc165)]-[name:OVTK_NodeId_Buffer_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00b18c10, 0x427d098c)]-[name:OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer]-[type:binary]-[bytes:256 (0x100)]
[ INF ] <Box algorithm::EBML stream spy>
...
\endverbatim
*
* Now let's try to understand what is produced. First we notice a clear
* separation between the different chunk the box receives. In each chunk, we
* have an EBML hierarchy with the different nodes. Here we analyse a signal
* stream so we have a header followed by multiple buffers.
*
* Concerning the header, we can focuse on the signal header part and
* the streamed matrix header part. In the first one, we can see that the sampling
* rate node appears as an integer with value 512 (the default sinus oscillator
* sampling frequency). The second one contains the description of the streamed
* matrix. The matrix has two dimensions (electrodes and sample count per buffer).
* The first dimension has a size of 4 (the default sinus oscillator channel count)
* and each of this channel has a label (channel 0-3). Finally, the second dimension
* has a size of 8 (the sample count per buffer you manually put in the sinus
* oscillator configuration) and the samples themselves do not have a name.
*
* Now looking at the buffer, we only have the streamed matrix part (signal
* stream do not produce signal specific buffer). The buffer content can not
* be displayed in the console (it could be a huge amount of binary non human
* readable data, so it is not relevant to print it). But you have an information
* of the size of this buffer. 256 is exactly the number of channels (4) multiplied
* by the number of samples per buffer (8) multiplied by the size of a single sample
* (8 because a sample is coded on a 64 bits float).
*
* When familiar with EBML and OpenViBE streams, this box is a strong tool
* to analyze what is sent from a box to another.
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_EBMLStreamSpy_Miscellaneous|
* The syntax of the configuration file is simple. Each line of the file
* should contain 3 fields. The first field is the name of the EBML node
* that should be printed in the log manager (this is human readable).
* The second field is the EBML node identifier. The last field is the node
* type. Several types are supported :
* - \e master : this means that this node does not have data attached but has
* several children. Any non master node is a leaf, so can contain data.
* - \e integer : this means that this node contains a signed integer value
* - \e uinteger : this means that this node contains an unsigned integer value
* - \e string : this means that this node contains an ASCII string value
* - \e float : this means that this node contains a floating point value
* - \e binary : this means that this node contains a raw buffer of elements.
* In such case, only the size of the buffer is printed. The content of the
* buffer is not printed.
*
* Any node identifier found in the stream and not present in the configuration
* file will be considered of type \e unknown and treated as if it was a \e binary
* node.
*
* Following is a part of the sample configuration file to illustrate the syntax :
\verbatim
...
OVTK_NodeId_Header_StreamedMatrix EBML::CIdentifier(0x0072F560, 0x7ED2CBED) master
OVTK_NodeId_Header_StreamedMatrix_DimensionCount EBML::CIdentifier(0x003FEBD4, 0x2725D428) uinteger
OVTK_NodeId_Header_StreamedMatrix_Dimension EBML::CIdentifier(0x0000E3C0, 0x3A7D5141) master
OVTK_NodeId_Header_StreamedMatrix_Dimension_Size EBML::CIdentifier(0x001302F7, 0x36D8438A) uinteger
OVTK_NodeId_Header_StreamedMatrix_Dimension_Label EBML::CIdentifier(0x00153E40, 0x190227E0) string
OVTK_NodeId_Buffer_StreamedMatrix EBML::CIdentifier(0x00120663, 0x08FBC165) master
OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer EBML::CIdentifier(0x00B18C10, 0x427D098C) binary
OVTK_NodeId_Header_Signal EBML::CIdentifier(0x007855DE, 0x3748D375) master
OVTK_NodeId_Header_Signal_Sampling EBML::CIdentifier(0x00141C43, 0x0C37006B) uinteger
...
\endverbatim
* |OVP_DocEnd_BoxAlgorithm_EBMLStreamSpy_Miscellaneous|
*/
@@ -0,0 +1,109 @@
/**
* \page BoxAlgorithm_ExternalProcessing External Processing
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Description|
This box allows to externalize data processing into an external program. It sends EBML data in chunks
according to a specified protocol, the external application must respond with an EBML response following
this same protocol.
A SDK for C++ and Python 3 (Python NeuroRT Box) are provided in order to simplify the development of
external boxes.
This box can work in two modes, either it launches the external program itself, or it will wait for client
connections during the initialize step.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Description|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Settings|
The External Processing box has several settings. The first eight parameters are reserved for the
box. Any additional parameters will be passed to the external program.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Settings|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting1|
If true, the box will attempt to start the external program automatically. If this setting is false, then the box will stop
during the initialize step and wait for the external program to connect during the time speficied by the Connection Timeout setting.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting1|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting2|
Path to the executable to run. This parameter is only used if the first parameter is activated.
Example: OpenViBE SDK comes with two example programs, one can be found in ${Path_Bin}/sdk-examples-communication-client-filter
Example: In the case you want to run a Python script on Windows, the program you are running is python, e.g: C:/Python35/python.exe
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting2|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting3|
Arguments passed to the third party program, if any are necessary. This parameter is only used if the first parameter is activated.
This parameter will be given to the third party program as is, thus it is necessary to quote any arguments that contain spaces.
Example: In the case you want to run a Python script on Windows, the parameter is the absolute path to the script that you want to run, e.g.: "C:/MyProject/myprogram.py" or "-m mylibrary.mymodule.mybox".
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting3|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting4|
The TCP port that the box is listening. It must be in the range 49152-65535 or it can be 0, in which case the port will be chosen
automatically.
The box acts as a Socket server and the external program as a client. If you have several External Processing boxes in the same scenario
each has to work on a different port.
An argument, with the value of the port, will be given to the third party program (after the Arguments parameter ) as: --port PORT
This means that your external program must accept the --port parameter and use it to connect to this box.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting4|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting5|
Whether or not to generate of a connection identifier for the connection. See the next setting for explanation.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting5|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting6|
This argument will be passed to the external program as a command line parameter: `--connection-id CONNECTIONID` and will be communicated to your
program through the protocol as well. You should check that the two are matching in order to avoid a clash if two boxes would be using the same
port.
We advise you to use an automatic identifier generation in production. Choose your custom connection identifier is however necessary when running
the external program explicitly.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting6|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting7|
A timeout, in seconds, for the incoming connection acceptance.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting7|
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Setting8|
This setting changes how often the box will process data. Each data processing requires that the box will
wait until it has received a response from the external program. Too many of these synchronisations can
induce a severe performance penalty.
If the box is a generator, then it will wait for the external program on each step. If the scenario is
played in real-time, then the box will poll the external program at 16Hz. If the scenario is in fast-forward
the refresh frequency of this box is 1Hz.
If this setting is set to false, the box will send all data it receives into the external program and wait
until it processes it and sends it back.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Setting8|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_ExternalProcessing_Miscellaneous|
This box requires synchronization with the external program in order to process data correctly and in order.
As the synchronization is a relatively slow process with regards to the duration of one update cycle (62ms) it
is better to try to limit the number of chunks that are send between the box and the client application.
If you find that your scenario is too slow, try using time based epoching in front of it to make chunks of data
larger.
* |OVP_DocEnd_BoxAlgorithm_ExternalProcessing_Miscellaneous|
*/
@@ -0,0 +1,47 @@
/**
* \page BoxAlgorithm_MatrixValidityChecker Matrix validity checker
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatrixValidityChecker_Description|
Ensures values stored in a matrix are valid, i.e. regular floating point values as opposed to NaN (not a number) or infinite.
* |OVP_DocEnd_BoxAlgorithm_MatrixValidityChecker_Description|
__________________________________________________________________
Inputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatrixValidityChecker_Inputs|
* |OVP_DocEnd_BoxAlgorithm_MatrixValidityChecker_Inputs|
* |OVP_DocBegin_BoxAlgorithm_MatrixValidityChecker_Input1|
* |OVP_DocEnd_BoxAlgorithm_MatrixValidityChecker_Input1|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatrixValidityChecker_Settings|
* |OVP_DocEnd_BoxAlgorithm_MatrixValidityChecker_Settings|
* |OVP_DocBegin_BoxAlgorithm_MatrixValidityChecker_Setting1|
Log level of messages to be printed whenever Nan or infinite values are found in input matrix.
* |OVP_DocEnd_BoxAlgorithm_MatrixValidityChecker_Setting1|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatrixValidityChecker_Examples|
* |OVP_DocEnd_BoxAlgorithm_MatrixValidityChecker_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatrixValidityChecker_Miscellaneous|
* |OVP_DocEnd_BoxAlgorithm_MatrixValidityChecker_Miscellaneous|
*/
@@ -0,0 +1,103 @@
/**
* \page BoxAlgorithm_StimulationListener Stimulation listener
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_StimulationListener_Description|
* The stimulation listener is a debugging purpose box, with
* the same idea as the \ref Doc_BoxAlgorithm_EBMLStreamSpy box
* but dedicated to stimulation streams. The idea is to dramatically
* reduce the log verbosity so the output may be followed realtime
* if necessary.
* |OVP_DocEnd_BoxAlgorithm_StimulationListener_Description|
__________________________________________________________________
Inputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_StimulationListener_Inputs|
* This box can receive as many input as necessary. All the inputs
* will be of type \ref Doc_Streams_Stimulation in order to
* be parsed by this the reader.
* |OVP_DocEnd_BoxAlgorithm_StimulationListener_Inputs|
* |OVP_DocBegin_BoxAlgorithm_StimulationListener_Input1|
* This is the default input of this box.
* |OVP_DocEnd_BoxAlgorithm_StimulationListener_Input1|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_StimulationListener_Settings|
* |OVP_DocEnd_BoxAlgorithm_StimulationListener_Settings|
* |OVP_DocBegin_BoxAlgorithm_StimulationListener_Setting1|
* This setting indicates what log level will be used to
* print the the received stimulations.
* |OVP_DocEnd_BoxAlgorithm_StimulationListener_Setting1|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_StimulationListener_Examples|
* As an example, we could connect a clock stimulator to a
* stimulation listener. Leave the default settings of the
* clock stimulator, so it sends an \e OVTK_StimulationId_Label_00
* stimulation every second. Now chose an appropriate log level
* for the stimulation listener and press 'start'. If you're
* familiar to what \ref Doc_BoxAlgorithm_EBMLStreamSpy produces,
* you may feel more confortable with what is produced here for
* stimulations.
*
* The output should look like this :
\verbatim
...
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 4294967296 (0x100000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 8589934592 (0x200000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 12884901888 (0x300000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 17179869184 (0x400000000) and duration 0 (0x0)
...
\endverbatim
*
* Now let's try to understand what is produced. Each line represents
* received stimulation. The input index which received the stimulation
* is printed. Then follow the stimulation code, its date and its duration.
* The stimulation name is retrieved from the type manager when correctly
* registered. Here, you can see that an \e OVTK_StimulationId_Label_00 is
* received every second.
*
* More tests could be done with another clock stimulator with different
* timings and stimulation codes. You will want to add inputs to the stimulation
* listener box in order to get proper results. For example with one more box
* sending \e OVTK_StimulationId_Label_01 every half second, the output would
* look like this :
\verbatim
...
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 2147483648 (0x80000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 4294967296 (0x100000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 4294967296 (0x100000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 6442450944 (0x180000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 8589934592 (0x200000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 8589934592 (0x200000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 10737418240 (0x280000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 12884901888 (0x300000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 12884901888 (0x300000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 15032385536 (0x380000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 17179869184 (0x400000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 17179869184 (0x400000000) and duration 0 (0x0)
...
\endverbatim
* |OVP_DocEnd_BoxAlgorithm_StimulationListener_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_StimulationListener_Miscellaneous|
* |OVP_DocEnd_BoxAlgorithm_StimulationListener_Miscellaneous|
*/
@@ -0,0 +1,214 @@
.. _Doc_BoxAlgorithm_EBMLStreamSpy:
EBML stream spy
===============
.. container:: attribution
:Author:
Yann Renard
:Company:
INRIA/IRISA
.. image:: images/Doc_BoxAlgorithm_EBMLStreamSpy.png
This sample EBML stream analyzer prints the EBML tree structure to the console
The purpose of this box is to spy an EBML stream and decode its structure to
the log manager. In order to do so, the box has to know a list of expected EBML
node identifiers and EBML node types. If you don't know what EBML is, you
should check the `EBML Documentation
<https://github.com/Matroska-Org/ebml-specification>`_ page. The list of
expected node identifiers and types is collected from a configuration file.
Also, the author is able to chose which log level to use in order to output the
information.
Such box is mostly useful for debug purpose. It allows
a developper to check what arrives to a box in a human
readable way.
Inputs
------
.. csv-table::
:header: "Input Name", "Stream Type"
"Spied EBML stream 1", "EBML stream"
This box can receive as many input as necessary. All the inputs
will be of type :ref:`Doc_Streams_EBML` in order to
be parsed by this the reader.
Spied EBML stream 1
~~~~~~~~~~~~~~~~~~~
This is the default input of this box.
.. _Doc_BoxAlgorithm_EBMLStreamSpy_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"EBML nodes description", "Filename", "${Path_Data}/plugins/tools/config-ebml-stream-spy.txt"
"Log level to use", "Log level", "Information"
"Expand binary blocks", "Boolean", "false"
"Number of values in expanded blocks", "Integer", "4"
EBML nodes description
~~~~~~~~~~~~~~~~~~~~~~
This first setting indicates where to find the configuration file.
The box comes with a default configuration file containing all the
default node identifiers of NeuroRT. You should extend this
configuration in order to add your own EBML nodes in case you
have created new EBML stream types.
Log level to use
~~~~~~~~~~~~~~~~
This second settings indicates what log level will be used to
print the EBML stream structure.
.. _Doc_BoxAlgorithm_EBMLStreamSpy_Examples:
Examples
--------
As an example, we could connect an EBML stream spy to a sinus
oscillator. Leave the default sinus oscillator settings to their
default, except the sample count per buffer can be set to 8 for the
example. Chose an appropriate log level for the EBML stream spy and
press 'start'. You will probably notice that a lot of text is sent
to the log manager, making the use of this box difficult in real time.
Once again, consider it as a debugging box.
The output should look like this :
.. code::
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x00000000),(0x00000000, 0x00000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x002b395f, 0x108adfae)]-[name:OVTK_NodeId_Header]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cdd0f7, 0x46b0278d)]-[name:OVTK_NodeId_Header_StreamType]-[type:uinteger]-[value:0 (0x0)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x006f5a08, 0x7796ebc5)]-[name:OVTK_NodeId_Header_StreamVersion]-[type:uinteger]-[value:0 (0x0)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x007855de, 0x3748d375)]-[name:OVTK_NodeId_Header_Signal]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00141c43, 0x0c37006b)]-[name:OVTK_NodeId_Header_Signal_Sampling]-[type:uinteger]-[value:512 (0x200)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x0072f560, 0x7ed2cbed)]-[name:OVTK_NodeId_Header_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x003febd4, 0x2725d428)]-[name:OVTK_NodeId_Header_StreamedMatrix_DimensionCount]-[type:uinteger]-[value:2 (0x2)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x0000e3c0, 0x3a7d5141)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x001302f7, 0x36d8438a)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Size]-[type:uinteger]-[value:4 (0x4)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 0]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 1]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 2]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:Channel 3]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x0000e3c0, 0x3a7d5141)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x001302f7, 0x36d8438a)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Size]-[type:uinteger]-[value:8 (0x8)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00153e40, 0x190227e0)]-[name:OVTK_NodeId_Header_StreamedMatrix_Dimension_Label]-[type:string]-[value:]
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x00000000),(0x00000000, 0x04000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cf2101, 0x02375310)]-[name:OVTK_NodeId_Buffer]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00120663, 0x08fbc165)]-[name:OVTK_NodeId_Buffer_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00b18c10, 0x427d098c)]-[name:OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer]-[type:binary]-[bytes:256 (0x100)]
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x04000000),(0x00000000, 0x08000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cf2101, 0x02375310)]-[name:OVTK_NodeId_Buffer]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00120663, 0x08fbc165)]-[name:OVTK_NodeId_Buffer_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00b18c10, 0x427d098c)]-[name:OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer]-[type:binary]-[bytes:256 (0x100)]
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy>
[ INF ] <Box algorithm::EBML stream spy> For input Spied EBML stream 1 of type EBML stream :
[ INF ] <Box algorithm::EBML stream spy> For chunk [id:0 (0x0)] at [time:(0x00000000, 0x08000000),(0x00000000, 0x0c000000)]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00cf2101, 0x02375310)]-[name:OVTK_NodeId_Buffer]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00120663, 0x08fbc165)]-[name:OVTK_NodeId_Buffer_StreamedMatrix]
[ INF ] <Box algorithm::EBML stream spy> Opened EBML node [id:(0x00b18c10, 0x427d098c)]-[name:OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer]-[type:binary]-[bytes:256 (0x100)]
[ INF ] <Box algorithm::EBML stream spy>
...
Now let's try to understand what is produced. First we notice a clear
separation between the different chunk the box receives. In each chunk, we
have an EBML hierarchy with the different nodes. Here we analyse a signal
stream so we have a header followed by multiple buffers.
Concerning the header, we can focuse on the signal header part and
the streamed matrix header part. In the first one, we can see that the sampling
rate node appears as an integer with value 512 (the default sinus oscillator
sampling frequency). The second one contains the description of the streamed
matrix. The matrix has two dimensions (electrodes and sample count per buffer).
The first dimension has a size of 4 (the default sinus oscillator channel count)
and each of this channel has a label (channel 0-3). Finally, the second dimension
has a size of 8 (the sample count per buffer you manually put in the sinus
oscillator configuration) and the samples themselves do not have a name.
Now looking at the buffer, we only have the streamed matrix part (signal
stream do not produce signal specific buffer). The buffer content can not
be displayed in the console (it could be a huge amount of binary non human
readable data, so it is not relevant to print it). But you have an information
of the size of this buffer. 256 is exactly the number of channels (4) multiplied
by the number of samples per buffer (8) multiplied by the size of a single sample
(8 because a sample is coded on a 64 bits float).
When familiar with EBML and OpenViBE streams, this box is a strong tool
to analyze what is sent from a box to another.
.. _Doc_BoxAlgorithm_EBMLStreamSpy_Miscellaneous:
Miscellaneous
-------------
The syntax of the configuration file is simple. Each line of the file
should contain 3 fields. The first field is the name of the EBML node
that should be printed in the log manager (this is human readable).
The second field is the EBML node identifier. The last field is the node
type. Several types are supported :
- \e master : this means that this node does not have data attached but has
several children. Any non master node is a leaf, so can contain data.
- \e integer : this means that this node contains a signed integer value
- \e uinteger : this means that this node contains an unsigned integer value
- \e string : this means that this node contains an ASCII string value
- \e float : this means that this node contains a floating point value
- \e binary : this means that this node contains a raw buffer of elements.
In such case, only the size of the buffer is printed. The content of the
buffer is not printed.
Any node identifier found in the stream and not present in the configuration
file will be considered of type \e unknown and treated as if it was a \e binary
node.
Following is a part of the sample configuration file to illustrate the syntax :
.. code::
...
OVTK_NodeId_Header_StreamedMatrix EBML::CIdentifier(0x0072F560, 0x7ED2CBED) master
OVTK_NodeId_Header_StreamedMatrix_DimensionCount EBML::CIdentifier(0x003FEBD4, 0x2725D428) uinteger
OVTK_NodeId_Header_StreamedMatrix_Dimension EBML::CIdentifier(0x0000E3C0, 0x3A7D5141) master
OVTK_NodeId_Header_StreamedMatrix_Dimension_Size EBML::CIdentifier(0x001302F7, 0x36D8438A) uinteger
OVTK_NodeId_Header_StreamedMatrix_Dimension_Label EBML::CIdentifier(0x00153E40, 0x190227E0) string
OVTK_NodeId_Buffer_StreamedMatrix EBML::CIdentifier(0x00120663, 0x08FBC165) master
OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer EBML::CIdentifier(0x00B18C10, 0x427D098C) binary
OVTK_NodeId_Header_Signal EBML::CIdentifier(0x007855DE, 0x3748D375) master
OVTK_NodeId_Header_Signal_Sampling EBML::CIdentifier(0x00141C43, 0x0C37006B) uinteger
...
@@ -0,0 +1,150 @@
.. _Doc_BoxAlgorithm_ExternalProcessing:
External Processing
===================
.. container:: attribution
:Author:
Alexis Placet
:Company:
Mensia Technologies SA
.. image:: images/Doc_BoxAlgorithm_ExternalProcessing.png
Launches an external program which can then process data. This box and the program communicate using TCP connection and a defined protocol.
This box allows to externalize data processing into an external program. It sends EBML data in chunks
according to a specified protocol, the external application must respond with an EBML response following
this same protocol.
A SDK for C++ and Python 3 (Python NeuroRT Box) are provided in order to simplify the development of
external boxes.
This box can work in two modes, either it launches the external program itself, or it will wait for client
connections during the initialize step.
.. _Doc_BoxAlgorithm_ExternalProcessing_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Launch third party program", "Boolean", "true"
"Executable path", "Filename", ""
"Arguments", "String", ""
"Port", "Integer", "0"
"Automatic connection identifier", "Boolean", "true"
"Custom connection identifier", "String", ""
"Incoming connection timeout", "Integer", "10"
"Generator", "Boolean", "false"
The External Processing box has several settings. The first eight parameters are reserved for the
box. Any additional parameters will be passed to the external program.
Launch third party program
~~~~~~~~~~~~~~~~~~~~~~~~~~
If true, the box will attempt to start the external program automatically.
We advise to use this mode in production.
If this setting is false, then the box will stop
during the initialize step and wait for the external program to connect during the time speficied by the Connection Timeout setting.
This mode is useful during development, since it allows to run the program manually and check the console.
Executable path
~~~~~~~~~~~~~~~
Path to the executable to run. This parameter is only used if the first parameter is activated.
Example: OpenViBE SDK comes with two example programs, one can be found in ``${Path_Bin}/sdk-examples-communication-client-filter``
Example: In the case you want to run a Python script on Windows, the program you are running is python, e.g: ``C:/Python35/python.exe``
Arguments
~~~~~~~~~
Arguments passed to the third party program, if any are necessary. This parameter is only used if the first parameter is activated.
This parameter will be given to the third party program as is, thus it is necessary to quote any arguments that contain spaces.
Example: In the case you want to run a Python script on Windows, the parameter is the absolute path to the script that you want to run, e.g.: ``C:/MyProject/myprogram.py`` or ``-m mylibrary.mymodule.mybox``.
Port
~~~~
The TCP port that the box is listening. It must be in the range 49152-65535 or it can be 0, in which case the port will be chosen
automatically.
The box acts as a Socket server and the external program as a client. If you have several External Processing boxes in the same scenario
each has to work on a different port.
We advise to use port ``0`` in production.
An argument, with the value of the port, will be given to the third party program (after the Arguments parameter ) as: ``--port PORT``
This means that your external program must accept the ``--port`` parameter and use it to connect to this box.
Automatic connection identifier
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Whether or not to generate of a connection identifier for the connection. See the next setting for explanation.
Custom connection identifier
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This argument will be passed to the external program as a command line parameter: ``--connection-id CONNECTIONID`` and will be communicated to your
program through the protocol as well. You should check that the two are matching in order to avoid a clash if two boxes would be using the same
port.
We advise you to use an automatic identifier generation in production. Choose your custom connection identifier is however necessary when running
the external program explicitly.
Incoming connection timeout
~~~~~~~~~~~~~~~~~~~~~~~~~~~
A timeout, in seconds, for the incoming connection acceptance.
Generator
~~~~~~~~~
This setting changes how often the box will process data. Each data processing requires that the box will
wait until it has received a response from the external program. Too many of these synchronisations can
induce a severe performance penalty.
If the box is a generator, then it will wait for the external program on each step. If the scenario is
played in real-time, then the box will poll the external program at 16Hz. If the scenario is in fast-forward
the refresh frequency of this box is 1Hz.
If this setting is set to false, the box will send all data it receives into the external program and wait
until it processes it and sends it back.
.. _Doc_BoxAlgorithm_ExternalProcessing_Miscellaneous:
Miscellaneous
-------------
Performances
~~~~~~~~~~~~
This box requires synchronization with the external program in order to process data correctly and in order.
As the synchronization is a relatively slow process with regards to the duration of one update cycle (62ms) it
is better to try to limit the number of chunks that are send between the box and the client application.
If you find that your scenario is too slow, try using time based epoching in front of it to make chunks of data
larger.
Development mode
~~~~~~~~~~~~~~~~
While developing your program, you may want to run it in Debug mode in your environment.
In order to run your program manually you should change the settings of the box:
* uncheck option ``Launch Third Party Program``,
* uncheck option ``Automatic connection identifier``,
* change the default port, for example to ``59595``, (make sure this is the default port used by your program)
* make sure the setting ``Incoming connection timeout`` will leave you enough time to run your program manually (default setting should be enough)
Then, you can first run your scenario through NeuroRT Studio, and then run your program manually.
@@ -0,0 +1,50 @@
.. _Doc_BoxAlgorithm_MatrixValidityChecker:
Matrix validity checker
=======================
.. container:: attribution
:Author:
Yann Renard
:Company:
INRIA/IRISA
.. image:: images/Doc_BoxAlgorithm_MatrixValidityChecker.png
This box is for debugging purposes and allows an author to check the validity of a streamed matrix and derived stream. This box can log a message, stop the player or interpolate data.
Ensures values stored in a matrix are valid, i.e. regular floating point values as opposed to NaN (not a number) or infinite.
Inputs
------
.. csv-table::
:header: "Input Name", "Stream Type"
"Stream 1", "Streamed matrix"
Outputs
-------
.. csv-table::
:header: "Output Name", "Stream Type"
"Output stream 1", "Streamed matrix"
.. _Doc_BoxAlgorithm_MatrixValidityChecker_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Log level", "Log level", "Warning"
"Action to do", "Action to do", "Log warning"
Log level
~~~~~~~~~
Log level of messages to be printed whenever Nan or infinite values are found in input matrix.
@@ -0,0 +1,110 @@
.. _Doc_BoxAlgorithm_StimulationListener:
Stimulation listener
====================
.. container:: attribution
:Author:
Yann Renard
:Company:
INRIA/IRISA
.. image:: images/Doc_BoxAlgorithm_StimulationListener.png
Prints each received stimulationto the log using the log level specified in the box config.
The stimulation listener is a debugging purpose box, with
the same idea as the :ref:`Doc_BoxAlgorithm_EBMLStreamSpy` box
but dedicated to stimulation streams. The idea is to dramatically
reduce the log verbosity so the output may be followed realtime
if necessary.
Inputs
------
.. csv-table::
:header: "Input Name", "Stream Type"
"Stimulation stream 1", "Stimulations"
This box can receive as many input as necessary. All the inputs
will be of type :ref:`Doc_Streams_Stimulation` in order to
be parsed by this the reader.
Stimulation stream 1
~~~~~~~~~~~~~~~~~~~~
This is the default input of this box.
.. _Doc_BoxAlgorithm_StimulationListener_Settings:
Settings
--------
.. csv-table::
:header: "Setting Name", "Type", "Default Value"
"Log level to use", "Log level", "Information"
Log level to use
~~~~~~~~~~~~~~~~
This setting indicates what log level will be used to
print the the received stimulations.
.. _Doc_BoxAlgorithm_StimulationListener_Examples:
Examples
--------
As an example, we could connect a clock stimulator to a
stimulation listener. Leave the default settings of the
clock stimulator, so it sends an \e OVTK_StimulationId_Label_00
stimulation every second. Now chose an appropriate log level
for the stimulation listener and press 'start'. If you're
familiar to what :ref:`Doc_BoxAlgorithm_EBMLStreamSpy` produces,
you may feel more confortable with what is produced here for
stimulations.
The output should look like this :
.. code::
...
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 4294967296 (0x100000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 8589934592 (0x200000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 12884901888 (0x300000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 17179869184 (0x400000000) and duration 0 (0x0)
...
Now let's try to understand what is produced. Each line represents
received stimulation. The input index which received the stimulation
is printed. Then follow the stimulation code, its date and its duration.
The stimulation name is retrieved from the type manager when correctly
registered. Here, you can see that an \e OVTK_StimulationId_Label_00 is
received every second.
More tests could be done with another clock stimulator with different
timings and stimulation codes. You will want to add inputs to the stimulation
listener box in order to get proper results. For example with one more box
sending \e OVTK_StimulationId_Label_01 every half second, the output would
look like this :
.. code::
...
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 2147483648 (0x80000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 4294967296 (0x100000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 4294967296 (0x100000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 6442450944 (0x180000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 8589934592 (0x200000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 8589934592 (0x200000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 10737418240 (0x280000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 12884901888 (0x300000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 12884901888 (0x300000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 15032385536 (0x380000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 0 (0x0) with name Stimulation stream 1 got stimulation 33024 (0x8100)[OVTK_StimulationId_Label_00] at date 17179869184 (0x400000000) and duration 0 (0x0)
[ INF ] <Box algorithm::Stimulation listener> For input 1 (0x1) with name Stimulation stream 2 got stimulation 33025 (0x8101)[OVTK_StimulationId_Label_01] at date 17179869184 (0x400000000) and duration 0 (0x0)
...
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,74 @@
OVTK_NodeId_Acquisition_Header EBML::CIdentifier(0x00000000, 0x00004239) master
OVTK_NodeId_Acquisition_AcquisitionInfo EBML::CIdentifier(0x00000000, 0x00004240) master
OVTK_NodeId_Acquisition_ExperimentId EBML::CIdentifier(0x00000000, 0x00004241) uinteger
OVTK_NodeId_Acquisition_SubjectAge EBML::CIdentifier(0x00000000, 0x00004242) uinteger
OVTK_NodeId_Acquisition_SubjectGender EBML::CIdentifier(0x00000000, 0x00004243) uinteger
OVTK_NodeId_Acquisition_ChannelCount EBML::CIdentifier(0x00000000, 0x00004244) uinteger
OVTK_NodeId_Acquisition_SamplingFrequency EBML::CIdentifier(0x00000000, 0x00004245) uinteger
OVTK_NodeId_Acquisition_ChannelNames EBML::CIdentifier(0x00000000, 0x00004246) master
OVTK_NodeId_Acquisition_ChannelName EBML::CIdentifier(0x00000000, 0x00004247) string
OVTK_NodeId_Acquisition_GainFactors EBML::CIdentifier(0x00000000, 0x00004248) master
OVTK_NodeId_Acquisition_GainFactor EBML::CIdentifier(0x00000000, 0x00004249) float
OVTK_NodeId_Acquisition_ChannelLocations EBML::CIdentifier(0x00000000, 0x00004250) master
OVTK_NodeId_Acquisition_ChannelLocation EBML::CIdentifier(0x00000000, 0x00004251) binary(double)
OVTK_NodeId_Acquisition_Buffer EBML::CIdentifier(0x00000000, 0x0000005A) master
OVTK_NodeId_Acquisition_Samples EBML::CIdentifier(0x00000000, 0x0000005B) master
OVTK_NodeId_Acquisition_SamplesPerChannelCount EBML::CIdentifier(0x00000000, 0x0000005C) uinteger
OVTK_NodeId_Acquisition_SampleBlock EBML::CIdentifier(0x00000000, 0x0000005D) binary(float)
OVTK_NodeId_Acquisition_Stimulations EBML::CIdentifier(0x00000000, 0x00000060) master
OVTK_NodeId_Acquisition_StimulationsCount EBML::CIdentifier(0x00000000, 0x00000061) uinteger
OVTK_NodeId_Acquisition_Stimulation EBML::CIdentifier(0x00000000, 0x00000062) master
OVTK_NodeId_Acquisition_StimulationSampleIndex EBML::CIdentifier(0x00000000, 0x00000063) uinteger
OVTK_NodeId_Acquisition_StimulationIdentifier EBML::CIdentifier(0x00000000, 0x00000064) uinteger
OVTK_NodeId_Header EBML::CIdentifier(0x002B395F, 0x108ADFAE) master
OVTK_NodeId_Header_StreamType EBML::CIdentifier(0x00CDD0F7, 0x46B0278D) uinteger
OVTK_NodeId_Header_StreamVersion EBML::CIdentifier(0x006F5A08, 0x7796EBC5) uinteger
OVTK_NodeId_Buffer EBML::CIdentifier(0x00CF2101, 0x02375310) master
OVTK_NodeId_End EBML::CIdentifier(0x00D9DDC3, 0x0B12873A) master
OVTK_NodeId_Header_StreamedMatrix EBML::CIdentifier(0x0072F560, 0x7ED2CBED) master
OVTK_NodeId_Header_StreamedMatrix_DimensionCount EBML::CIdentifier(0x003FEBD4, 0x2725D428) uinteger
OVTK_NodeId_Header_StreamedMatrix_Dimension EBML::CIdentifier(0x0000E3C0, 0x3A7D5141) master
OVTK_NodeId_Header_StreamedMatrix_Dimension_Size EBML::CIdentifier(0x001302F7, 0x36D8438A) uinteger
OVTK_NodeId_Header_StreamedMatrix_Dimension_Label EBML::CIdentifier(0x00153E40, 0x190227E0) string
OVTK_NodeId_Buffer_StreamedMatrix EBML::CIdentifier(0x00120663, 0x08FBC165) master
OVTK_NodeId_Buffer_StreamedMatrix_RawBuffer EBML::CIdentifier(0x00B18C10, 0x427D098C) binary(double)
OVTK_NodeId_Header_Signal EBML::CIdentifier(0x007855DE, 0x3748D375) master
OVTK_NodeId_Header_Signal_Sampling EBML::CIdentifier(0x00141C43, 0x0C37006B) uinteger
OVTK_NodeId_Header_Spectrum EBML::CIdentifier(0x00CCFA4B, 0x14F37D4D) master
OVTK_NodeId_Header_Spectrum_FrequencyBand_Deprecated EBML::CIdentifier(0x0010983C, 0x21F8BDE5) master
OVTK_NodeId_Header_Spectrum_FrequencyBand_Start_Deprecated EBML::CIdentifier(0x00AA5654, 0x2403A2CB) float
OVTK_NodeId_Header_Spectrum_FrequencyBand_Stop_Deprecated EBML::CIdentifier(0x00A44C82, 0x05BE50D5) float
OVTK_NodeId_Header_Spectrum_FrequencyAbscissa EBML::CIdentifier(0x00D7287D, 0x622A2BF5) float
OVTK_NodeId_Header_Spectrum_Sampling EBML::CIdentifier(0x006876E9, 0x1DCB0CA1) uinteger
OVTK_NodeId_Buffer_Stimulation EBML::CIdentifier(0x006DEABE, 0x7FC05A20) master
OVTK_NodeId_Buffer_Stimulation_NumberOfStimulations EBML::CIdentifier(0x00BB790B, 0x2B8574D8) uinteger
OVTK_NodeId_Buffer_Stimulation_Stimulation EBML::CIdentifier(0x0016EAC6, 0x29FBCAA1) master
OVTK_NodeId_Buffer_Stimulation_Stimulation_ID EBML::CIdentifier(0x006FA5DB, 0x4BAC31E9) uinteger
OVTK_NodeId_Buffer_Stimulation_Stimulation_Date EBML::CIdentifier(0x00B866D8, 0x14DA5374) uinteger
OVTK_NodeId_Buffer_Stimulation_Stimulation_Duration EBML::CIdentifier(0x14EE055F, 0x87FBCC9C) uinteger
OVTK_NodeId_Header_ChannelUnits EBML::CIdentifier(0x17400C76, 0x16CF14C8) master
OVTK_NodeId_Header_ChannelUnits_Dynamic EBML::CIdentifier(0x7307023C, 0x7F754D2E) uinteger
OVTK_NodeId_Header_ChannelLocalisation EBML::CIdentifier(0xF2CFE60B, 0xEFD63E3B) master
OVTK_NodeId_Header_ChannelLocalisation_Dynamic EBML::CIdentifier(0x5338AF5C, 0x07C469C3) uinteger
OVTK_NodeId_Header_ExperimentInfo EBML::CIdentifier(0x00746BA0, 0x115AE04D) master
OVTK_NodeId_Header_ExperimentInfo_Experiment EBML::CIdentifier(0x0011D6B7, 0x48F1AA39) master
OVTK_NodeId_Header_ExperimentInfo_Experiment_ID EBML::CIdentifier(0x006ACD74, 0x1C960C26) uinteger
OVTK_NodeId_Header_ExperimentInfo_Experiment_Date EBML::CIdentifier(0x002F8FB7, 0x6DA7552D) uinteger
OVTK_NodeId_Header_ExperimentInfo_Subject EBML::CIdentifier(0x003EC620, 0x333E0A94) master
OVTK_NodeId_Header_ExperimentInfo_Subject_ID EBML::CIdentifier(0x00D62974, 0x473D4AA5) uinteger
OVTK_NodeId_Header_ExperimentInfo_Subject_Name EBML::CIdentifier(0x0041FD0A, 0x6BCD9A99) string
OVTK_NodeId_Header_ExperimentInfo_Subject_Age EBML::CIdentifier(0x00DF7DD9, 0x33336C51) uinteger
OVTK_NodeId_Header_ExperimentInfo_Subject_Gender EBML::CIdentifier(0x0069BB84, 0x3FC8E149) uinteger
OVTK_NodeId_Header_ExperimentInfo_Context EBML::CIdentifier(0x0018C291, 0x7985DFDD) master
OVTK_NodeId_Header_ExperimentInfo_Context_LaboratoryID EBML::CIdentifier(0x003F11B9, 0x26D76D9C) uinteger
OVTK_NodeId_Header_ExperimentInfo_Context_LaboratoryName EBML::CIdentifier(0x00EB1F23, 0x51C23B83) string
OVTK_NodeId_Header_ExperimentInfo_Context_TechnicianID EBML::CIdentifier(0x00874A7F, 0x60DC34C2) uinteger
OVTK_NodeId_Header_ExperimentInfo_Context_TechnicianName EBML::CIdentifier(0x00C8C393, 0x31CE5B3E) string
DummyEnd EBML::CIdentifier(0x00000000, 0x00000000) binary
@@ -0,0 +1,244 @@
#include "ovpCBoxAlgorithmEBMLStreamSpy.h"
#include <iostream>
#include <fstream>
#include <algorithm>
#include <fs/Files.h>
namespace OpenViBE {
namespace Plugins {
namespace Tools {
bool CBoxAlgorithmEBMLStreamSpy::initialize()
{
const Kernel::IBox& boxCtx = getStaticBoxContext();
m_reader = createReader(*this);
m_helper = EBML::createReaderHelper();
bool expand;
const CString fileName = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
const uint64_t logLevel = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
if (boxCtx.getSettingCount() > 2)
{
expand = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
m_nExpandValues = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3);
}
else
{
expand = false;
m_nExpandValues = 4;
}
m_logLevel = Kernel::ELogLevel(logLevel);
std::ifstream file;
FS::Files::openIFStream(file, fileName);
while (file.good() && !file.eof())
{
uint32_t id1;
uint32_t id2;
std::string identifier1;
std::string identifier2;
std::string name;
std::string type;
file >> name;
file >> identifier1;
file >> identifier2;
file >> type;
sscanf(identifier1.c_str(), "EBML::CIdentifier(0x%08x", &id1);
sscanf(identifier2.c_str(), "0x%08x)", &id2);
if (!expand)
{
if ((type == "binary(long double)") || (type == "binary(double)") || (type == "binary(float)")
|| (type == "binary(integer8)") || (type == "binary(integer16)") || (type == "binary(integer32)")
|| (type == "binary(integer64)") || (type == "binary(uinteger8)") || (type == "binary(uinteger16)")
|| (type == "binary(uinteger32)") || (type == "binary(uinteger64)")) { type = "binary"; }
}
// std::cout << "[" << identifier1 << "][" << identifier2 << "]" << std::endl;
// printf("[EBML::CIdentifier(0x%08X,][0x%08X]\n", id1, id2);
// std::cout << EBML::CIdentifier(id1, id2) << std::endl;
m_names[EBML::CIdentifier(id1, id2)] = name;
m_types[EBML::CIdentifier(id1, id2)] = type;
}
return true;
}
bool CBoxAlgorithmEBMLStreamSpy::uninitialize()
{
m_helper->release();
m_helper = nullptr;
m_reader->release();
m_reader = nullptr;
return true;
}
bool CBoxAlgorithmEBMLStreamSpy::isMasterChild(const EBML::CIdentifier& identifier)
{
const auto n = m_names.find(identifier);
const auto t = m_types.find(identifier);
if (n != m_names.end() && t != m_types.end()) { return (t->second == "master"); }
return false;
}
void CBoxAlgorithmEBMLStreamSpy::openChild(const EBML::CIdentifier& identifier)
{
const auto n = m_names.find(identifier);
getLogManager() << m_logLevel;
for (size_t i = 0; i <= m_nodes.size(); ++i) { getLogManager() << " "; }
getLogManager() << "Opened EBML node [id:" << identifier << "]-[name:" << (n != m_names.end() ? n->second : "unknown") << "]";
if (isMasterChild(identifier)) { getLogManager() << "\n"; }
m_nodes.push(identifier);
}
template <class T>
void CBoxAlgorithmEBMLStreamSpy::processBinaryBlock(const void* buffer, const size_t size)
{
const size_t n = (size / sizeof(T));
const T* buf = static_cast<const T*>(buffer);
for (size_t i = 0; i < std::min(m_nExpandValues, n); ++i) { getLogManager() << (i == 0 ? "" : " ") << buf[i]; }
if (m_nExpandValues < n) { getLogManager() << " ..."; }
}
void CBoxAlgorithmEBMLStreamSpy::processChildData(const void* buffer, const size_t size)
{
const auto t = m_types.find(m_nodes.top());
if (t != m_types.end())
{
if (t->second == "uinteger") { getLogManager() << "-[type:" << t->second << "]-[value:" << m_helper->getUInt(buffer, size) << "]"; }
else if (t->second == "integer") { getLogManager() << "-[type:" << t->second << "]-[value:" << m_helper->getInt(buffer, size) << "]"; }
else if (t->second == "float") { getLogManager() << "-[type:" << t->second << "]-[value:" << m_helper->getDouble(buffer, size) << "]"; }
else if (t->second == "string") { getLogManager() << "-[type:" << t->second << "]-[value:" << m_helper->getStr(buffer, size) << "]"; }
else if (t->second == "binary") { getLogManager() << "-[type:" << t->second << "]-[bytes:" << size << "]"; }
else if (t->second == "binary(double)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<double>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(float)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<float>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(integer8)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<int8_t>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(integer16)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<int16_t>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(integer32)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<int>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(integer64)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<int64_t>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(uinteger8)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<uint8_t>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(uinteger16)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<uint16_t>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(uinteger32)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<uint32_t>(buffer, size);
getLogManager() << "]";
}
else if (t->second == "binary(uinteger64)")
{
getLogManager() << "-[type:" << t->second << "]-[values:";
processBinaryBlock<uint64_t>(buffer, size);
getLogManager() << "]";
}
else { getLogManager() << "-[type:unknown]-[bytes:" << size << "]"; }
}
getLogManager() << "\n";
}
bool CBoxAlgorithmEBMLStreamSpy::processInput(const size_t /*index*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmEBMLStreamSpy::process()
{
Kernel::IBoxIO& boxCtx = getDynamicBoxContext();
const Kernel::IBox& staticBoxCtx = getStaticBoxContext();
uint64_t tStart = 0;
uint64_t tEnd = 0;
size_t size = 0;
const uint8_t* buffer = nullptr;
getLogManager() << m_logLevel << "\n";
for (size_t i = 0; i < staticBoxCtx.getInputCount(); ++i)
{
if (boxCtx.getInputChunkCount(i))
{
CString inputName;
staticBoxCtx.getInputName(i, inputName);
CIdentifier inputType;
staticBoxCtx.getInputType(i, inputType);
getLogManager() << m_logLevel << "For input " << inputName << " of type " << getTypeManager().getTypeName(inputType) << " :\n";
for (size_t j = 0; j < boxCtx.getInputChunkCount(i); ++j)
{
boxCtx.getInputChunk(i, j, tStart, tEnd, size, buffer);
boxCtx.markInputAsDeprecated(i, j);
getLogManager() << m_logLevel << "For chunk [id:" << j << "] at [time:" << CIdentifier(tStart) << "," << CIdentifier(tEnd)
<< " / " << CTime(tStart) << "," << CTime(tEnd) << "]\n";
m_reader->processData(buffer, size);
}
}
}
getLogManager() << m_logLevel << "\n";
return true;
}
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,106 @@
#pragma once
#include "../ovp_defines.h"
#include <toolkit/ovtk_all.h>
#include <ebml/IReader.h>
#include <ebml/IReaderHelper.h>
#include <map>
#include <stack>
#include <string>
namespace OpenViBE {
namespace Plugins {
namespace Tools {
class CBoxAlgorithmEBMLStreamSpy final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>, virtual public EBML::IReaderCallback
{
public:
CBoxAlgorithmEBMLStreamSpy() { }
void release() override { delete this; }
bool initialize() override;
bool uninitialize() override;
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 { m_nodes.pop(); }
bool processInput(const size_t index) override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_EBMLStreamSpy)
protected:
template <class T>
void processBinaryBlock(const void* buffer, size_t size);
std::stack<EBML::CIdentifier> m_nodes;
std::map<EBML::CIdentifier, std::string> m_names;
std::map<EBML::CIdentifier, std::string> m_types;
size_t m_nExpandValues = 0;
Kernel::ELogLevel m_logLevel = Kernel::ELogLevel::LogLevel_None;
EBML::IReader* m_reader = nullptr;
EBML::IReaderHelper* m_helper = nullptr;
};
class CBoxAlgorithmEBMLStreamSpyListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool check(Kernel::IBox& box) const
{
for (size_t i = 0; i < box.getInputCount(); ++i)
{
box.setInputName(i, ("Spied EBML stream " + std::to_string(i + 1)).c_str());
box.setInputType(i, OV_TypeId_EBMLStream);
}
return true;
}
bool onInputRemoved(Kernel::IBox& box, const size_t /*index*/) override { return this->check(box); }
bool onInputAdded(Kernel::IBox& box, const size_t /*index*/) override { return this->check(box); }
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmEBMLStreamSpyDesc final : public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return "EBML stream spy"; }
CString getAuthorName() const override { return "Yann Renard"; }
CString getAuthorCompanyName() const override { return "INRIA/IRISA"; }
CString getShortDescription() const override { return "EBML stream tree viewer"; }
CString getDetailedDescription() const override { return "This sample EBML stream analyzer prints the EBML tree structure to the console"; }
CString getCategory() const override { return "Tools"; }
CString getVersion() const override { return "1.0"; }
CString getSoftwareComponent() const override { return "openvibe-sdk"; }
CString getAddedSoftwareVersion() const override { return "0.0.0"; }
CString getUpdatedSoftwareVersion() const override { return "0.0.0"; }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_EBMLStreamSpy; }
IPluginObject* create() override { return new CBoxAlgorithmEBMLStreamSpy(); }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmEBMLStreamSpyListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Spied EBML stream 1", OV_TypeId_EBMLStream);
prototype.addSetting("EBML nodes description", OV_TypeId_Filename, "${Path_Data}/plugins/tools/config-ebml-stream-spy.txt");
prototype.addSetting("Log level to use", OV_TypeId_LogLevel, "Information");
prototype.addSetting("Expand binary blocks", OV_TypeId_Boolean, "false");
prototype.addSetting("Number of values in expanded blocks", OV_TypeId_Integer, "4");
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_EBMLStreamSpyDesc)
};
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,609 @@
#include "ovpCBoxAlgorithmExternalProcessing.h"
#include <chrono>
#include <cstdlib>
#include <stdlib.h>
#include <random>
#include <thread>
#include <algorithm>
#ifdef TARGET_OS_Windows
#include <process.h>
#include <Windows.h>
#include <ctime>
#else
#include <spawn.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
extern char **environ;
#endif
#include <system/ovCTime.h>
namespace OpenViBE {
namespace Plugins {
namespace Tools {
static Kernel::ELogLevel convertLogLevel(const Communication::ELogLevel level)
{
switch (level)
{
case Communication::LogLevel_Info: return Kernel::LogLevel_Info;
case Communication::LogLevel_Warning: return Kernel::LogLevel_Warning;
case Communication::LogLevel_Error: return Kernel::LogLevel_Error;
case Communication::LogLevel_Fatal: return Kernel::LogLevel_Fatal;
case Communication::LogLevel_Max:
case Communication::LogLevel_Unknown:
default: return Kernel::LogLevel_Info;
}
}
uint64_t CBoxAlgorithmExternalProcessing::getClockFrequency()
{
if (m_isGenerator)
{
// We slow down the generator type boxes by default, in order to limit syncing
// In fast forward we limit the syncing even more by setting the frequency to 1Hz
if (this->getPlayerContext().getStatus() == Kernel::EPlayerStatus::Forward) { return 1LL << 32; }
return 16LL << 32;
}
return 128LL << 32;
}
bool CBoxAlgorithmExternalProcessing::initialize()
{
m_port = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3);
// Check that the port is not in the system range
OV_ERROR_UNLESS_KRF((m_port >= 49152 && m_port <= 65535) || (m_port == 0),
"Port [" << m_port << "] is invalid. It must be either 0 or a number in the range 49152-65535.", Kernel::ErrorType::BadConfig);
// Settings
const Kernel::IBox& staticboxCtx = this->getStaticBoxContext();
for (size_t i = 8; i < staticboxCtx.getSettingCount(); ++i)
{
CString name;
staticboxCtx.getSettingName(i, name);
CIdentifier type;
staticboxCtx.getSettingType(i, type);
const CString value = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i);
OV_FATAL_UNLESS_K(m_messaging.addParameter(i, type.id(), name.toASCIIString(), value.toASCIIString()),
"Failed to add a parameter: " << i, Kernel::ErrorType::Internal);
}
// Inputs
for (size_t i = 0; i < staticboxCtx.getInputCount(); ++i)
{
CIdentifier type;
staticboxCtx.getInputType(i, type);
if (type == OV_TypeId_Stimulations) { m_decoders[i].initialize(*this, i); }
CString name;
staticboxCtx.getInputName(i, name);
OV_FATAL_UNLESS_K(m_messaging.addInput(i, type.id(), name.toASCIIString()),
"Failed to add an input: " << i, Kernel::ErrorType::Internal);
}
// Outputs
for (size_t i = 0; i < staticboxCtx.getOutputCount(); ++i)
{
CIdentifier type;
staticboxCtx.getOutputType(i, type);
CString name;
staticboxCtx.getOutputName(i, name);
if (!m_messaging.addOutput(i, type.id(), name.toASCIIString()))
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to add an output: " << i << "\n";
return false;
}
}
const bool mustGenerateConnectionID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 4);
if (mustGenerateConnectionID) { m_connectionID = generateConnectionID(32); }
else
{
const CString connectionID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 5);
m_connectionID = connectionID.toASCIIString();
}
OV_ERROR_UNLESS_KRF(m_messaging.listen(m_port),
"Could not listen to TCP port: " << m_port << ". This port may be already used by another service. Please try another one.",
Kernel::ErrorType::BadNetworkConnection);
if (m_port == 0)
{
m_messaging.getSocketPort(m_port);
this->getLogManager() << Kernel::LogLevel_Info << "Box is now listening on TCP port [" << m_port << "].\n";
}
m_shouldLaunchProgram = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
if (m_shouldLaunchProgram)
{
const CString programPath = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
const CString arguments = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
if (!launchThirdPartyProgram(programPath.toASCIIString(), arguments.toASCIIString()))
{
// Error message in the function
return false;
}
this->getLogManager() << Kernel::LogLevel_Info << "Third party program [" << programPath.toASCIIString() << "] started.\n";
}
const auto startTime = System::Time::zgetTime();
bool clientConnected = false;
m_hasReceivedEndMessage = false;
m_acceptTimeout = CTime(double(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 6))).time();
m_isGenerator = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 7);
while (System::Time::zgetTime() - startTime < m_acceptTimeout)
{
if (m_messaging.accept())
{
clientConnected = true;
this->getLogManager() << Kernel::LogLevel_Info << "Client connected to the server.\n";
break;
}
const Communication::MessagingServer::ELibraryError error = m_messaging.getLastError();
if (error == Communication::MessagingServer::ELibraryError::BadAuthenticationReceived)
{
OV_WARNING_K("A client sent a bad authentication.");
break;
}
if (error == Communication::MessagingServer::ELibraryError::NoAuthenticationReceived) { OV_WARNING_K("The client has not sent authentication."); }
}
OV_ERROR_UNLESS_KRF(clientConnected, "No client connected before the timeout.", Kernel::ErrorType::Internal);
// Now synchronize once with the client so it can perform its initialize before
// the processing starts
m_messaging.pushSync();
while (m_messaging.isConnected() && !m_messaging.waitForSyncMessage())
{
if (!m_messaging.waitForSyncMessage()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); }
}
m_syncTimeout = CTime(0.0625).time();
m_lastSyncTime = System::Time::zgetTime();
return true;
}
bool CBoxAlgorithmExternalProcessing::uninitialize()
{
for (auto& decoder : m_decoders) { decoder.second.uninitialize(); }
if (!m_hasReceivedEndMessage)
{
const bool result = m_messaging.close();
#ifdef TARGET_OS_Windows
if (m_shouldLaunchProgram && m_extProcessId > 0)
{
DWORD exitCode;
// Wait for external process to stop by himself, terminate it if necessary
const auto startTime = System::Time::zgetTime();
while (System::Time::zgetTime() - startTime < m_acceptTimeout)
{
GetExitCodeProcess(HANDLE(m_extProcessId), &exitCode);
if (exitCode != STILL_ACTIVE) { break; }
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (exitCode == STILL_ACTIVE)
{
OV_ERROR_UNLESS_KRF(TerminateProcess(HANDLE(m_extProcessId), EXIT_FAILURE), "Failed to kill third party program.",
Kernel::ErrorType::Unknown);
}
else if (exitCode != 0) { OV_WARNING_K("Third party program [" << m_extProcessId << "] has terminated with exit code [" << int(exitCode) << "]"); }
}
#else
if (m_shouldLaunchProgram && m_extProcessId != 0)
{
int status;
pid_t pid = waitpid(m_extProcessId, &status, WNOHANG);
// Wait for external process to stop by himself, terminate it after 10s
auto startTime = System::Time::zgetTime();
while (pid == 0 && System::Time::zgetTime() - startTime < m_acceptTimeout)
{
// Check if the program has hung itself
pid = waitpid(m_extProcessId, &status, WNOHANG);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (pid != 0)
{
if (WIFEXITED(status)) { OV_WARNING_K("Third party program [" << m_extProcessId << "] has terminated with exit code [" << WEXITSTATUS(status) << "]"); }
else if (WIFSIGNALED(status)) { OV_WARNING_K("Third party program [" << m_extProcessId << "] killed by signal [" << WTERMSIG(status) << "]"); }
}
else
{
kill(m_extProcessId, SIGTERM);
waitpid(m_extProcessId, &status, 0);
this->getLogManager() << Kernel::LogLevel_Info << "Third party program [" << m_extProcessId << "] exited with status [" << WEXITSTATUS(status) << "]\n";
}
}
#endif
return result;
}
return true;
}
bool CBoxAlgorithmExternalProcessing::processClock(Kernel::CMessageClock& /*msg*/) { return this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess(); }
bool CBoxAlgorithmExternalProcessing::processInput(const size_t /*index*/)
{
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmExternalProcessing::process()
{
if (m_messaging.isInErrorState())
{
const std::string errorString = Communication::MessagingServer::getErrorString(m_messaging.getLastError());
OV_ERROR_KRF("Error state connection: " << errorString << ".\n This may be due to a broken client connection.",
Kernel::ErrorType::BadNetworkConnection);
}
if (m_hasReceivedEndMessage == false && m_messaging.isEndReceived() == true)
{
this->getLogManager() << Kernel::LogLevel_Info << "The third party program has ended the communication.\n";
m_messaging.close();
m_hasReceivedEndMessage = true;
}
OV_ERROR_UNLESS_KRF(m_messaging.pushTime(this->getPlayerContext().getCurrentTime()), "Failed to push Time.", Kernel::ErrorType::BadNetworkConnection);
const Kernel::IBox& staticboxCtx = this->getStaticBoxContext();
Kernel::IBoxIO& boxCtx = this->getDynamicBoxContext();
// Send input EBML to the client
bool hasSentDataToClient = false;
for (size_t i = 0; i < staticboxCtx.getInputCount(); ++i)
{
auto maybeStimulationDecoder = m_decoders.find(i);
for (size_t j = 0; j < boxCtx.getInputChunkCount(i); ++j)
{
if (!m_hasReceivedEndMessage)
{
uint64_t startTime = 0;
uint64_t endTime = 0;
size_t chunkSize = 0;
const uint8_t* chunkBuffer = nullptr;
OV_FATAL_UNLESS_K(boxCtx.getInputChunk(i, j, startTime, endTime, chunkSize, chunkBuffer),
"Failed to get input chunk [" << i << "][" << j << "]", Kernel::ErrorType::Internal);
std::shared_ptr<std::vector<uint8_t>> ebml(new std::vector<uint8_t>(chunkBuffer, chunkBuffer + chunkSize));
// We only encode stimulation stream chunks if they contain stimulations
if (maybeStimulationDecoder != m_decoders.end())
{
maybeStimulationDecoder->second.decode(j, false); // The input will be marked as deprecated later
// Cache empty chunks, we will send them when a stimulation or a signal chunk arrives
if (maybeStimulationDecoder->second.getOutputStimulationSet()->getStimulationCount() == 0)
{
m_packetHistory.emplace(startTime, endTime, i, ebml);
OV_FATAL_UNLESS_K(boxCtx.markInputAsDeprecated(i, j), "Failed to mark input as deprecated", Kernel::ErrorType::Internal);
break;
}
}
// Empty the history before to send useful data
while (!m_packetHistory.empty())
{
OV_ERROR_UNLESS_KRF(m_messaging.pushEBML(m_packetHistory.front().index, m_packetHistory.front().startTime, m_packetHistory.front().endTime,
m_packetHistory.front().EBML), "Failed to push EBML.", Kernel::ErrorType::BadNetworkConnection);
m_packetHistory.pop();
}
// Push the last EBML
OV_ERROR_UNLESS_KRF(m_messaging.pushEBML(i, startTime, endTime, ebml), "Failed to push EBML.", Kernel::ErrorType::BadNetworkConnection);
hasSentDataToClient = true;
}
OV_FATAL_UNLESS_K(boxCtx.markInputAsDeprecated(i, j), "Failed to mark input as deprecated", Kernel::ErrorType::Internal);
}
}
if (hasSentDataToClient || m_isGenerator || System::Time::zgetTime() - m_lastSyncTime > m_syncTimeout)
{
m_lastSyncTime = System::Time::zgetTime();
// Here, we send a sync message to tell to the client that we have no more data to send.
// Generators do not have input data, so the box never has to send data to the external program
// and thus needs to perform syncing on each tick.
OV_ERROR_UNLESS_KRF(m_messaging.pushSync(), "Failed to push sync message.", Kernel::ErrorType::BadNetworkConnection);
if (!m_hasReceivedEndMessage)
{
this->log();
uint64_t packetId;
size_t index;
uint64_t startTime;
uint64_t endTime;
std::shared_ptr<const std::vector<uint8_t>> ebml;
bool receivedSync = false;
while (!receivedSync && !m_hasReceivedEndMessage && !m_messaging.isInErrorState() && m_messaging.isConnected())
{
receivedSync = m_messaging.waitForSyncMessage();
while (m_messaging.popEBML(packetId, index, startTime, endTime, ebml))
{
OV_ERROR_UNLESS_KRF(boxCtx.appendOutputChunkData(index, ebml->data(), ebml->size()),
"Failed to append output chunk data.", Kernel::ErrorType::Internal);
OV_ERROR_UNLESS_KRF(boxCtx.markOutputAsReadyToSend(index, startTime, endTime),
"Failed to mark output as ready to send.", Kernel::ErrorType::Internal);
}
if (!receivedSync) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); }
}
}
}
return true;
}
std::string CBoxAlgorithmExternalProcessing::generateConnectionID(const size_t size)
{
std::default_random_engine generator{ std::random_device()() };
std::uniform_int_distribution<int> uni(0, 34);
std::string connectionID;
for (size_t i = 0; i < size; ++i)
{
const char c = char(uni(generator));
connectionID.push_back((c < 26) ? ('A' + c) : '1' + (c - 26));
}
return connectionID;
}
static std::vector<std::string> splitCommandLine(const std::string& cmdLine)
{
std::vector<std::string> list;
std::string arg;
bool escape = false;
enum { Idle, Arg, QuotedArg } state = Idle;
for (const char c : cmdLine)
{
if (!escape && c == '\\')
{
escape = true;
continue;
}
switch (state)
{
case Idle:
if (!escape && c == '"')
{
state = QuotedArg;
#if defined TARGET_OS_Windows
arg += c;
#endif
}
else if (escape || c != ' ')
{
arg += c;
state = Arg;
}
break;
case Arg:
if (!escape && c == '"')
{
state = QuotedArg;
#if defined TARGET_OS_Windows
arg += c;
#endif
}
else if (escape || c != ' ') { arg += c; }
else
{
list.push_back(arg);
arg.clear();
state = Idle;
}
break;
case QuotedArg:
if (!escape && c == '"')
{
state = arg.empty() ? Idle : Arg;
#if defined TARGET_OS_Windows
arg += c;
#endif
}
else { arg += c; }
break;
}
escape = false;
}
if (!arg.empty()) { list.push_back(arg); }
return list;
}
char* strToChar(const std::string& s)
{
char* c = new char[s.size() + 1];
std::copy(s.begin(), s.end(), c);
return c;
}
bool CBoxAlgorithmExternalProcessing::launchThirdPartyProgram(const std::string& programPath, const std::string& arguments)
{
m_extProcessId = 0;
const std::vector<std::string> argumentsVector = splitCommandLine(arguments);
std::vector<std::string> programArguments = { programPath, "--connection-id", m_connectionID, "--port", std::to_string(m_port) };
programArguments.insert(programArguments.begin() + 1, argumentsVector.cbegin(), argumentsVector.cend()); // Add the arguments after the program path.
std::vector<char*> argv;
std::transform(programArguments.begin(), programArguments.end(), std::back_inserter(argv), strToChar);
argv.push_back(nullptr);
#ifdef TARGET_OS_Windows
// _spawnp on Windows has a special case for empty program
int status;
if (programPath.empty())
{
status = -1;
_set_errno(ENOENT);
}
else { status = int(_spawnvp(_P_NOWAIT, programPath.c_str(), argv.data())); }
m_extProcessId = status;
// _P_DETACH,
#else
posix_spawn_file_actions_t fileAction;
int res = posix_spawn_file_actions_init(&fileAction);
OV_ERROR_UNLESS_KRF(res==0, "File action could not be initialized. Got error [" << res << "]", Kernel::ErrorType::BadCall);
res = posix_spawn_file_actions_addclose(&fileAction, STDOUT_FILENO);
OV_ERROR_UNLESS_KRF(res==0, "File action 'close' could not be added. Got error [" << res << "]", Kernel::ErrorType::BadCall);
this->getLogManager() << Kernel::LogLevel_Info << "Run third party program [" << programPath << "] with arguments [" << arguments << "].\n";
int status = posix_spawnp(&m_extProcessId, programPath.c_str(), &fileAction, nullptr, argv.data(), environ);
#ifdef TARGET_OS_Linux
// On linux the glibc is bugged and posix_spawnp does not actually work as specified
// we have to check if the program did not exit immediately with a 127 error code
// for this we need to wait a bit because it could be that the process has not yet launched
// wait until the process exists or if it has failed
bool processExists = false;
bool processHasFailed = false;
while (!processExists && !processHasFailed)
{
System::Time::sleep(10);
processExists = (kill(m_extProcessId, 0) == 0);
int childStatus;
pid_t pid = waitpid(m_extProcessId, &childStatus, WNOHANG);
if (pid != 0)
{
// The process is dead
if (WIFEXITED(childStatus))
{
// If the exit status is 0 this means that maybe we will actually succeed in launching the program
if (WEXITSTATUS(childStatus) != 0)
{
m_extProcessId = 0;
status = WEXITSTATUS(childStatus);
}
}
else
{
OV_WARNING_K("The third party process died");
m_extProcessId = 0;
status = 1;
}
processHasFailed = true;
}
}
#endif
#endif
for (size_t i = 0; i < argv.size() - 1; ++i) { delete[] argv[i]; }
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
if (status != 0)
{
const std::string errorMessage = "Failed to launch the program [" + programPath + "]: ";
m_extProcessId = 0;
OV_ERROR_KRF( errorMessage.c_str() << "[" << status << "]", Kernel::ErrorType::BadResourceCreation);
}
#else
if (status == -1)
{
std::string errorMessage = "Failed to launch the program [" + programPath + "]:";
switch (errno)
{
case E2BIG:
errorMessage += "Argument list exceeds 1024 bytes.\n";
break;
case EINVAL:
errorMessage += "Mode argument is invalid.\n";
break;
case ENOENT:
errorMessage += "File or path is not found.\n";
break;
case ENOEXEC:
errorMessage += "Specified file is not executable or has invalid executable-file format.\n";
break;
case ENOMEM:
errorMessage += "Not enough memory is available to execute the new process.\n";
break;
default:
errorMessage += "Unknown error.\n";
break;
}
OV_ERROR_KRF(errorMessage.c_str(), Kernel::ErrorType::BadResourceCreation);
}
#endif
return true;
}
void CBoxAlgorithmExternalProcessing::log()
{
Communication::ELogLevel logLevel;
std::string logMessage;
uint64_t packetId;
while (m_messaging.popLog(packetId, logLevel, logMessage))
{
this->getLogManager() << convertLogLevel(logLevel) << "From third party program: " << logMessage << "\n";
}
}
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,143 @@
#pragma once
#include "../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <communication/ovCMessagingServer.h>
#include <map>
#include <queue>
#include <vector>
#include <cstdint>
namespace OpenViBE {
namespace Plugins {
namespace Tools {
class CBoxAlgorithmExternalProcessing final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
CBoxAlgorithmExternalProcessing() : m_acceptTimeout(10ULL << 32) {}
void release() override { delete this; }
uint64_t getClockFrequency() override;
bool initialize() override;
bool uninitialize() override;
bool processClock(Kernel::CMessageClock& msg) override;
bool processInput(const size_t index) override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_ExternalProcessing)
private:
struct SPacket
{
uint64_t startTime;
uint64_t endTime;
size_t index;
std::shared_ptr<std::vector<uint8_t>> EBML;
SPacket(const uint64_t startTime, const uint64_t endTime, const size_t index, const std::shared_ptr<std::vector<uint8_t>>& ebml)
: startTime(startTime), endTime(endTime), index(index), EBML(ebml) { }
};
/**
* \brief generate a connection identifier.
*
* \param size Size of the connection identifier.
*
* \return A string composed of size characters in the A-Z,0-9 range
*/
static std::string generateConnectionID(const size_t size);
/**
* \brief Launch a third party program
*
* \param programPath Executable path
* \param arguments Arguments to pass to the program
*
* \retval true
* \retval false
*/
bool launchThirdPartyProgram(const std::string& programPath, const std::string& arguments);
/**
* \brief Log in NeuroRT log from third party program
*/
void log();
Communication::MessagingServer m_messaging;
size_t m_port = 0;
std::string m_connectionID;
std::string m_programPath;
bool m_isGenerator = false;
int m_extProcessId = 0;
uint64_t m_acceptTimeout = 0;
bool m_shouldLaunchProgram = false;
bool m_hasReceivedEndMessage = false;
// Synchronization timeout, and save time of last synchronization
uint64_t m_syncTimeout = 0;
uint64_t m_lastSyncTime = 0;
std::map<uint64_t, Toolkit::TStimulationDecoder<CBoxAlgorithmExternalProcessing>> m_decoders;
std::queue<SPacket> m_packetHistory;
};
class CBoxAlgorithmExternalProcessingListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmExternalProcessingDesc final : public IBoxAlgorithmDesc
{
public:
void release() override {}
CString getName() const override { return "External Processing"; }
CString getAuthorName() const override { return "Alexis Placet"; }
CString getAuthorCompanyName() const override { return "Mensia Technologies SA"; }
CString getShortDescription() const override { return "This box can communicate via TCP with an other program."; }
CString getDetailedDescription() const override
{
return "Launches an external program which can then processes data. This box and the program communicate using TCP connection and a defined protocol.";
}
CString getCategory() const override { return "Scripting"; }
CString getVersion() const override { return "1.0"; }
CString getSoftwareComponent() const override { return "openvibe-sdk"; }
CString getAddedSoftwareVersion() const override { return "1.0.0"; }
CString getUpdatedSoftwareVersion() const override { return "1.0.0"; }
CString getStockItemName() const override { return "gtk-edit"; }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_ExternalProcessing; }
IPluginObject* create() override { return new CBoxAlgorithmExternalProcessing; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmExternalProcessingListener; }
void releaseBoxListener(IBoxListener* boxListener) const override { delete boxListener; }
bool getBoxPrototype(Kernel::IBoxProto& boxAlgorithmPrototype) const override
{
boxAlgorithmPrototype.addSetting("Launch third party program", OV_TypeId_Boolean, "true"); // 0
boxAlgorithmPrototype.addSetting("Executable path", OV_TypeId_Filename, ""); // 1
boxAlgorithmPrototype.addSetting("Arguments", OV_TypeId_String, ""); // 2
boxAlgorithmPrototype.addSetting("Port", OV_TypeId_Integer, "0"); // 3
boxAlgorithmPrototype.addSetting("Automatic connection identifier", OV_TypeId_Boolean, "true"); // 4
boxAlgorithmPrototype.addSetting("Custom connection identifier", OV_TypeId_String, ""); // 5
boxAlgorithmPrototype.addSetting("Incoming connection timeout", OV_TypeId_Integer, "10"); // 6
boxAlgorithmPrototype.addSetting("Generator", OV_TypeId_Boolean, "false"); // 7
boxAlgorithmPrototype.addFlag(Kernel::BoxFlag_CanAddInput);
boxAlgorithmPrototype.addFlag(Kernel::BoxFlag_CanModifyInput);
boxAlgorithmPrototype.addFlag(Kernel::BoxFlag_CanAddOutput);
boxAlgorithmPrototype.addFlag(Kernel::BoxFlag_CanModifyOutput);
boxAlgorithmPrototype.addFlag(Kernel::BoxFlag_CanAddSetting);
boxAlgorithmPrototype.addFlag(Kernel::BoxFlag_CanModifySetting);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_ExternalProcessingDesc)
};
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,171 @@
#include "ovpCBoxAlgorithmMatrixValidityChecker.h"
#include <cmath>
namespace OpenViBE {
namespace Plugins {
namespace Tools {
bool CBoxAlgorithmMatrixValidityChecker::initialize()
{
const Kernel::IBox& boxCtx = this->getStaticBoxContext();
uint64_t logLevel = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
m_logLevel = Kernel::ELogLevel(logLevel);
m_validityCheckerType = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
if (boxCtx.getSettingCount() == 1
) { m_validityCheckerType = OVP_TypeId_ValidityCheckerType_LogWarning.id(); } // note that for boxes with one setting, we fallback to the old behavior
OV_ERROR_UNLESS_KRF(boxCtx.getSettingCount() <= 1 || boxCtx.getInputCount() == boxCtx.getOutputCount(),
"Invalid input count [" << boxCtx.getInputCount() << "] (expected same value as output count [" << boxCtx.getOutputCount() <<
"])",
Kernel::ErrorType::BadConfig);
m_decoders.resize(boxCtx.getInputCount());
m_encoders.resize(boxCtx.getInputCount());
for (size_t i = 0; i < boxCtx.getInputCount(); ++i)
{
m_decoders[i].initialize(*this, i);
m_encoders[i].initialize(*this, i);
m_encoders[i].getInputMatrix().setReferenceTarget(m_decoders[i].getOutputMatrix());
}
m_lastValidSamples.clear();
m_lastValidSamples.resize(boxCtx.getInputCount());
m_nTotalInterpolatedSample.clear();
m_nTotalInterpolatedSample.resize(boxCtx.getInputCount());
m_nTotalInterpolatedChunk.clear();
m_nTotalInterpolatedChunk.resize(boxCtx.getInputCount());
return true;
}
bool CBoxAlgorithmMatrixValidityChecker::uninitialize()
{
const size_t nInput = this->getStaticBoxContext().getInputCount();
for (size_t i = 0; i < nInput; ++i)
{
m_decoders[i].uninitialize();
m_encoders[i].uninitialize();
}
m_decoders.clear();
m_encoders.clear();
return true;
}
bool CBoxAlgorithmMatrixValidityChecker::processInput(const size_t /*index*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmMatrixValidityChecker::process()
{
Kernel::IBoxIO& boxCtx = this->getDynamicBoxContext();
const size_t nInput = this->getStaticBoxContext().getInputCount();
const size_t nSetting = this->getStaticBoxContext().getSettingCount();
for (size_t i = 0; i < nInput; ++i)
{
for (size_t j = 0; j < boxCtx.getInputChunkCount(i); ++j)
{
m_decoders[i].decode(j);
CMatrix* matrix = m_decoders[i].getOutputMatrix();
if (m_decoders[i].isHeaderReceived())
{
if (nSetting > 1) { m_encoders[i].encodeHeader(); }
if (m_validityCheckerType == OVP_TypeId_ValidityCheckerType_Interpolate.id())
{
m_nTotalInterpolatedSample[i] = 0;
m_nTotalInterpolatedChunk[i] = 0;
// for each channel, save of the last valid sample
m_lastValidSamples[i].resize(matrix->getDimensionSize(0));
}
}
if (m_decoders[i].isBufferReceived())
{
// log warning
if (m_validityCheckerType == OVP_TypeId_ValidityCheckerType_LogWarning.id())
{
if (!matrix->isBufferValid())
{
getLogManager() << m_logLevel << "Matrix on input " << i << " either contains NAN or Infinity between " <<
CTime(boxCtx.getInputChunkStartTime(i, j)) << " and " << CTime(boxCtx.getInputChunkEndTime(i, j)) << ".\n";
}
}
// stop player
else if (m_validityCheckerType == OVP_TypeId_ValidityCheckerType_StopPlayer.id())
{
if (!matrix->isBufferValid())
{
this->getPlayerContext().stop();
OV_ERROR_KRF(
"Invalid matrix content on input [" << i << "]: either contains NAN or Infinity between [" << CTime(boxCtx.
getInputChunkStartTime(i, j)) << "] and [" << CTime(boxCtx.getInputChunkEndTime(i, j)) << "]",
Kernel::ErrorType::BadInput);
}
}
// interpolate
else if (m_validityCheckerType == OVP_TypeId_ValidityCheckerType_Interpolate.id())
{
const size_t nChannel = matrix->getDimensionSize(0);
const size_t nSample = matrix->getDimensionSize(1);
double* buffer = matrix->getBuffer();
size_t nInterpolatedSample = 0;
for (size_t k = 0; k < nChannel; ++k)
{
for (size_t l = 0; l < nSample; ++l)
{
if (std::isnan(buffer[l + k * nSample]) || std::isinf(buffer[l + k * nSample]))
{
// interpolation : order 0 (easiest for online interpolation)
buffer[l + k * nSample] = m_lastValidSamples[i][k];
nInterpolatedSample++;
}
else
{
// save of the last valid sample of channel k
m_lastValidSamples[i][k] = buffer[l + k * nSample];
}
}
}
m_nTotalInterpolatedSample[i] += nInterpolatedSample;
// log management
if (nInterpolatedSample > 0 && m_nTotalInterpolatedSample[i] == nInterpolatedSample) // beginning of interpolation
{
getLogManager() << m_logLevel << "Matrix on input " << i << " either contains NAN or Infinity from " << CTime(
boxCtx.getInputChunkStartTime(i, j)) << ": interpolation is enable.\n";
}
if (nInterpolatedSample > 0) // update of ChunkCount during interpolation
{
m_nTotalInterpolatedChunk[i]++;
}
if (nInterpolatedSample == 0 && m_nTotalInterpolatedSample[i] > 0) // end of interpolation
{
getLogManager() << m_logLevel << "Matrix on input " << i << " contained " << 100.0 * m_nTotalInterpolatedSample[i] / (
m_nTotalInterpolatedChunk[i] * nSample * nChannel) << " % of NAN or Infinity. Interpolation disable from " << CTime(
boxCtx.getInputChunkStartTime(i, j)) << ".\n";
m_nTotalInterpolatedSample[i] = 0; // reset
m_nTotalInterpolatedChunk[i] = 0;
}
}
else { OV_WARNING_K("Invalid action type [" << m_validityCheckerType << "]"); }
if (nSetting > 1) { m_encoders[i].encodeBuffer(); }
}
if (m_decoders[i].isEndReceived()) { if (nSetting > 1) { m_encoders[i].encodeEnd(); } }
if (nSetting > 1) { boxCtx.markOutputAsReadyToSend(i, boxCtx.getInputChunkStartTime(i, j), boxCtx.getInputChunkEndTime(i, j)); }
}
}
return true;
}
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,128 @@
#pragma once
#include "../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace Plugins {
namespace Tools {
class CBoxAlgorithmMatrixValidityChecker final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
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_MatrixValidityChecker)
protected:
std::vector<Toolkit::TStreamedMatrixDecoder<CBoxAlgorithmMatrixValidityChecker>> m_decoders;
std::vector<Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmMatrixValidityChecker>> m_encoders;
Kernel::ELogLevel m_logLevel = Kernel::ELogLevel::LogLevel_None;
uint64_t m_validityCheckerType = 0;
std::vector<size_t> m_nTotalInterpolatedSample;
std::vector<size_t> m_nTotalInterpolatedChunk;
std::vector<std::vector<double>> m_lastValidSamples;
};
class CBoxAlgorithmMatrixValidityCheckerListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool check(Kernel::IBox& box) const
{
for (size_t i = 0; i < box.getInputCount(); ++i)
{
box.setInputName(i, ("Stream " + std::to_string(i + 1)).c_str());
box.setInputType(i, OV_TypeId_StreamedMatrix);
}
for (size_t i = 0; i < box.getOutputCount(); ++i)
{
box.setOutputName(i, ("Output stream " + std::to_string(i + 1)).c_str());
box.setInputType(i, OV_TypeId_StreamedMatrix);
}
return true;
}
bool onInputAdded(Kernel::IBox& box, const size_t index) override
{
box.setInputType(index, OV_TypeId_StreamedMatrix);
if (box.getSettingCount() > 1) { box.addOutput("", OV_TypeId_StreamedMatrix); }
this->check(box);
return true;
}
bool onInputRemoved(Kernel::IBox& box, const size_t index) override
{
box.removeOutput(index);
this->check(box);
return true;
}
bool onOutputAdded(Kernel::IBox& box, const size_t index) override
{
box.setOutputType(index, OV_TypeId_StreamedMatrix);
box.addInput("", OV_TypeId_StreamedMatrix);
this->check(box);
return true;
}
bool onOutputRemoved(Kernel::IBox& box, const size_t index) override
{
box.removeInput(index);
this->check(box);
return true;
}
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmMatrixValidityCheckerDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return "Matrix validity checker"; }
CString getAuthorName() const override { return "Yann Renard"; }
CString getAuthorCompanyName() const override { return "INRIA/IRISA"; }
CString getShortDescription() const override { return "Checks if a matrix contains \"not a number\" or \"infinity\" elements"; }
CString getDetailedDescription() const override
{
return
"This box is for debugging purposes and allows an author to check the validity of a streamed matrix and derived stream. This box can log a message, stop the player or interpolate data.";
}
CString getCategory() const override { return "Tools"; }
CString getVersion() const override { return "1.0"; }
CString getSoftwareComponent() const override { return "openvibe-sdk"; }
CString getAddedSoftwareVersion() const override { return "0.0.0"; }
CString getUpdatedSoftwareVersion() const override { return "0.0.0"; }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_MatrixValidityChecker; }
IPluginObject* create() override { return new CBoxAlgorithmMatrixValidityChecker; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmMatrixValidityCheckerListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Stream 1", OV_TypeId_StreamedMatrix);
prototype.addOutput("Output stream 1", OV_TypeId_StreamedMatrix);
prototype.addSetting("Log level", OV_TypeId_LogLevel, "Warning");
prototype.addSetting("Action to do", OVP_TypeId_ValidityCheckerType, OVP_TypeId_ValidityCheckerType_LogWarning.toString());
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
prototype.addFlag(Kernel::BoxFlag_CanAddOutput);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_MatrixValidityCheckerDesc)
};
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,80 @@
#include "ovpCBoxAlgorithmStimulationListener.h"
namespace OpenViBE {
namespace Plugins {
namespace Tools {
bool CBoxAlgorithmStimulationListener::initialize()
{
const size_t nInput = this->getStaticBoxContext().getInputCount();
for (size_t i = 0; i < nInput; ++i) { m_stimulationDecoders.push_back(new Toolkit::TStimulationDecoder<CBoxAlgorithmStimulationListener>(*this, i)); }
m_logLevel = Kernel::ELogLevel(uint64_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0)));
return true;
}
bool CBoxAlgorithmStimulationListener::uninitialize()
{
const size_t nInput = this->getStaticBoxContext().getInputCount();
for (size_t i = 0; i < nInput; ++i)
{
m_stimulationDecoders[i]->uninitialize();
delete m_stimulationDecoders[i];
}
m_stimulationDecoders.clear();
return true;
}
bool CBoxAlgorithmStimulationListener::processInput(const size_t /*index*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmStimulationListener::process()
{
const Kernel::IBox& staticboxCtx = this->getStaticBoxContext();
Kernel::IBoxIO& boxCtx = this->getDynamicBoxContext();
const size_t nInput = this->getStaticBoxContext().getInputCount();
for (size_t i = 0; i < nInput; ++i)
{
for (size_t j = 0; j < boxCtx.getInputChunkCount(i); ++j)
{
m_stimulationDecoders[i]->decode(j);
if (m_stimulationDecoders[i]->isHeaderReceived()) { }
if (m_stimulationDecoders[i]->isBufferReceived())
{
const IStimulationSet* stimSet = m_stimulationDecoders[i]->getOutputStimulationSet();
CString inputName;
staticboxCtx.getInputName(i, inputName);
for (size_t k = 0; k < stimSet->getStimulationCount(); ++k)
{
this->getLogManager() << m_logLevel
<< "For input " << i << " with name " << inputName
<< " got stimulation " << stimSet->getStimulationIdentifier(k)
<< "[" << getTypeManager().getEnumerationEntryNameFromValue(OV_TypeId_Stimulation, stimSet->getStimulationIdentifier(k)) << "]"
<< " at date " << CTime(stimSet->getStimulationDate(k))
<< " and duration " << CTime(stimSet->getStimulationDuration(k)) << "\n";
OV_WARNING_UNLESS_K(
stimSet->getStimulationDate(k) >= boxCtx.getInputChunkStartTime(i, j)
&& stimSet->getStimulationDate(k) <= boxCtx.getInputChunkEndTime(i, j),
"Invalid out of range date [" << CTime(stimSet->getStimulationDate(k)) << "] (expected value between ["
<< CTime(boxCtx.getInputChunkStartTime(i, j)) << "] and [" << CTime(boxCtx.getInputChunkEndTime(i, j)) << "])");
}
}
if (m_stimulationDecoders[i]->isEndReceived()) { }
boxCtx.markInputAsDeprecated(i, j);
}
}
return true;
}
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,84 @@
#pragma once
#include "../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <vector>
namespace OpenViBE {
namespace Plugins {
namespace Tools {
class CBoxAlgorithmStimulationListener final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
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_StimulationListener)
protected:
Kernel::ELogLevel m_logLevel = Kernel::LogLevel_None;
std::vector<Toolkit::TStimulationDecoder<CBoxAlgorithmStimulationListener>*> m_stimulationDecoders;
};
class CBoxAlgorithmStimulationListenerListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool check(Kernel::IBox& box) const
{
for (size_t i = 0; i < box.getInputCount(); ++i)
{
box.setInputName(i, ("Stimulation stream " + std::to_string(i + 1)).c_str());
box.setInputType(i, OV_TypeId_Stimulations);
}
return true;
}
bool onInputRemoved(Kernel::IBox& box, const size_t /*index*/) override { return this->check(box); }
bool onInputAdded(Kernel::IBox& box, const size_t /*index*/) override { return this->check(box); }
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmStimulationListenerDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return "Stimulation listener"; }
CString getAuthorName() const override { return "Yann Renard"; }
CString getAuthorCompanyName() const override { return "INRIA/IRISA"; }
CString getShortDescription() const override { return "Prints stimulation codes in the log manager"; }
CString getDetailedDescription() const override { return "Prints each received stimulationto the log using the log level specified in the box config."; }
CString getCategory() const override { return "Tools"; }
CString getVersion() const override { return "1.0"; }
CString getSoftwareComponent() const override { return "openvibe-sdk"; }
CString getAddedSoftwareVersion() const override { return "0.0.0"; }
CString getUpdatedSoftwareVersion() const override { return "0.0.0"; }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_StimulationListener; }
IPluginObject* create() override { return new CBoxAlgorithmStimulationListener; }
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmStimulationListenerListener; }
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Stimulation stream 1", OV_TypeId_Stimulations);
prototype.addSetting("Log level to use", OV_TypeId_LogLevel, "Information");
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_StimulationListenerDesc)
};
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,23 @@
#pragma once
// Boxes
//---------------------------------------------------------------------------------------------------
#define OVP_ClassId_BoxAlgorithm_EBMLStreamSpy OpenViBE::CIdentifier(0x0ED76695, 0x01A69CC3)
#define OVP_ClassId_BoxAlgorithm_EBMLStreamSpyDesc OpenViBE::CIdentifier(0x354A6864, 0x06BC570C)
#define OVP_ClassId_BoxAlgorithm_ExternalProcessing OpenViBE::CIdentifier(0x15422959, 0x16304449)
#define OVP_ClassId_BoxAlgorithm_ExternalProcessingDesc OpenViBE::CIdentifier(0x63386942, 0x61D42502)
#define OVP_ClassId_BoxAlgorithm_MatrixValidityChecker OpenViBE::CIdentifier(0x60210579, 0x6F7519B6)
#define OVP_ClassId_BoxAlgorithm_MatrixValidityCheckerDesc OpenViBE::CIdentifier(0x6AFC2671, 0x1D8C493C)
#define OVP_ClassId_BoxAlgorithm_StimulationListener OpenViBE::CIdentifier(0x65731E1D, 0x47DE5276)
#define OVP_ClassId_BoxAlgorithm_StimulationListenerDesc OpenViBE::CIdentifier(0x0EC013FD, 0x5DD23E44)
// Global defines
//---------------------------------------------------------------------------------------------------
#ifdef TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
#include "ovp_global_defines.h"
#endif // TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
#define OVP_TypeId_ValidityCheckerType OpenViBE::CIdentifier(0x32EA493A, 0x11E56D82)
#define OVP_TypeId_ValidityCheckerType_LogWarning OpenViBE::CIdentifier(0x747A0F84, 0x1097253A)
#define OVP_TypeId_ValidityCheckerType_StopPlayer OpenViBE::CIdentifier(0x4EC06D50, 0x5B131CE2)
#define OVP_TypeId_ValidityCheckerType_Interpolate OpenViBE::CIdentifier(0x1DE96E02, 0x53767550)
@@ -0,0 +1,27 @@
#include "ovp_defines.h"
#include "box-algorithms/ovpCBoxAlgorithmEBMLStreamSpy.h"
#include "box-algorithms/ovpCBoxAlgorithmStimulationListener.h"
#include "box-algorithms/ovpCBoxAlgorithmMatrixValidityChecker.h"
#include "box-algorithms/ovpCBoxAlgorithmExternalProcessing.h"
namespace OpenViBE {
namespace Plugins {
namespace Tools {
OVP_Declare_Begin()
// ValidityCheckerType: this type registration enables the choice between different action to do on an invalid stream
context.getTypeManager().registerEnumerationType(OVP_TypeId_ValidityCheckerType, "Action to do");
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_ValidityCheckerType, "Log warning", OVP_TypeId_ValidityCheckerType_LogWarning.id());
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_ValidityCheckerType, "Stop player", OVP_TypeId_ValidityCheckerType_StopPlayer.id());
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_ValidityCheckerType, "Interpolate", OVP_TypeId_ValidityCheckerType_Interpolate.id());
OVP_Declare_New(CBoxAlgorithmStimulationListenerDesc);
OVP_Declare_New(CBoxAlgorithmEBMLStreamSpyDesc);
OVP_Declare_New(CBoxAlgorithmMatrixValidityCheckerDesc);
OVP_Declare_New(CBoxAlgorithmExternalProcessingDesc);
OVP_Declare_End()
} // namespace Tools
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,5 @@
Time:1x1,End Time,Time signal:,Event Id,Event Date,Event Duration
0.0000000000,1.0000000000,-1.#IND000000,,,
1.0000000000,2.0000000000,-1.#IND000000,,,
2.0000000000,3.0000000000,-1.#INF000000,,,
3.0000000000,4.0000000000,0.0000000000,,,
1 Time:1x1 End Time Time signal: Event Id Event Date Event Duration
2 0.0000000000 1.0000000000 -1.#IND000000
3 1.0000000000 2.0000000000 -1.#IND000000
4 2.0000000000 3.0000000000 -1.#INF000000
5 3.0000000000 4.0000000000 0.0000000000
@@ -0,0 +1,421 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>2.2.0</CreatorVersion>
<Settings>
<Setting>
<Identifier>(0x460057cc, 0xfaa7362d)</Identifier>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Test Name</Name>
<DefaultValue>matrix-validity</DefaultValue>
<Value>matrix-validity</Value>
</Setting>
</Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x000003fa, 0x00002132)</Identifier>
<Name>Matrix validity checker</Name>
<AlgorithmClassIdentifier>(0x60210579, 0x6f7519b6)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
<Name>Stream 1</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
<Name>Output stream 1</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0xa88b3667, 0x0871638c)</TypeIdentifier>
<Name>Log level</Name>
<DefaultValue>Warning</DefaultValue>
<Value>Warning</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x32ea493a, 0x11e56d82)</TypeIdentifier>
<Name>Action to do</Name>
<DefaultValue>Log warning</DefaultValue>
<Value>Log warning</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>368</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>960</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xfa1061e7, 0x341aafb9)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>2</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00000d10, 0x00007eaa)</Identifier>
<Name>Time signal</Name>
<AlgorithmClassIdentifier>(0x28a5e7ff, 0x530095de)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Generated signal</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Sampling frequency</Name>
<DefaultValue>512</DefaultValue>
<Value>1</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Generated epoch sample count</Name>
<DefaultValue>32</DefaultValue>
<Value>1</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>256</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>960</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x9e5ca01e, 0x30a4d8c3)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00003e6a, 0x00004b24)</Identifier>
<Name>CSV File Writer</Name>
<AlgorithmClassIdentifier>(0x428375e8, 0x325f2db9)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
<Name>Input stream</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulations stream</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Filename</Name>
<DefaultValue>record-[$core{date}-$core{time}].csv</DefaultValue>
<Value>${Player_ScenarioDirectory}/$var{Test Name}-output.csv</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Precision</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Append data</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Only last matrix</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>432</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>960</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xee4b6d30, 0x788aed29)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>4</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00004679, 0x000071fa)</Identifier>
<Name>Clock stimulator</Name>
<AlgorithmClassIdentifier>(0x4f756d3f, 0x29ff0b96)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Generated stimulations</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Interstimulation interval (in sec)</Name>
<DefaultValue>1.0</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
<Name>Stimulation</Name>
<DefaultValue>OVTK_StimulationId_Label_00</DefaultValue>
<Value>OVTK_StimulationId_Label_00</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>368</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>1104</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x27b3ee3c, 0xc50527e6)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00004e4d, 0x000039e9)</Identifier>
<Name>Simple DSP</Name>
<AlgorithmClassIdentifier>(0x00e26fa1, 0x1dbab1b2)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Input - A</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Output</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Equation</Name>
<DefaultValue>x</DefaultValue>
<Value>log(x-2)</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>304</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>960</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x21889dc4, 0x1126497e)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x000058a3, 0x00004604)</Identifier>
<Name>Player Controller</Name>
<AlgorithmClassIdentifier>(0x5f426dce, 0x08456e13)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulations</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
<Name>Stimulation name</Name>
<DefaultValue>OVTK_StimulationId_Label_00</DefaultValue>
<Value>OVTK_StimulationId_Label_00</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0xcc14d8d6, 0xf27ecb73)</TypeIdentifier>
<Name>Action to perform</Name>
<DefaultValue>Pause</DefaultValue>
<Value>Stop</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>432</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>1104</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x568d148e, 0x650792b3)</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>2</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
</Attributes>
</Box>
</Boxes>
<Links>
<Link>
<Identifier>(0x00000c57, 0x00001eb3)</Identifier>
<Source>
<BoxIdentifier>(0x00004e4d, 0x000039e9)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000003fa, 0x00002132)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x0000337a, 0x0000449a)</Identifier>
<Source>
<BoxIdentifier>(0x00000d10, 0x00007eaa)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00004e4d, 0x000039e9)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x0000651e, 0x000040fc)</Identifier>
<Source>
<BoxIdentifier>(0x000003fa, 0x00002132)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00003e6a, 0x00004b24)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00007567, 0x00000d11)</Identifier>
<Source>
<BoxIdentifier>(0x00004679, 0x000071fa)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000058a3, 0x00004604)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments></Comments>
<Metadata>
<Entry>
<Identifier>(0x00003b78, 0x00006392)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":320,"identifier":"(0x000011d8, 0x00001e90)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":480},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00004896, 0x00003e2f)","index":0,"name":"Default tab","parentIdentifier":"(0x000011d8, 0x00001e90)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x000015cd, 0x00006b70)","index":0,"name":"Empty","parentIdentifier":"(0x00004896, 0x00003e2f)","type":0}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>