This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,51 @@
PROJECT(openvibe-plugins-games)
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
SET(PROJECT_VERSION ${OV_GLOBAL_VERSION_STRING})
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.hpp src/*.h src/*.inl src/*.c)
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
FOLDER ${PLUGINS_FOLDER}
COMPILE_FLAGS "-DOVP_Exports -DOVP_Shared -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE")
# ---------------------------------
INCLUDE_DIRECTORIES("src")
# OpenViBE Base
INCLUDE("FindOpenViBE")
INCLUDE("FindOpenViBECommon")
# OpenViBE Third Party
INCLUDE("FindThirdPartyBoost")
INCLUDE("FindThirdPartyBoost_System")
INCLUDE("FindThirdPartyLSL")
# ---------------------------------
# Target macros
# Defines target operating system, architecture, compiler
# ---------------------------------
SET_BUILD_PLATFORM()
#so that boost won't need to link against DateTime when using the interprocess communication library shared memory writer box
#ADD_DEFINITIONS(-DBOOST_DATE_TIME_NO_LIB)
# -----------------------------
# Install files
# -----------------------------
INSTALL(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${DIST_BINDIR}
LIBRARY DESTINATION ${DIST_LIBDIR}
ARCHIVE DESTINATION ${DIST_LIBDIR})
SET(SUB_DIR_NAME Games)
INSTALL(DIRECTORY box-tutorials/ DESTINATION ${DIST_DATADIR}/openvibe/scenarios/box-tutorials/${SUB_DIR_NAME})
# ---------------------------------
# Test applications
# ---------------------------------
#IF(OV_COMPILE_TESTS)
#ADD_SUBDIRECTORY(test)
#ENDIF()
@@ -0,0 +1,530 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>3.0.0</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x000006bc, 0x0000724a)</Identifier>
<Name>Stimulation listener</Name>
<AlgorithmClassIdentifier>(0x65731e1d, 0x47de5276)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulation stream 1</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0xa88b3667, 0x0871638c)</TypeIdentifier>
<Name>Log level to use</Name>
<DefaultValue>Information</DefaultValue>
<Value>Information</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>512</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>896</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xf451ad91, 0x14c75f86)</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>(0x000006bc, 0x0000724b)</Identifier>
<Name>Stimulation listener</Name>
<AlgorithmClassIdentifier>(0x65731e1d, 0x47de5276)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulation stream 1</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0xa88b3667, 0x0871638c)</TypeIdentifier>
<Name>Log level to use</Name>
<DefaultValue>Information</DefaultValue>
<Value>Information</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>512</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>1024</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xf451ad91, 0x14c75f86)</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>(0x00001d83, 0x00005bb9)</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.000000</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>928</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>(0x00003316, 0x000057c7)</Identifier>
<Name>Matrix Display</Name>
<AlgorithmClassIdentifier>(0x54f0796d, 0x3ede2cc0)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
<Name>Matrix</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x3d3c7c7f, 0xef0e7129)</TypeIdentifier>
<Name>Color gradient</Name>
<DefaultValue>0:2,36,58; 50:100,100,100; 100:83,17,20</DefaultValue>
<Value>0:2,36,58; 50:100,100,100; 100:83,17,20</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Steps</Name>
<DefaultValue>100</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Symetric min/max</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Real time min/max</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>512</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>784</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x4ff49bdb, 0x9dcf6788)</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>4</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00003552, 0x000054ad)</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>256</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>320</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>832</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>(0x0000629e, 0x000034f6)</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>368</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>832</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>(0x000077e6, 0x00007175)</Identifier>
<Name>Hello Bidirectionnal Game</Name>
<AlgorithmClassIdentifier>(0x47616d65, 0x42696469)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Input signal</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Input stimulations</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
<Name>Output matrix</Name>
</Output>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Output stimulations</Name>
</Output>
</Outputs>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>432</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>832</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xf916e69e, 0x8bfebe7a)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>2</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
</Boxes>
<Links>
<Link>
<Identifier>(0x000003dc, 0x000048bc)</Identifier>
<Source>
<BoxIdentifier>(0x00003552, 0x000054ad)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x0000629e, 0x000034f6)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x000016aa, 0x00005cf5)</Identifier>
<Source>
<BoxIdentifier>(0x000077e6, 0x00007175)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00003316, 0x000057c7)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00002fe9, 0x00005b2e)</Identifier>
<Source>
<BoxIdentifier>(0x00001d83, 0x00005bb9)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000006bc, 0x0000724b)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00003882, 0x00002272)</Identifier>
<Source>
<BoxIdentifier>(0x000077e6, 0x00007175)</BoxIdentifier>
<BoxOutputIndex>1</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000006bc, 0x0000724a)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00004d3e, 0x00005caa)</Identifier>
<Source>
<BoxIdentifier>(0x0000629e, 0x000034f6)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000077e6, 0x00007175)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00005a84, 0x0000720a)</Identifier>
<Source>
<BoxIdentifier>(0x00001d83, 0x00005bb9)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000077e6, 0x00007175)</BoxIdentifier>
<BoxInputIndex>1</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x00000a8d, 0x000047b4)</Identifier>
<Text>&lt;b&gt;Remarques : &lt;/b&gt; :
Le Jeu doit être lancé en premier
pour eviter des retards dans OpenViBE du fait de la recherche de canaux LSL.
Unity gère mieux la recherche continue de canaux LSL.
&lt;b&gt; Remarks: &lt;/b&gt;:
The Game must be launched first
to avoid delays in OpenViBE due to LSL channel search.
Unity better manages the continuous search for LSL channels. </Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>512</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>416</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x00006a65, 0x00005977)</Identifier>
<Text>Signal = Sin(time)
Game is available in the Repository : https://gitlab.inria.fr/openvibe/unity-games/hello-bidirectionnal</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>832</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>272</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x00003414, 0x00007f3b)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":320,"identifier":"(0x00000cf5, 0x00000b02)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":480},{"boxIdentifier":"(0x00003316, 0x000057c7)","childCount":0,"identifier":"(0x00001b1d, 0x00004d15)","parentIdentifier":"(0xffffffff, 0xffffffff)","type":3},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00003657, 0x00003658)","index":0,"name":"Default tab","parentIdentifier":"(0x00000cf5, 0x00000b02)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x000018fe, 0x00004f01)","index":0,"name":"Empty","parentIdentifier":"(0x00003657, 0x00003658)","type":0}]</Data>
</Entry>
</Metadata>
<Attributes>
<Attribute>
<Identifier>(0x079d1f09, 0x667c7871)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x60bc58ab, 0x7a1b4d83)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x790d75b8, 0x3bb90c33)</Identifier>
<Value>Thibaut Monseigne</Value>
</Attribute>
<Attribute>
<Identifier>(0x7a3a1558, 0xf12c63c2)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x84009d7c, 0x3c4e763b)</Identifier>
<Value>Light scenario that works with Hello World game</Value>
</Attribute>
<Attribute>
<Identifier>(0x8c1fc55b, 0x7b433dc2)</Identifier>
<Value>1.0</Value>
</Attribute>
<Attribute>
<Identifier>(0x9f5c4075, 0x4a0d3666)</Identifier>
<Value>Hello World Game</Value>
</Attribute>
<Attribute>
<Identifier>(0xf36a1567, 0xd13c53da)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xf6b2e3fa, 0x7bd43926)</Identifier>
<Value>Games</Value>
</Attribute>
<Attribute>
<Identifier>(0xf8034a49, 0x8b3f37cc)</Identifier>
<Value>Inria</Value>
</Attribute>
</Attributes>
</OpenViBE-Scenario>
@@ -0,0 +1,220 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>2.2.0</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x00000050, 0x00007f60)</Identifier>
<Name>Hello Sender Game</Name>
<AlgorithmClassIdentifier>(0x4cbf4237, 0x24f54a7c)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
<Name>Output matrix</Name>
</Output>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Output stimulations</Name>
</Output>
</Outputs>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>240</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>752</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xcdc02a11, 0x9a816677)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00002498, 0x000035c7)</Identifier>
<Name>Matrix Display</Name>
<AlgorithmClassIdentifier>(0x54f0796d, 0x3ede2cc0)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
<Name>Matrix</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x3d3c7c7f, 0xef0e7129)</TypeIdentifier>
<Name>Color gradient</Name>
<DefaultValue>0:2,36,58; 50:100,100,100; 100:83,17,20</DefaultValue>
<Value>0:2,36,58; 50:100,100,100; 100:83,17,20</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Steps</Name>
<DefaultValue>100</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Symetric min/max</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Real time min/max</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>336</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>688</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x4ff49bdb, 0x9dcf6788)</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>4</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x000066c9, 0x00005cd9)</Identifier>
<Name>Stimulation listener</Name>
<AlgorithmClassIdentifier>(0x65731e1d, 0x47de5276)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulation stream 1</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0xa88b3667, 0x0871638c)</TypeIdentifier>
<Name>Log level to use</Name>
<DefaultValue>Information</DefaultValue>
<Value>Information</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>336</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>800</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xf451ad91, 0x14c75f86)</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>
</Boxes>
<Links>
<Link>
<Identifier>(0x000070d3, 0x000045e2)</Identifier>
<Source>
<BoxIdentifier>(0x00000050, 0x00007f60)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00002498, 0x000035c7)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00007ec0, 0x000065a9)</Identifier>
<Source>
<BoxIdentifier>(0x00000050, 0x00007f60)</BoxIdentifier>
<BoxOutputIndex>1</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000066c9, 0x00005cd9)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x00000a8d, 0x000047b4)</Identifier>
<Text>&lt;b&gt;Remarks&lt;/b&gt; :
It is currently impossible to send and receive information by LSL in the same scenario.
Indeed, the LSL library waits to receive its flow (or gives up) before moving on.
In addition, OpenViBE is not multi-process.
It blocks until it has received its flow (or gives up).
It is therefore advisable to launch the transmitter before the receive
or plan for a shorter but repeated stream search after launch in the event of a startup failure.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>1152</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>288</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x00006a65, 0x00005977)</Identifier>
<Text>Game is available in the Repository : https://gitlab.inria.fr/openvibe/unity-games/hello-sender
Run the Game before the Script</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>768</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>176</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x00003414, 0x00007f3b)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":320,"identifier":"(0x00000cf5, 0x00000b02)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":480},{"boxIdentifier":"(0x00002498, 0x000035c7)","childCount":0,"identifier":"(0x00005d08, 0x00001914)","parentIdentifier":"(0xffffffff, 0xffffffff)","type":3},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00003657, 0x00003658)","index":0,"name":"Default tab","parentIdentifier":"(0x00000cf5, 0x00000b02)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x000018fe, 0x00004f01)","index":0,"name":"Empty","parentIdentifier":"(0x00003657, 0x00003658)","type":0}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>
@@ -0,0 +1,326 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>2.2.0</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x00001d83, 0x00005bb9)</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.000000</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>928</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>(0x000029cc, 0x00007eba)</Identifier>
<Name>Hello World Game</Name>
<AlgorithmClassIdentifier>(0x46705bc3, 0x3058a939)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Input signal</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Input stimulations</Name>
</Input>
</Inputs>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>432</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>832</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xcb293370, 0xee8027f2)</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>2</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00003552, 0x000054ad)</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>256</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>320</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>832</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>(0x0000629e, 0x000034f6)</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>368</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>832</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>
</Boxes>
<Links>
<Link>
<Identifier>(0x000003dc, 0x000048bc)</Identifier>
<Source>
<BoxIdentifier>(0x00003552, 0x000054ad)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x0000629e, 0x000034f6)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00000e9b, 0x00001c1a)</Identifier>
<Source>
<BoxIdentifier>(0x0000629e, 0x000034f6)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000029cc, 0x00007eba)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x000031d4, 0x00003e9b)</Identifier>
<Source>
<BoxIdentifier>(0x00001d83, 0x00005bb9)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000029cc, 0x00007eba)</BoxIdentifier>
<BoxInputIndex>1</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x00000a8d, 0x000047b4)</Identifier>
<Text>&lt;b&gt;Remarks&lt;/b&gt; :
It is currently impossible to send and receive information by LSL in the same scenario.
Indeed, the LSL library waits to receive its flow (or gives up) before moving on.
In addition, OpenViBE is not multi-process.
It blocks until it has received its flow (or gives up).
It is therefore advisable to launch the transmitter before the receiver.
Or plan for a shorter but repeated stream search after launch in the event of a startup failure.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>496</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>384</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x00006a65, 0x00005977)</Identifier>
<Text>Signal = Sin(time)
Game is available in the Repository : https://gitlab.inria.fr/openvibe/unity-games/hello-world</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>832</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>272</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x00003414, 0x00007f3b)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":320,"identifier":"(0x00000cf5, 0x00000b02)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":480},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00003657, 0x00003658)","index":0,"name":"Default tab","parentIdentifier":"(0x00000cf5, 0x00000b02)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x000018fe, 0x00004f01)","index":0,"name":"Empty","parentIdentifier":"(0x00003657, 0x00003658)","type":0}]</Data>
</Entry>
</Metadata>
<Attributes>
<Attribute>
<Identifier>(0x079d1f09, 0x667c7871)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x60bc58ab, 0x7a1b4d83)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x790d75b8, 0x3bb90c33)</Identifier>
<Value>Thibaut Monseigne</Value>
</Attribute>
<Attribute>
<Identifier>(0x7a3a1558, 0xf12c63c2)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x84009d7c, 0x3c4e763b)</Identifier>
<Value>Light scenario that works with Hello World game</Value>
</Attribute>
<Attribute>
<Identifier>(0x8c1fc55b, 0x7b433dc2)</Identifier>
<Value>1.0</Value>
</Attribute>
<Attribute>
<Identifier>(0x9f5c4075, 0x4a0d3666)</Identifier>
<Value>Hello World Game</Value>
</Attribute>
<Attribute>
<Identifier>(0xf36a1567, 0xd13c53da)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xf6b2e3fa, 0x7bd43926)</Identifier>
<Value>Games</Value>
</Attribute>
<Attribute>
<Identifier>(0xf8034a49, 0x8b3f37cc)</Identifier>
<Value>Inria</Value>
</Attribute>
</Attributes>
</OpenViBE-Scenario>
@@ -0,0 +1,76 @@
/**
* \page BoxAlgorithm_HelloBidirectionnalGames Hello Bidirectionnal Games
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloBidirectionnalGames_Description|
This box forwards the signals and stimulations it gets to two corresponding LabStreamingLayer (LSL) streams and receive back The size of cube in game and a Beep Stimulation from the Unity Game.
This stream can be read by the Unity Games Hello Bidirectionnal here : https://gitlab.inria.fr/openvibe/unity-games/hello-bidirectionnal
Remarks : It is recommanded to run the Unity App Before to avoid "too big" lag in OpenViBE with continuous search of stream. Unity can support that easily.
* |OVP_DocEnd_BoxAlgorithm_HelloBidirectionnalGames_Description|
__________________________________________________________________
Inputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloBidirectionnalGames_Inputs|
* |OVP_DocEnd_BoxAlgorithm_HelloBidirectionnalGames_Inputs|
*
* |OVP_DocBegin_BoxAlgorithm_HelloBidirectionnalGames_Input1|
The signal input stream.
* |OVP_DocEnd_BoxAlgorithm_HelloBidirectionnalGames_Input1|
* |OVP_DocBegin_BoxAlgorithm_HelloBidirectionnalGames_Input2|
The stimulation input stream.
* |OVP_DocEnd_BoxAlgorithm_HelloBidirectionnalGames_Input2|
__________________________________________________________________
Outputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Outputs|
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Outputs|
*
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Output1|
The size of the Cube in Unity App.
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Output1|
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Output2|
The Beep stimulation from the Unity App.
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Output2|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloBidirectionnalGames_Settings|
* |OVP_DocEnd_BoxAlgorithm_HelloBidirectionnalGames_Settings|
*
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloBidirectionnalGames_Examples|
Easiest way to test the box is to use a time signal box with a simple DSP sin(x) and a Clock Stimulation with stimulation `OVTK_StimulationId_Label_00` for inputs and just a display matrix and a stimulation listener for output.
Run the Game, next run the Scenario.
* |OVP_DocEnd_BoxAlgorithm_HelloBidirectionnalGames_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloBidirectionnalGames_Miscellaneous|
The box creates each LSL stream at the beginning of the playback, after it has received its corresponding OpenViBE stream header information. Hence, if either signal or stimulus socket
of the box is not connected or does not receive a header, the box will not create the corresponding LSL stream.
The reception LSL streams are searched during each process to create inlet when stream are available.
Stream formats: The signal stream is continuous float. The stimulation stream is noncontinuous int, and each 64bit OpenViBE stimulation is truncated to an int marker.
* |OVP_DocEnd_BoxAlgorithm_HelloBidirectionnalGames_Miscellaneous|
*/
@@ -0,0 +1,62 @@
/**
* \page BoxAlgorithm_HelloSenderGames Hello Sender Games
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Description|
This box receives the signals and stimulations it gets from two corresponding LabStreamingLayer (LSL) streams.
These streams can be read by the Unity Games Hello Sender here : https://gitlab.inria.fr/openvibe/unity-games/hello-sender
Remarks : It is currently impossible to send and receive information by LSL in the same scenario.
Indeed, the LSL library waits to receive its flow (or gives up) before moving on. In addition, OpenViBE is not multi-process.
It blocks until it has received its flow (or gives up).
It is therefore advisable to launch the transmitter before the receiver or plan for a shorter but repeated stream search after launch in the event of a startup failure.
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Description|
__________________________________________________________________
Outputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Outputs|
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Outputs|
*
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Output1|
The matrix output stream.
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Output1|
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Output2|
The stimulation output stream.
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Output2|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Settings|
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Settings|
*
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Examples|
Run the Game, next run the Scenario.
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloSenderGames_Miscellaneous|
The box creates each LSL stream at the beginning of the playback, the Process is stopped until available stream are found.
Stream formats: The matrix stream is noncontinuous float. The stimulation stream is noncontinuous int.
* |OVP_DocEnd_BoxAlgorithm_HelloSenderGames_Miscellaneous|
*/
@@ -0,0 +1,64 @@
/**
* \page BoxAlgorithm_HelloWorldGames Hello World Games
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloWorldGames_Description|
This box forwards the signals and stimulations it gets to two corresponding LabStreamingLayer (LSL) streams.
This stream can be read by the Unity Games Hello World here : https://gitlab.inria.fr/openvibe/unity-games/hello-world
Remarks : It is currently impossible to send and receive information by LSL in the same scenario.
Indeed, the LSL library waits to receive its flow (or gives up) before moving on. In addition, OpenViBE is not multi-process.
It blocks until it has received its flow (or gives up).
It is therefore advisable to launch the transmitter before the receiver.
Or plan for a shorter but repeated stream search after launch in the event of a startup failure.
* |OVP_DocEnd_BoxAlgorithm_HelloWorldGames_Description|
__________________________________________________________________
Inputs description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloWorldGames_Inputs|
* |OVP_DocEnd_BoxAlgorithm_HelloWorldGames_Inputs|
*
* |OVP_DocBegin_BoxAlgorithm_HelloWorldGames_Input1|
The signal input stream.
* |OVP_DocEnd_BoxAlgorithm_HelloWorldGames_Input1|
* |OVP_DocBegin_BoxAlgorithm_HelloWorldGames_Input2|
The stimulation input stream.
* |OVP_DocEnd_BoxAlgorithm_HelloWorldGames_Input2|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloWorldGames_Settings|
* |OVP_DocEnd_BoxAlgorithm_HelloWorldGames_Settings|
*
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloWorldGames_Examples|
Easiest way to test the box is to use a time signal box with a simple DSP sin(x) and a Clock Stimulation with stimulation `OVTK_StimulationId_Label_00`. Run the Scenario, next run the Game.
* |OVP_DocEnd_BoxAlgorithm_HelloWorldGames_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_HelloWorldGames_Miscellaneous|
The box creates each LSL stream at the beginning of the playback, after it has received its corresponding OpenViBE stream header information. Hence, if either signal or stimulus socket
of the box is not connected or does not receive a header, the box will not create the corresponding LSL stream.
Stream formats: The signal stream is continuous float. The stimulation stream is noncontinuous int, and each 64bit OpenViBE stimulation is truncated to an int marker.
* |OVP_DocEnd_BoxAlgorithm_HelloWorldGames_Miscellaneous|
*/
@@ -0,0 +1,232 @@
#ifdef TARGET_HAS_ThirdPartyLSL
#include "CBoxAlgorithmHelloBidirectionnalGame.hpp"
#include "utils.hpp"
#include <ctime>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace Games {
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloBidirectionnalGame::initialize()
{
//---------- Initialize Input/Output ----------
m_signalDecoder.initialize(*this, 0);
m_stimDecoder.initialize(*this, 1);
m_iMatrix = m_signalDecoder.getOutputMatrix();
m_iStimSet = m_stimDecoder.getOutputStimulationSet();
m_signalEncoder.initialize(*this, 0);
m_stimEncoder.initialize(*this, 1);
m_oMatrix = m_signalEncoder.getInputMatrix();
m_oStimSet = m_stimEncoder.getInputStimulationSet();
//---------- Initialize LSL Stream (to Unity) ----------
// These are supposed to be unique, so we don't have them in the box config
m_outSignalID = CIdentifier::random().str();
m_outMarkerID = CIdentifier::random().str();
while (m_outMarkerID == m_outSignalID) { m_outMarkerID = CIdentifier::random().str(); } // very unlikely
this->getLogManager() << Kernel::LogLevel_Trace << "We Will create signal stream [" << m_outSignalName << ", id " << m_outSignalID
<< "] and stimulation stream [" << m_outMarkerName << ", id " << m_outMarkerID << "]\n";
//---------- Create Headers for Output ----------
// Matrix Header
m_oMatrix->resize(1, 1);
m_signalEncoder.encodeHeader();
// Stimulation Header
m_oStimSet->setStimulationCount(0); // reset stimulation output
m_stimEncoder.encodeHeader();
Kernel::IBoxIO& boxCtx = this->getDynamicBoxContext();
boxCtx.markOutputAsReadyToSend(0, m_lastMatrixTime, m_lastMatrixTime); // Makes the output available
boxCtx.markOutputAsReadyToSend(1, m_lastStimTime, m_lastStimTime); // Makes the output available
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloBidirectionnalGame::uninitialize()
{
//---------- Uninitialize Input/Output ----------
m_signalDecoder.uninitialize();
m_stimDecoder.uninitialize();
m_signalEncoder.uninitialize();
m_stimEncoder.uninitialize();
//---------- Delete LSL Stream Inlet/Outlet ----------
if (m_signalOutlet)
{
delete m_signalOutlet;
m_signalOutlet = nullptr;
}
if (m_stimOutlet)
{
delete m_stimOutlet;
m_stimOutlet = nullptr;
}
if (m_signalInlet)
{
m_signalInlet->close_stream();
delete m_signalInlet;
m_signalInlet = nullptr;
}
if (m_stimInlet)
{
m_stimInlet->close_stream();
delete m_stimInlet;
m_stimInlet = nullptr;
}
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloBidirectionnalGame::processInput(const size_t /*index*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloBidirectionnalGame::process()
{
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
const uint64_t currentTime = getPlayerContext().getCurrentTime();
//---------- Emission Part ----------
// Process signals
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
{
m_signalDecoder.decode(i);
if (m_signalDecoder.isHeaderReceived() && !m_signalOutlet)
{
const size_t samplesPerBlock = m_signalDecoder.getOutputMatrix()->getDimensionSize(1);
const size_t frequency = m_signalDecoder.getOutputSamplingRate();
lsl::stream_info signalInfo = createSignalStreamInfo(m_outSignalName, m_outSignalID, m_signalDecoder.getOutputMatrix(), frequency);
// make a new outlet
try { m_signalOutlet = new lsl::stream_outlet(signalInfo, int(samplesPerBlock)); }
catch (...)
{
this->getLogManager() << "Unable to create signal outlet\n";
return false;
}
}
if (m_signalDecoder.isBufferReceived())
{
sendSignal(m_signalOutlet, m_iMatrix, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
}
//if (m_signalDecoder.isEndReceived()) { }
}
// Process stimuli -> LSL markers.
// Note that stimuli with identifiers not fitting to int will be mangled by a static cast.
for (size_t i = 0; i < boxContext.getInputChunkCount(1); ++i)
{
m_stimDecoder.decode(i);
if (m_stimDecoder.isHeaderReceived() && !m_stimOutlet)
{
// Open a stimulus stream
lsl::stream_info info = createStimulationStreamInfo(m_outMarkerName, m_outMarkerID);
try { m_stimOutlet = new lsl::stream_outlet(info); }
catch (...)
{
this->getLogManager() << "Unable to create marker outlet\n";
return false;
}
}
if (m_stimDecoder.isBufferReceived()) { sendStimulation(m_stimOutlet, m_iStimSet); }
//if (m_stimDecoder.isEndReceived()) { }
}
//---------- Reception Part ----------
if (!m_signalInlet) // We don't have a signal inlet
{
const lsl::stream_info signalInfo = findStreamInfo(m_inSignalName, "", 0); // timeout of 0 to avoid blocking OpenViBE
if (signalInfo.name() == m_inSignalName)
{
m_signalInlet = new lsl::stream_inlet(signalInfo);
try { m_signalInlet->open_stream(); }
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open signal stream with name [" << signalInfo.name() << "]\n";
return false;
}
this->getLogManager() << Kernel::LogLevel_Trace << "We have open stream [" << signalInfo.name() << "]\n";
}
}
if (m_signalInlet) // We have a signal inlet
{
double time;
// Signal
try { time = m_signalInlet->pull_sample(&m_bufferLSL, 1, 0.0); } // 2 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get signal sample\n";
return false;
}
if (std::abs(time) > 0.0)
{
m_oMatrix->getBuffer()[0] = double(m_bufferLSL);
m_signalEncoder.encodeBuffer(); // Buffer encoded
boxContext.markOutputAsReadyToSend(0, m_lastMatrixTime, currentTime); // Makes the output available
m_lastMatrixTime = currentTime;
}
}
if (!m_stimInlet) // We haven't a stimulation inlet
{
const lsl::stream_info stimInfo = findStreamInfo(m_inMarkerName, "", 0); // timeout of 0 to avoid blocking OpenViBE
if (stimInfo.name() == m_inMarkerName)
{
m_stimInlet = new lsl::stream_inlet(stimInfo);
try { m_stimInlet->open_stream(); }
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open marker stream with name [" << stimInfo.name() << "]\n";
return false;
}
this->getLogManager() << Kernel::LogLevel_Trace << "We have open stream [" << stimInfo.name() << "]\n";
}
}
if (m_stimInlet) // We have a stimulation inlet
{
double time;
try { time = m_stimInlet->pull_sample(&m_bufferLSL, 1, 0.0); } // 1 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get stimulation sample\n";
return false;
}
if (std::abs(time) > 0.0)
{
m_oStimSet->setStimulationCount(0); // reset stimulation output
m_oStimSet->appendStimulation(uint64_t(m_bufferLSL), currentTime, 0);
m_stimEncoder.encodeBuffer(); // Buffer encoded
boxContext.markOutputAsReadyToSend(1, m_lastStimTime, currentTime); // Makes the output available
m_lastStimTime = currentTime;
this->getLogManager() << Kernel::LogLevel_Info << "Stim received with time " << time << "s in the unity app\n";
}
}
return true;
}
} // namespace Games
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyLSL
@@ -0,0 +1,108 @@
///-------------------------------------------------------------------------------------------------
///
/// \file CBoxAlgorithmHelloBidirectionnalGame.hpp
/// \brief Class of the box that communicates with Hello Bidirectionnal Game.
/// \author Thibaut Monseigne (Inria).
/// \version 1.0.
/// \date 24/02/2021
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
///
///-------------------------------------------------------------------------------------------------
#pragma once
#ifdef TARGET_HAS_ThirdPartyLSL
#include "defines.hpp"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <lsl_cpp.h>
#include <ctime>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace Games {
/// <summary> The class CBoxAlgorithmHelloBidirectionnalGame describes the box that sends value in LSL. </summary>
class CBoxAlgorithmHelloBidirectionnalGame 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>, Game_Box_Hello_Bidirectionnal)
protected:
// Encoder / Decoder
Toolkit::TStimulationDecoder<CBoxAlgorithmHelloBidirectionnalGame> m_stimDecoder;
Toolkit::TSignalDecoder<CBoxAlgorithmHelloBidirectionnalGame> m_signalDecoder;
Toolkit::TStimulationEncoder<CBoxAlgorithmHelloBidirectionnalGame> m_stimEncoder;
Toolkit::TSignalEncoder<CBoxAlgorithmHelloBidirectionnalGame> m_signalEncoder;
// Input/ Output
CMatrix *m_iMatrix = nullptr, *m_oMatrix = nullptr;
IStimulationSet *m_iStimSet = nullptr, *m_oStimSet = nullptr;
uint64_t m_lastMatrixTime = 0, m_lastStimTime = 0;
// LSL Stream
lsl::stream_outlet *m_signalOutlet = nullptr, *m_stimOutlet = nullptr;
lsl::stream_inlet *m_signalInlet = nullptr, *m_stimInlet = nullptr;
const std::string m_outSignalName = "ovOutSignal", m_outMarkerName = "ovOutMarkers";
const std::string m_inSignalName = "ovInSignal", m_inMarkerName = "ovInMarkers";
std::string m_outSignalID, m_outMarkerID;
float m_bufferLSL = 0.0;
};
/// <summary> Descriptor of the box Hello Bidirectionnal Game. </summary>
class CBoxAlgorithmHelloBidirectionnalGameDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return "Hello Bidirectionnal Game"; }
CString getAuthorName() const override { return "Thibaut Monseigne"; }
CString getAuthorCompanyName() const override { return "Inria"; }
CString getShortDescription() const override
{
return "Send input stream via LabStreamingLayer (LSL) to the unity game Hello Bidirectionnal and receive back matrix and stimulation.";
}
CString getDetailedDescription() const override
{
return "The Unity Game is in the OpenViBE Unity Game Set of Repository (https://gitlab.inria.fr/openvibe/unity-games/hello-bidirectionnal).\n";
}
CString getCategory() const override { return "Games"; }
CString getVersion() const override { return "0.1"; }
CString getStockItemName() const override { return "gtk-connect"; }
CIdentifier getCreatedClass() const override { return Game_Box_Hello_Bidirectionnal; }
IPluginObject* create() override { return new CBoxAlgorithmHelloBidirectionnalGame; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Input signal", OV_TypeId_Signal);
prototype.addInput("Input stimulations", OV_TypeId_Stimulations);
prototype.addOutput("Output matrix", OV_TypeId_StreamedMatrix);
prototype.addOutput("Output stimulations", OV_TypeId_Stimulations);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, Game_Box_Hello_Bidirectionnal_Desc)
};
} // namespace Games
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyLSL
@@ -0,0 +1,173 @@
#ifdef TARGET_HAS_ThirdPartyLSL
#include "CBoxAlgorithmHelloSenderGame.hpp"
#include "utils.hpp"
#include <ctime>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace Games {
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloSenderGame::initialize()
{
m_signalInlet = nullptr;
m_stimInlet = nullptr;
m_signalEncoder.initialize(*this, 0);
m_stimEncoder.initialize(*this, 1);
m_oMatrix = m_signalEncoder.getInputMatrix();
m_oStimSet = m_stimEncoder.getInputStimulationSet();
// Signal Stream
const lsl::stream_info signalInfo = findStreamInfo(m_signalName);
if (signalInfo.name() != m_signalName)
{
this->getLogManager() << Kernel::LogLevel_Error << "Error getting signal stream info for [" << signalInfo.name() << "]\n";
return false;
}
m_signalInlet = new lsl::stream_inlet(signalInfo);
if (!m_signalInlet)
{
this->getLogManager() << Kernel::LogLevel_Error << "Error getting signal inlet for [" << signalInfo.name() << "]\n";
return false;
}
try { m_signalInlet->open_stream(); }
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open signal stream with name [" << signalInfo.name() << "]\n";
return false;
}
// Stimulation Stream
const lsl::stream_info stimInfo = findStreamInfo(m_markerName);
if (stimInfo.name() != m_markerName)
{
this->getLogManager() << Kernel::LogLevel_Error << "Error getting marker stream info for [" << stimInfo.name() << "]\n";
return false;
}
m_stimInlet = new lsl::stream_inlet(stimInfo);
if (!m_stimInlet)
{
this->getLogManager() << Kernel::LogLevel_Error << "Error getting marker inlet for [" << stimInfo.name() << "]\n";
return false;
}
try { m_stimInlet->open_stream(); }
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open marker stream with name [" << stimInfo.name() << "]\n";
return false;
}
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloSenderGame::uninitialize()
{
m_signalEncoder.uninitialize();
m_stimEncoder.uninitialize();
if (m_signalInlet)
{
m_signalInlet->close_stream();
delete m_signalInlet;
m_signalInlet = nullptr;
}
if (m_stimInlet)
{
m_stimInlet->close_stream();
delete m_stimInlet;
m_stimInlet = nullptr;
}
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloSenderGame::processClock(Kernel::CMessageClock& /*msg*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloSenderGame::process()
{
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
const uint64_t currentTime = getPlayerContext().getCurrentTime();
// Header
if (!m_headerSent)
{
m_buffer = new float[2];
// Matrix Header
m_oMatrix->resize(2, 1);
m_signalEncoder.encodeHeader();
// Stimulation Header
m_oStimSet->setStimulationCount(0); // reset stimulation output
m_stimEncoder.encodeHeader();
boxContext.markOutputAsReadyToSend(0, m_lastMatrixTime, m_lastMatrixTime); // Makes the output available
boxContext.markOutputAsReadyToSend(1, m_lastStimTime, m_lastStimTime); // Makes the output available
m_headerSent = true;
this->getLogManager() << Kernel::LogLevel_Info << "Header created\n";
}
// Core
double time;
// Signal
try { time = m_signalInlet->pull_sample(m_buffer, 2, 0.0); } // 2 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get signal sample\n";
return false;
}
if (std::abs(time) > 0.0)
{
double* buffer = m_oMatrix->getBuffer();
buffer[0] = double(m_buffer[0]);
buffer[1] = double(m_buffer[1]);
m_signalEncoder.encodeBuffer(); // Buffer encoded
boxContext.markOutputAsReadyToSend(0, m_lastMatrixTime, currentTime); // Makes the output available
m_lastMatrixTime = currentTime;
}
// Stimulation
try { time = m_stimInlet->pull_sample(m_buffer, 1, 0.0); } // 1 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
catch (...)
{
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get stimulation sample\n";
return false;
}
if (std::abs(time) > 0.0)
{
m_oStimSet->setStimulationCount(0); // reset stimulation output
m_oStimSet->appendStimulation(uint64_t(m_buffer[0]), currentTime, 0);
m_stimEncoder.encodeBuffer(); // Buffer encoded
boxContext.markOutputAsReadyToSend(1, m_lastStimTime, currentTime); // Makes the output available
m_lastStimTime = currentTime;
}
return true;
}
//--------------------------------------------------------------------------------
} // namespace Games
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyLSL
@@ -0,0 +1,99 @@
///-------------------------------------------------------------------------------------------------
///
/// \file CBoxAlgorithmHelloSenderGame.hpp
/// \brief Class of the box that communicate with Hello Sender Game.
/// \author Thibaut Monseigne (Inria).
/// \version 1.0.
/// \date 12/03/2020.
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
///
///-------------------------------------------------------------------------------------------------
#pragma once
#ifdef TARGET_HAS_ThirdPartyLSL
#include "defines.hpp"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <lsl_cpp.h>
#include <ctime>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace Games {
/// <summary> The class CBoxAlgorithmHelloSenderGame describes the box that send value in LSL. </summary>
class CBoxAlgorithmHelloSenderGame final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
void release() override { delete this; }
uint64_t getClockFrequency() override { return 64LL << 32; }
bool initialize() override;
bool uninitialize() override;
bool processClock(Kernel::CMessageClock& msg) override;
bool process() override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, Game_Box_Hello_Sender)
protected:
// Decoders
Toolkit::TStimulationEncoder<CBoxAlgorithmHelloSenderGame> m_stimEncoder;
Toolkit::TSignalEncoder<CBoxAlgorithmHelloSenderGame> m_signalEncoder;
CMatrix* m_oMatrix = nullptr;
IStimulationSet* m_oStimSet = nullptr;
float* m_buffer = nullptr;
bool m_headerSent = false;
uint64_t m_lastMatrixTime = 0;
uint64_t m_lastStimTime = 0;
lsl::stream_inlet *m_signalInlet = nullptr, *m_stimInlet = nullptr;
const std::string m_signalName = "ovSignal", m_markerName = "ovMarker";
};
/// <summary> Descriptor of the box Hello Sender Game. </summary>
class CBoxAlgorithmHelloSenderGameDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return "Hello Sender Game"; }
CString getAuthorName() const override { return "Thibaut Monseigne"; }
CString getAuthorCompanyName() const override { return "Inria"; }
CString getShortDescription() const override { return "Receive stream via LabStreamingLayer (LSL) from the unity game Hello Sender."; }
CString getDetailedDescription() const override
{
return "The Unity Game is in the OpenViBE Unity Game Set of Repository (https://gitlab.inria.fr/openvibe/unity-games/hello-sender).\n";
}
CString getCategory() const override { return "Games"; }
CString getVersion() const override { return "0.1"; }
CString getStockItemName() const override { return "gtk-connect"; }
CIdentifier getCreatedClass() const override { return Game_Box_Hello_Sender; }
IPluginObject* create() override { return new CBoxAlgorithmHelloSenderGame; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addOutput("Output matrix", OV_TypeId_StreamedMatrix);
prototype.addOutput("Output stimulations", OV_TypeId_Stimulations);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, Game_Box_Hello_Sender_Desc)
};
} // namespace Games
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyLSL
@@ -0,0 +1,124 @@
#ifdef TARGET_HAS_ThirdPartyLSL
#include "CBoxAlgorithmHelloWorldGame.hpp"
#include "utils.hpp"
#include <ctime>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace Games {
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloWorldGame::initialize()
{
m_signalOutlet = nullptr;
m_stimOutlet = nullptr;
m_signalDecoder.initialize(*this, 0);
m_stimDecoder.initialize(*this, 1);
m_iMatrix = m_signalDecoder.getOutputMatrix();
m_iStimSet = m_stimDecoder.getOutputStimulationSet();
// These are supposed to be unique, so we don't have them in the box config
m_signalID = CIdentifier::random().str();
m_markerID = CIdentifier::random().str();
while (m_markerID == m_signalID) { m_markerID = CIdentifier::random().str(); } // very unlikely
this->getLogManager() << Kernel::LogLevel_Trace << "We Will create streams [" << m_signalName << ", id " << m_signalID
<< "] and [" << m_markerName << ", id " << m_markerID << "]\n";
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloWorldGame::uninitialize()
{
m_signalDecoder.uninitialize();
m_stimDecoder.uninitialize();
if (m_signalOutlet)
{
delete m_signalOutlet;
m_signalOutlet = nullptr;
}
if (m_stimOutlet)
{
delete m_stimOutlet;
m_stimOutlet = nullptr;
}
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloWorldGame::processInput(const size_t /*index*/)
{
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
bool CBoxAlgorithmHelloWorldGame::process()
{
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
// Process signals
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
{
m_signalDecoder.decode(i);
if (m_signalDecoder.isHeaderReceived() && !m_signalOutlet)
{
const size_t samplesPerBlock = m_signalDecoder.getOutputMatrix()->getDimensionSize(1);
const size_t frequency = m_signalDecoder.getOutputSamplingRate();
lsl::stream_info signalInfo = createSignalStreamInfo(m_signalName, m_signalID, m_signalDecoder.getOutputMatrix(), frequency);
// make a new outlet
try { m_signalOutlet = new lsl::stream_outlet(signalInfo, int(samplesPerBlock)); }
catch (...)
{
this->getLogManager() << "Unable to create signal outlet\n";
return false;
}
}
if (m_signalDecoder.isBufferReceived())
{
sendSignal(m_signalOutlet, m_iMatrix, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
}
//if (m_signalDecoder.isEndReceived()) { }
}
// Process stimuli -> LSL markers.
// Note that stimuli with identifiers not fitting to int will be mangled by a static cast.
for (size_t i = 0; i < boxContext.getInputChunkCount(1); ++i)
{
m_stimDecoder.decode(i);
if (m_stimDecoder.isHeaderReceived() && !m_stimOutlet)
{
// Open a stimulus stream
lsl::stream_info info = createStimulationStreamInfo(m_markerName, m_markerID);
try { m_stimOutlet = new lsl::stream_outlet(info); }
catch (...)
{
this->getLogManager() << "Unable to create marker outlet\n";
return false;
}
}
if (m_stimDecoder.isBufferReceived()) { sendStimulation(m_stimOutlet, m_iStimSet); }
//if (m_stimDecoder.isEndReceived()) { }
}
return true;
}
} // namespace Games
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyLSL
@@ -0,0 +1,94 @@
///-------------------------------------------------------------------------------------------------
///
/// \file CBoxAlgorithmHelloWorldGame.hpp
/// \brief Class of the box that communicate with Hello World Game.
/// \author Thibaut Monseigne (Inria).
/// \version 1.0.
/// \date 12/03/2020.
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
///
///-------------------------------------------------------------------------------------------------
#pragma once
#ifdef TARGET_HAS_ThirdPartyLSL
#include "defines.hpp"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <lsl_cpp.h>
#include <ctime>
#include <iostream>
namespace OpenViBE {
namespace Plugins {
namespace Games {
/// <summary> The class CBoxAlgorithmHelloWorldGame describes the box that send value in LSL. </summary>
class CBoxAlgorithmHelloWorldGame 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>, Game_Box_Hello_World)
protected:
// Decoders
Toolkit::TStimulationDecoder<CBoxAlgorithmHelloWorldGame> m_stimDecoder;
Toolkit::TSignalDecoder<CBoxAlgorithmHelloWorldGame> m_signalDecoder;
CMatrix* m_iMatrix = nullptr;
IStimulationSet* m_iStimSet = nullptr;
lsl::stream_outlet *m_signalOutlet = nullptr, *m_stimOutlet = nullptr;
const std::string m_signalName = "ovSignal", m_markerName = "ovMarkers";
std::string m_signalID, m_markerID;
};
/// <summary> Descriptor of the box Hello World Game. </summary>
class CBoxAlgorithmHelloWorldGameDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return "Hello World Game"; }
CString getAuthorName() const override { return "Thibaut Monseigne"; }
CString getAuthorCompanyName() const override { return "Inria"; }
CString getShortDescription() const override { return "Send input stream via LabStreamingLayer (LSL) to the unity game Hello World."; }
CString getDetailedDescription() const override
{
return "The Unity Game is in the OpenViBE Unity Game Set of Repository (https://gitlab.inria.fr/openvibe/unity-games/hello-world).\n";
}
CString getCategory() const override { return "Games"; }
CString getVersion() const override { return "0.1"; }
CString getStockItemName() const override { return "gtk-connect"; }
CIdentifier getCreatedClass() const override { return Game_Box_Hello_World; }
IPluginObject* create() override { return new CBoxAlgorithmHelloWorldGame; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addInput("Input signal", OV_TypeId_Signal);
prototype.addInput("Input stimulations", OV_TypeId_Stimulations);
return true;
}
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, Game_Box_Hello_World_Desc)
};
} // namespace Games
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyLSL
@@ -0,0 +1,21 @@
///-------------------------------------------------------------------------------------------------
///
/// \file defines.hpp
/// \brief Defines list for Setting, Shortcut Macro and const.
/// \author Thibaut Monseigne (Inria).
/// \version 1.0.
/// \date 12/03/2020.
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
///
///-------------------------------------------------------------------------------------------------
#pragma once
// Boxes
//---------------------------------------------------------------------------------------------------
#define Game_Box_Hello_World OpenViBE::CIdentifier(0x46705bc3, 0x3058a939)
#define Game_Box_Hello_World_Desc OpenViBE::CIdentifier(0x3f921b93, 0xadb2b2ec)
#define Game_Box_Hello_Sender OpenViBE::CIdentifier(0x4cbf4237, 0x24f54a7c)
#define Game_Box_Hello_Sender_Desc OpenViBE::CIdentifier(0x5730a8f1, 0x96a608cc)
#define Game_Box_Hello_Bidirectionnal OpenViBE::CIdentifier(0x47616d65, 0x42696469)
#define Game_Box_Hello_Bidirectionnal_Desc OpenViBE::CIdentifier(0x47616d65, 0x42696464)
@@ -0,0 +1,24 @@
#include <openvibe/ov_all.h>
//#include "defines.hpp"
// Boxes Includes
#include "boxes/CBoxAlgorithmHelloWorldGame.hpp"
#include "boxes/CBoxAlgorithmHelloSenderGame.hpp"
#include "boxes/CBoxAlgorithmHelloBidirectionnalGame.hpp"
namespace OpenViBE {
namespace Plugins {
namespace Games {
OVP_Declare_Begin()
#ifdef TARGET_HAS_ThirdPartyLSL
// Register boxes
OVP_Declare_New(CBoxAlgorithmHelloWorldGameDesc)
OVP_Declare_New(CBoxAlgorithmHelloSenderGameDesc)
OVP_Declare_New(CBoxAlgorithmHelloBidirectionnalGameDesc)
#endif // TARGET_HAS_ThirdPartyLSL
OVP_Declare_End()
} // namespace Games
} // namespace Plugins
} // namespace OpenViBE
@@ -0,0 +1,91 @@
#include <iostream>
#ifdef TARGET_HAS_ThirdPartyLSL
#include "utils.hpp"
//-------------------------------------------------------------------------------------------------
lsl::stream_info createSignalStreamInfo(const std::string& name, const std::string& id, const OpenViBE::CMatrix* matrix, const size_t frequency)
{
const size_t nChannel = matrix->getDimensionSize(0);
// Open a signal stream
lsl::stream_info res(name, "signal", int(nChannel), double(frequency), lsl::cf_float32, id);
lsl::xml_element channels = res.desc().append_child("channels");
for (size_t c = 0; c < nChannel; ++c)
{
const std::string tmp = matrix->getDimensionLabel(0, c);
channels.append_child("channel").append_child_value("label", tmp).append_child_value("unit", "unknown").append_child_value("type", "signal");
}
return res;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
lsl::stream_info createStimulationStreamInfo(const std::string& name, const std::string& id)
{
lsl::stream_info res(name, "Markers", 1, lsl::IRREGULAR_RATE, lsl::cf_int32, id);
res.desc().append_child("channels").append_child("channel").append_child_value("label", "Stimulations").append_child_value("type", "marker");
return res;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void sendSignal(lsl::stream_outlet* outlet, const OpenViBE::CMatrix* matrix, const uint64_t startTime, const uint64_t endTime)
{
if (outlet->have_consumers())
{
const size_t nChannel = matrix->getDimensionSize(0);
const size_t nSamples = matrix->getDimensionSize(1);
const double* iBuffer = matrix->getBuffer();
std::vector<float> buffer(nChannel);
// note: the step computed below should be exactly the same as could be obtained from the sampling rate
const double start = OpenViBE::CTime(startTime).toSeconds();
const double step = OpenViBE::CTime(endTime - startTime).toSeconds() / double(nSamples);
for (size_t s = 0; s < nSamples; ++s)
{
for (size_t c = 0; c < nChannel; ++c) { buffer[c] = float(iBuffer[c * nSamples + s]); }
outlet->push_sample(buffer, start + double(s) * step);
}
}
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void sendStimulation(lsl::stream_outlet* outlet, const OpenViBE::IStimulationSet* stimSet)
{
if (outlet->have_consumers())
{
for (size_t s = 0; s < stimSet->getStimulationCount(); ++s)
{
const int code = int(stimSet->getStimulationIdentifier(s));
const double date = OpenViBE::CTime(stimSet->getStimulationDate(s)).toSeconds();
outlet->push_sample(&code, date);
}
}
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
lsl::stream_info findStreamInfo(const std::string& name, const std::string& id, const int timeout)
{
// Find the signal stream
const std::vector<lsl::stream_info> infos = lsl::resolve_stream("name", name, 1, timeout);
if (infos.empty())
{
if (timeout != 0) { std::cerr << "Failed to find stream with name [" << name << "]\n"; } // Avoid a print if timeout is 0
return lsl::stream_info();
}
for (const auto& i : infos)
{
if (i.source_id() == id) { return i; } // This is the best one
}
return infos[0];
}
//-------------------------------------------------------------------------------------------------
#endif // TARGET_HAS_ThirdPartyLSL
@@ -0,0 +1,62 @@
///-------------------------------------------------------------------------------------------------
///
/// \file utils.hpp
/// \brief Defines some function to facilitate Box Management.
/// \author Thibaut Monseigne (Inria).
/// \version 1.0.
/// \date 12/03/2020.
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
///
///-------------------------------------------------------------------------------------------------
#pragma once
#ifdef TARGET_HAS_ThirdPartyLSL
#include <openvibe/ov_all.h>
#include <lsl_cpp.h>
//-------------------------------------------------------------------------------------------------
// Sending
//-------------------------------------------------------------------------------------------------
/// <summary> Create the stream information for signals.</summary>
/// <param name="name"> The name of the stream. </param>
/// <param name="id"> The identifier of the stream. </param>
/// <param name="matrix"> The matrix to get infos (channel number and label).</param>
/// <param name="frequency"> The signal frequency.</param>
/// <returns> the stream info. </returns>
lsl::stream_info createSignalStreamInfo(const std::string& name, const std::string& id, const OpenViBE::CMatrix* matrix, const size_t frequency);
/// <summary> Create the stream information for stimulations.</summary>
/// <param name="name"> The name of the stream. </param>
/// <param name="id"> The identifier of the stream. </param>
/// <returns> the stream info. </returns>
lsl::stream_info createStimulationStreamInfo(const std::string& name, const std::string& id);
/// <summary> Send Signal in LSL outlet. </summary>
/// <param name="outlet"> The LSL outlet. </param>
/// <param name="matrix"> The matrix with the signal to send. </param>
/// <param name="startTime"> The start time of the signal. </param>
/// <param name="endTime"> The end time of the signal. </param>
void sendSignal(lsl::stream_outlet* outlet, const OpenViBE::CMatrix* matrix, const uint64_t startTime, const uint64_t endTime);
/// <summary> Send the stimulation in LSL outlet. </summary>
/// <param name="outlet"> The LSL outlet. </param>
/// <param name="stimSet">The stimulation set to send. </param>
void sendStimulation(lsl::stream_outlet* outlet, const OpenViBE::IStimulationSet* stimSet);
//-------------------------------------------------------------------------------------------------
// Receiving
//-------------------------------------------------------------------------------------------------
/// <summary> Finds the stream information with the function <c>lsl::resolve_stream</c>. </summary>
/// <param name="name"> The expected name of the stream. </param>
/// <param name="id"> Optionally The expected ID of the stream in addition of the name. </param>
/// <param name="timeout"> Optionally a timeout of the operation, in seconds (default: no timeout).
/// If the timeout expires, a default stream info is returned. </param>
/// <returns></returns>
lsl::stream_info findStreamInfo(const std::string& name, const std::string& id = "", const int timeout = LSL_FOREVER);
#endif // TARGET_HAS_ThirdPartyLSL