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,53 @@
PROJECT(openvibe-plugins-matlab)
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
SET(PROJECT_VERSION ${OV_GLOBAL_VERSION_STRING})
add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/share/OV_stimulations.m
DEPENDS openvibe-stimulation-generator ${OPENVIBE_SDK_PATH}/share/openvibe/toolkit/stimulation_list.txt
COMMAND openvibe-stimulation-generator
--matlab
${OPENVIBE_SDK_PATH}/share/openvibe/toolkit/stimulation_list.txt
${CMAKE_CURRENT_SOURCE_DIR}/share/OV_stimulations.m
COMMENT "Generating matlab stimulation sources..." )
add_custom_target(generate_matlab_stimulations_file DEPENDS share/OV_stimulations.m)
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.inl)
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
add_dependencies(openvibe-plugins-matlab generate_matlab_stimulations_file)
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("FindOpenViBEModuleSystem")
INCLUDE("FindOpenViBEModuleFS")
INCLUDE("FindThirdPartyMatlab")
# ---------------------------------
# ---------------------------------
# -----------------------------
# 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/matlab)
INSTALL(DIRECTORY box-tutorials DESTINATION ${DIST_DATADIR}/openvibe/scenarios/)
@@ -0,0 +1,543 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>2.2.0</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x00002bed, 0x00001e7e)</Identifier>
<Name>Raw signal</Name>
<AlgorithmClassIdentifier>(0x0055be5f, 0x087bdd12)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Data</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulations</Name>
</Input>
<Input>
<TypeIdentifier>(0x6ab26b81, 0x0f8c02f3)</TypeIdentifier>
<Name>Channel Units</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x5de046a6, 0x086340aa)</TypeIdentifier>
<Name>Display Mode</Name>
<DefaultValue>Scan</DefaultValue>
<Value>Scan</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x33a30739, 0x00d5299b)</TypeIdentifier>
<Name>Auto vertical scale</Name>
<DefaultValue>Per channel</DefaultValue>
<Value>Per channel</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Scale refresh interval (secs)</Name>
<DefaultValue>5</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Scale</Name>
<DefaultValue>100</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Offset</Name>
<DefaultValue>0</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Time Scale</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Horizontal ruler</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Vertical ruler</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Multiview</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>304</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>544</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x92c056a7, 0x2dc71aff)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc73e83ec, 0xf855c5bc)</Identifier>
<Value>false</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>9</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>3</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x000043a1, 0x00007d94)</Identifier>
<Name>Tuto 1 : Signal filter</Name>
<AlgorithmClassIdentifier>(0x03303e0e, 0x39fe10df)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Signal input</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Trigger</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Filtered Signal</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Box clock frequency in Hz</Name>
<DefaultValue>64</DefaultValue>
<Value>32</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Matlab executable (path)</Name>
<DefaultValue>C:/Program Files (x86)/MATLAB/R2013b/bin/win32/matlab.exe</DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Matlab working directory</Name>
<DefaultValue>[path-to-my-matlab-workspace]</DefaultValue>
<Value>${Player_ScenarioDirectory}</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Initialize function</Name>
<DefaultValue>bci_Initialize</DefaultValue>
<Value>tuto1_signal_filter_Initialize</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Process function</Name>
<DefaultValue>bci_Process</DefaultValue>
<Value>tuto1_signal_filter_Process</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Uninitialize function</Name>
<DefaultValue>bci_Uninitialize</DefaultValue>
<Value>tuto1_signal_filter_Uninitialize</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
<Name>Zero trigger</Name>
<DefaultValue>OVTK_StimulationId_Label_01</DefaultValue>
<Value>OVTK_StimulationId_Label_01</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>240</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>336</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xc0b69293, 0x2c33365a)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>6</Value>
</Attribute>
<Attribute>
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00004e6e, 0x00000d13)</Identifier>
<Name>Matlab output</Name>
<AlgorithmClassIdentifier>(0x0055be5f, 0x087bdd12)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Data</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulations</Name>
</Input>
<Input>
<TypeIdentifier>(0x6ab26b81, 0x0f8c02f3)</TypeIdentifier>
<Name>Channel Units</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x5de046a6, 0x086340aa)</TypeIdentifier>
<Name>Display Mode</Name>
<DefaultValue>Scan</DefaultValue>
<Value>Scan</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x33a30739, 0x00d5299b)</TypeIdentifier>
<Name>Auto vertical scale</Name>
<DefaultValue>Per channel</DefaultValue>
<Value>Per channel</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Scale refresh interval (secs)</Name>
<DefaultValue>5</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Scale</Name>
<DefaultValue>100</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Offset</Name>
<DefaultValue>0</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Time Scale</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Horizontal ruler</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Vertical ruler</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Multiview</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>352</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x92c056a7, 0x2dc71aff)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc73e83ec, 0xf855c5bc)</Identifier>
<Value>false</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>9</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>3</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00006b9e, 0x0000124c)</Identifier>
<Name>Press 'a' to set all samples to 0</Name>
<AlgorithmClassIdentifier>(0x00d317b9, 0x6324c3ff)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Outgoing Stimulations</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Filename</Name>
<DefaultValue>${Path_Data}/plugins/stimulation/simple-keyboard-to-stimulations.txt</DefaultValue>
<Value>${Path_Data}/plugins/stimulation/simple-keyboard-to-stimulations.txt</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>112</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>496</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x8d89d3b7, 0x8339d210)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>1</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00007bdb, 0x0000106d)</Identifier>
<Name>Sinus oscillator</Name>
<AlgorithmClassIdentifier>(0x7e33bdb8, 0x68194a4a)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Generated signal</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Channel count</Name>
<DefaultValue>4</DefaultValue>
<Value>2</Value>
<Modifiability>false</Modifiability>
</Setting>
<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>16</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>112</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>304</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x0b214ed8, 0x1f9ad83a)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>3</Value>
</Attribute>
</Attributes>
</Box>
</Boxes>
<Links>
<Link>
<Identifier>(0x000014b6, 0x00007cdc)</Identifier>
<Source>
<BoxIdentifier>(0x00007bdb, 0x0000106d)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00002bed, 0x00001e7e)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00004c29, 0x0000420f)</Identifier>
<Source>
<BoxIdentifier>(0x00007bdb, 0x0000106d)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000043a1, 0x00007d94)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x0000516a, 0x00000f70)</Identifier>
<Source>
<BoxIdentifier>(0x00006b9e, 0x0000124c)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000043a1, 0x00007d94)</BoxIdentifier>
<BoxInputIndex>1</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x000066b4, 0x00006517)</Identifier>
<Source>
<BoxIdentifier>(0x000043a1, 0x00007d94)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00004e6e, 0x00000d13)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x00000f2b, 0x00004d77)</Identifier>
<Text>You can browse each box' documentation by selecting the box and pressing &lt;b&gt;F1&lt;/b&gt;
The documentation page for this tutorial is available at:
&lt;i&gt;openvibe.inria.fr/tutorial-using-matlab-with-openvibe&lt;/i&gt;</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>32</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x00002ca7, 0x00004cd8)</Identifier>
<Text>&lt;b&gt;Configure the Matlab Scripting box:&lt;/b&gt;
&lt;span color="red"&gt; Set the matlab executable path before use !&lt;/span&gt;
Enter the path to your local Matlab installation.
You can choose the Stimulation trigger
that will set all input samples to 0</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>144</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>240</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x0000775c, 0x000078ff)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0x00006b9e, 0x0000124c)","childCount":0,"identifier":"(0x00001cbe, 0x000035db)","parentIdentifier":"(0xffffffff, 0xffffffff)","type":3},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":492,"identifier":"(0x0000500a, 0x00001fd8)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":634},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x0000288c, 0x00006c84)","index":0,"name":"Default tab","parentIdentifier":"(0x0000500a, 0x00001fd8)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":2,"dividerPosition":221,"identifier":"(0x000017f0, 0x00006465)","index":0,"maxDividerPosition":447,"name":"Vertical split","parentIdentifier":"(0x0000288c, 0x00006c84)","type":4},{"boxIdentifier":"(0x00002bed, 0x00001e7e)","childCount":0,"identifier":"(0x00006c72, 0x00007d16)","index":0,"parentIdentifier":"(0x000017f0, 0x00006465)","type":3},{"boxIdentifier":"(0x00004e6e, 0x00000d13)","childCount":0,"identifier":"(0x000073ee, 0x00006c76)","index":1,"parentIdentifier":"(0x000017f0, 0x00006465)","type":3}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>
@@ -0,0 +1,18 @@
% tuto1_signal_filter_Initialize.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
% The function tuto1_signal_filter_Initialize is called when pressing 'play' in the scenario.
%
function box_out = tuto1_signal_filter_Initialize(box_in)
disp('Matlab initialize function has been called.')
box_in.user_data.trigger_state = false;
% Don't forget to pass the modified box as output.
box_out = box_in;
end
@@ -0,0 +1,50 @@
% tuto1_signal_filter_Process.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
% The function tuto1_signal_filter_Process is called at the clock frequency.
%
function box_out = tuto1_signal_filter_Process(box_in)
% we iterate over the pending chunks on input 2 (STIMULATIONS)
for i = 1: OV_getNbPendingInputChunk(box_in,2)
% we pop the first chunk to be processed, note that box_in is used as the output variable to continue processing
[box_in, start_time, end_time, stim_set] = OV_popInputBuffer(box_in,2);
% the stimulation set is a 3xN matrix.
% The openvibe stimulation stream sends even empty stimulation set
% so the following boxes know there is no stimulation to expect in
% the latest time range. These empty chunk are also in the matlab buffer.
if(numel(stim_set) >= 3) % at least one stim in the set.
fprintf('Received stimulation code %i at time %f\n', stim_set(1), stim_set(2))
if stim_set(1) == box_in.settings(1).value % I'm lazy... I only check the first stim in the set.
box_in.user_data.trigger_state = ~box_in.user_data.trigger_state;
disp('Trigger is switched.')
end
end
end
% we iterate over the pending chunks on input 1 (SIGNAL)
for i = 1: OV_getNbPendingInputChunk(box_in,1)
% we pop the first chunk to be processed, note that box_in is used as the output variable to continue processing
[box_in, start_time, end_time, matrix_data] = OV_popInputBuffer(box_in,1);
box_in.outputs{1}.header = box_in.inputs{1}.header;
% if requested, all samples are set to 0
if(box_in.user_data.trigger_state)
matrix_data(1:end) = 0;
end
% we add the chunk to the signal output buffer. Note that we use box_in as the output variable.
box_in = OV_addOutputBuffer(box_in,1,start_time,end_time,matrix_data);
end
% Pass the modified box as output to continue processing
box_out = box_in;
end
@@ -0,0 +1,13 @@
% tuto1_signal_filter_Uninitialize.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
% The function tuto1_signal_filter_Uninitialize is called when pressing 'stop' in the scenario.
%
function box_out = tuto1_signal_filter_Uninitialize(box_in)
disp('Matlab uninitialize function has been called.')
box_out = box_in;
end
@@ -0,0 +1,688 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>2.2.0</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x000008b2, 0x000031dd)</Identifier>
<Name>Corrupted signal</Name>
<AlgorithmClassIdentifier>(0x0055be5f, 0x087bdd12)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Data</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulations</Name>
</Input>
<Input>
<TypeIdentifier>(0x6ab26b81, 0x0f8c02f3)</TypeIdentifier>
<Name>Channel Units</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x5de046a6, 0x086340aa)</TypeIdentifier>
<Name>Display Mode</Name>
<DefaultValue>Scan</DefaultValue>
<Value>Scan</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x33a30739, 0x00d5299b)</TypeIdentifier>
<Name>Auto vertical scale</Name>
<DefaultValue>Per channel</DefaultValue>
<Value>Per channel</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Scale refresh interval (secs)</Name>
<DefaultValue>5</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Scale</Name>
<DefaultValue>100</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Offset</Name>
<DefaultValue>0</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Time Scale</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Horizontal ruler</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Vertical ruler</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Multiview</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>416</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>304</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x92c056a7, 0x2dc71aff)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc73e83ec, 0xf855c5bc)</Identifier>
<Value>false</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>9</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>3</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00001dc6, 0x00006378)</Identifier>
<Name>Time based epoching</Name>
<AlgorithmClassIdentifier>(0x00777fa0, 0x5dc3f560)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Input signal</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Epoched signal 1</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Epoch 1 duration (in sec)</Name>
<DefaultValue>1</DefaultValue>
<Value>2</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Epoch 1 intervals (in sec)</Name>
<DefaultValue>0.5</DefaultValue>
<Value>2</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>192</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>352</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xc5ff41e9, 0xccc59a01)</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>
</Attributes>
</Box>
<Box>
<Identifier>(0x000027c9, 0x0000731d)</Identifier>
<Name>1</Name>
<AlgorithmClassIdentifier>(0x361722e8, 0x311574e8)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Input signal</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Output signal</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Channel List</Name>
<DefaultValue>:</DefaultValue>
<Value>:</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x3bcf9e67, 0x0c23994d)</TypeIdentifier>
<Name>Action</Name>
<DefaultValue>Select</DefaultValue>
<Value>Select</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x666f25e9, 0x3e5738d6)</TypeIdentifier>
<Name>Channel Matching Method</Name>
<DefaultValue>Smart</DefaultValue>
<Value>Smart</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>112</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x277826e1, 0xa30a3bd0)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc73e83ec, 0xf855c5bc)</Identifier>
<Value>false</Value>
</Attribute>
<Attribute>
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
<Value>1</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>3</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>1</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x000066c7, 0x00005ac8)</Identifier>
<Name>Generic stream reader</Name>
<AlgorithmClassIdentifier>(0x6468099f, 0x0370095a)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Output stream 1</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Filename</Name>
<DefaultValue></DefaultValue>
<Value>${Path_Data}/scenarios/signals/bci-ssvep-training.ov</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>48</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xf37b8e7a, 0x1bc33e4e)</Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00007ec5, 0x00003579)</Identifier>
<Name>Tuto2 : FFT</Name>
<AlgorithmClassIdentifier>(0x03303e0e, 0x39fe10df)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Signal input</Name>
</Input>
</Inputs>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Filtered Signal</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Box clock frequency in Hz</Name>
<DefaultValue>64</DefaultValue>
<Value>32</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Matlab executable (path)</Name>
<DefaultValue>C:/Program Files (x86)/MATLAB/R2013b/bin/win32/matlab.exe</DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Matlab working directory</Name>
<DefaultValue>[path-to-my-matlab-workspace]</DefaultValue>
<Value>${Player_ScenarioDirectory}</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Initialize function</Name>
<DefaultValue>bci_Initialize</DefaultValue>
<Value>tuto2_FFT_filter_Initialize</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Process function</Name>
<DefaultValue>bci_Process</DefaultValue>
<Value>tuto2_FFT_filter_Process</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Uninitialize function</Name>
<DefaultValue>bci_Uninitialize</DefaultValue>
<Value>tuto2_FFT_filter_Uninitialize</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Noise frequency</Name>
<DefaultValue>20</DefaultValue>
<Value>20</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Noise amplitude</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Plot range : min frequency</Name>
<DefaultValue>5</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Plot range : max frequency</Name>
<DefaultValue>50</DefaultValue>
<Value>50</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>288</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>336</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xc0b69293, 0x2c33365a)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>6</Value>
</Attribute>
<Attribute>
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00007f47, 0x00001bc6)</Identifier>
<Name>Raw signal</Name>
<AlgorithmClassIdentifier>(0x0055be5f, 0x087bdd12)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Data</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulations</Name>
</Input>
<Input>
<TypeIdentifier>(0x6ab26b81, 0x0f8c02f3)</TypeIdentifier>
<Name>Channel Units</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x5de046a6, 0x086340aa)</TypeIdentifier>
<Name>Display Mode</Name>
<DefaultValue>Scan</DefaultValue>
<Value>Scan</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x33a30739, 0x00d5299b)</TypeIdentifier>
<Name>Auto vertical scale</Name>
<DefaultValue>Per channel</DefaultValue>
<Value>Per channel</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Scale refresh interval (secs)</Name>
<DefaultValue>5</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Scale</Name>
<DefaultValue>100</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Offset</Name>
<DefaultValue>0</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Time Scale</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Horizontal ruler</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Vertical ruler</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Multiview</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>416</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>464</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x92c056a7, 0x2dc71aff)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc73e83ec, 0xf855c5bc)</Identifier>
<Value>false</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>9</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>3</Value>
</Attribute>
</Attributes>
</Box>
</Boxes>
<Links>
<Link>
<Identifier>(0x00002758, 0x00001276)</Identifier>
<Source>
<BoxIdentifier>(0x000027c9, 0x0000731d)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00007f47, 0x00001bc6)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x000046f2, 0x00007e90)</Identifier>
<Source>
<BoxIdentifier>(0x000027c9, 0x0000731d)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00001dc6, 0x00006378)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x0000494d, 0x00004db5)</Identifier>
<Source>
<BoxIdentifier>(0x00001dc6, 0x00006378)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00007ec5, 0x00003579)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00006c26, 0x00006a80)</Identifier>
<Source>
<BoxIdentifier>(0x00007ec5, 0x00003579)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000008b2, 0x000031dd)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00006c31, 0x00005c81)</Identifier>
<Source>
<BoxIdentifier>(0x000066c7, 0x00005ac8)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x000027c9, 0x0000731d)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x000020c1, 0x00005db7)</Identifier>
<Text>We extract a 2 seconds window
every 2 seconds</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>96</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>176</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x000032ad, 0x000007b4)</Identifier>
<Text>&lt;b&gt;Configure the Matlab Scripting box:&lt;/b&gt;
&lt;span color="red"&gt; Set the matlab executable path
and the working directory before use !&lt;/span&gt;
If you want to add a sinusoid noise to the signal
set the noise frequency and amplitude.
Amplitude to 0 results in no noise.
Set the frequency range for the plot scale.</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>96</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>288</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x00003f54, 0x00005026)</Identifier>
<Text>You can browse each box' documentation by selecting the box and pressing &lt;b&gt;F1&lt;/b&gt;
The documentation page for this tutorial is available at:
&lt;i&gt;openvibe.inria.fr/tutorial-using-matlab-with-openvibe&lt;/i&gt;</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>-16</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x00006b7a, 0x000044fb)</Identifier>
<Text>The signal display boxes prints
on a 2 seconds horizontal scale</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>96</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>400</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x0000775c, 0x000078ff)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":362,"identifier":"(0x00005a65, 0x00005347)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":442},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00007762, 0x000022c1)","index":0,"name":"Default tab","parentIdentifier":"(0x00005a65, 0x00005347)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":2,"dividerPosition":156,"identifier":"(0x00007f9f, 0x00002f07)","index":0,"maxDividerPosition":317,"name":"Vertical split","parentIdentifier":"(0x00007762, 0x000022c1)","type":4},{"boxIdentifier":"(0x00007f47, 0x00001bc6)","childCount":0,"identifier":"(0x00006697, 0x000030ae)","index":0,"parentIdentifier":"(0x00007f9f, 0x00002f07)","type":3},{"boxIdentifier":"(0x000008b2, 0x000031dd)","childCount":0,"identifier":"(0x000062cd, 0x0000001e)","index":1,"parentIdentifier":"(0x00007f9f, 0x00002f07)","type":3}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>
@@ -0,0 +1,25 @@
% tuto2_FFT_filter_Initialize.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
function box_out = tuto2_FFT_filter_Initialize(box_in)
% we display the setting values
disp('Box settings are:')
for i=1:size(box_in.settings,2)
fprintf('\t%s : %s\n',box_in.settings(i).name, num2str(box_in.settings(i).value));
end
% let's add a user-defined indicator to know if the output header is set
box_in.user_data.is_headerset = false;
% We also add some statistics
box_in.user_data.nb_matrix_processed = 0;
box_in.user_data.mean_fft_matrix = 0;
box_out = box_in;
end
@@ -0,0 +1,75 @@
% tuto2_FFT_filter_Process.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
function box_out = tuto2_FFT_filter_Process(box_in)
for i = 1: OV_getNbPendingInputChunk(box_in,1)
if(~box_in.user_data.is_headerset)
% The output is the input + noise, only on first channel
box_in.outputs{1}.header = box_in.inputs{1}.header;
box_in.outputs{1}.header.nb_channels = 1;
box_in.outputs{1}.header.channel_names = {'FFT'};
box_in.user_data.is_headerset = 1;
% We print the header in the console
disp('Input header is :')
box_in.inputs{1}.header
disp('Output header is :')
box_in.outputs{1}.header
end
% we increment the matrix count
box_in.user_data.nb_matrix_processed = box_in.user_data.nb_matrix_processed + 1;
[box_in, start_time, end_time, matrix_data] = OV_popInputBuffer(box_in,1);
Fs = box_in.inputs{1}.header.sampling_rate; % Sampling frequency
T = 1/Fs; % Sample time
L = box_in.inputs{1}.header.nb_samples_per_buffer; % Length of signal
t = (0:L-1)*T; % Time vector
% We generate the requested sinusoid noise
noise_amplitude = box_in.settings(2).value;
noise_frequency = box_in.settings(1).value;
sinusoid = noise_amplitude * sin(2*pi* noise_frequency *t);
% We add this sinus to the original signal on first channel only
sig = sinusoid + matrix_data(1,1:L);
subplot(3,1,1);
plot(Fs*t,sinusoid)
title('Noise')
xlabel('time (seconds)')
subplot(3,1,2);
plot(Fs*t,sig)
title('Signal Corrupted with the noise (channel 1)')
xlabel('time (seconds)')
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(sig,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
plot_range_fmin = box_in.settings(3).value;
plot_range_fmax = box_in.settings(4).value;
subplot(3,1,3)
plot(f(plot_range_fmin*2:plot_range_fmax*2),2*abs(Y(plot_range_fmin*2:plot_range_fmax*2)))
title('Single-Sided Amplitude Spectrum of the corrupted signal (channel 1)')
xlabel('Frequency (Hz)')
ylabel('Amplitude')
% we sum the FFT for later mean computation
if box_in.user_data.nb_matrix_processed == 1
box_in.user_data.mean_fft_matrix = Y;
else
box_in.user_data.mean_fft_matrix = box_in.user_data.mean_fft_matrix + Y;
end
box_in = OV_addOutputBuffer(box_in,1,start_time,end_time,sig);
end
box_out = box_in;
end
@@ -0,0 +1,34 @@
% tuto2_FFT_filter_Uninitialize.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
% The function tuto2_FFT_filter_Uninitialize is called when pressing 'stop' in the scenario.
% We compute the mean FFT and plot it.
%
function box_out = tuto2_FFT_filter_Uninitialize(box_in)
disp('Uninitializing the box...')
Fs = box_in.inputs{1}.header.sampling_rate; % Sampling frequency
L = box_in.inputs{1}.header.nb_samples_per_buffer; % Length of signal
NFFT = 2^nextpow2(L);
f = Fs/2*linspace(0,1,NFFT/2+1);
box_in.user_data.mean_fft_matrix = box_in.user_data.mean_fft_matrix / box_in.user_data.nb_matrix_processed;
%% we close the previous figure window and plot the mean FFT between 5 and 50Hz.
close(gcf);
plot_range_fmin = box_in.settings(3).value;
plot_range_fmax = box_in.settings(4).value;
plot(f(plot_range_fmin*2:plot_range_fmax*2),2*abs(box_in.user_data.mean_fft_matrix(plot_range_fmin*2:plot_range_fmax*2)))
title('MEAN Single-Sided Amplitude Spectrum of the corrupted signal (channel 1)')
xlabel('Frequency (Hz)')
ylabel('Amplitude')
% We pause the execution for 10 seconds (to be able to see the figure before the scenario is stopped)
pause(10);
box_out = box_in;
end
@@ -0,0 +1,338 @@
<OpenViBE-Scenario>
<FormatVersion>2</FormatVersion>
<Creator>OpenViBE Designer</Creator>
<CreatorVersion>2.2.0</CreatorVersion>
<Settings></Settings>
<Inputs></Inputs>
<Outputs></Outputs>
<Boxes>
<Box>
<Identifier>(0x00001c6f, 0x00005a88)</Identifier>
<Name>Tuto 3 : sinus generator</Name>
<AlgorithmClassIdentifier>(0x03303e0e, 0x39fe10df)</AlgorithmClassIdentifier>
<Outputs>
<Output>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>New output</Name>
</Output>
<Output>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>New output(1)</Name>
</Output>
</Outputs>
<Settings>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Box clock frequency in Hz</Name>
<DefaultValue>64</DefaultValue>
<Value>32</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
<Name>Matlab executable (path)</Name>
<DefaultValue>C:/Program Files (x86)/MATLAB/R2013b/bin/win32/matlab.exe</DefaultValue>
<Value></Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Matlab working directory</Name>
<DefaultValue>${Player_ScenarioDirectory}</DefaultValue>
<Value>${Player_ScenarioDirectory}</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Initialize function</Name>
<DefaultValue>matlab_Initialize</DefaultValue>
<Value>tuto3_sinus_generator_Initialize</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Process function</Name>
<DefaultValue>matlab_Process</DefaultValue>
<Value>tuto3_sinus_generator_Process</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
<Name>Uninitialize function</Name>
<DefaultValue>matlab_Uninitialize</DefaultValue>
<Value>tuto3_sinus_generator_Uninitialize</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Channel count</Name>
<DefaultValue></DefaultValue>
<Value>4</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Samples per buffer</Name>
<DefaultValue></DefaultValue>
<Value>16</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
<Name>Amplitude</Name>
<DefaultValue></DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
<Name>Stimulation</Name>
<DefaultValue>OVTK_GDF_Artifact_EOG_Large</DefaultValue>
<Value>OVTK_StimulationId_Label_01</Value>
<Modifiability>false</Modifiability>
</Setting>
</Settings>
<Attributes>
<Attribute>
<Identifier>(0x17ee7c08, 0x94c14893)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
<Value>208</Value>
</Attribute>
<Attribute>
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
<Value>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0xc0b69293, 0x2c33365a)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc46b3d00, 0x3e0454e1)</Identifier>
<Value>(0x00000000, 0x6e3d4519)</Value>
</Attribute>
<Attribute>
<Identifier>(0xc73e83ec, 0xf855c5bc)</Identifier>
<Value>false</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>6</Value>
</Attribute>
<Attribute>
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
<Value></Value>
</Attribute>
</Attributes>
</Box>
<Box>
<Identifier>(0x00002f39, 0x000039fc)</Identifier>
<Name>Signal display</Name>
<AlgorithmClassIdentifier>(0x0055be5f, 0x087bdd12)</AlgorithmClassIdentifier>
<Inputs>
<Input>
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
<Name>Data</Name>
</Input>
<Input>
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
<Name>Stimulations</Name>
</Input>
<Input>
<TypeIdentifier>(0x6ab26b81, 0x0f8c02f3)</TypeIdentifier>
<Name>Channel Units</Name>
</Input>
</Inputs>
<Settings>
<Setting>
<TypeIdentifier>(0x5de046a6, 0x086340aa)</TypeIdentifier>
<Name>Display Mode</Name>
<DefaultValue>Scan</DefaultValue>
<Value>Scan</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x33a30739, 0x00d5299b)</TypeIdentifier>
<Name>Auto vertical scale</Name>
<DefaultValue>Per channel</DefaultValue>
<Value>Per channel</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Scale refresh interval (secs)</Name>
<DefaultValue>5</DefaultValue>
<Value>5</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Scale</Name>
<DefaultValue>100</DefaultValue>
<Value>100</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Vertical Offset</Name>
<DefaultValue>0</DefaultValue>
<Value>0</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
<Name>Time Scale</Name>
<DefaultValue>10</DefaultValue>
<Value>10</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Horizontal ruler</Name>
<DefaultValue>true</DefaultValue>
<Value>true</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Vertical ruler</Name>
<DefaultValue>false</DefaultValue>
<Value>false</Value>
<Modifiability>false</Modifiability>
</Setting>
<Setting>
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
<Name>Multiview</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>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
<Value>(0x92c056a7, 0x2dc71aff)</Value>
</Attribute>
<Attribute>
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
<Value></Value>
</Attribute>
<Attribute>
<Identifier>(0xc73e83ec, 0xf855c5bc)</Identifier>
<Value>false</Value>
</Attribute>
<Attribute>
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
<Value>9</Value>
</Attribute>
<Attribute>
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
<Value>3</Value>
</Attribute>
</Attributes>
</Box>
</Boxes>
<Links>
<Link>
<Identifier>(0x00003443, 0x00005347)</Identifier>
<Source>
<BoxIdentifier>(0x00001c6f, 0x00005a88)</BoxIdentifier>
<BoxOutputIndex>0</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00002f39, 0x000039fc)</BoxIdentifier>
<BoxInputIndex>0</BoxInputIndex>
</Target>
</Link>
<Link>
<Identifier>(0x00007d44, 0x000014de)</Identifier>
<Source>
<BoxIdentifier>(0x00001c6f, 0x00005a88)</BoxIdentifier>
<BoxOutputIndex>1</BoxOutputIndex>
</Source>
<Target>
<BoxIdentifier>(0x00002f39, 0x000039fc)</BoxIdentifier>
<BoxInputIndex>1</BoxInputIndex>
</Target>
</Link>
</Links>
<Comments>
<Comment>
<Identifier>(0x00000b01, 0x0000700e)</Identifier>
<Text>You can browse each box' documentation by selecting the box and pressing &lt;b&gt;F1&lt;/b&gt;
The documentation page for this tutorial is available at:
&lt;i&gt;openvibe.inria.fr/tutorial-using-matlab-with-openvibe&lt;/i&gt;</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>400</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>0</Value>
</Attribute>
</Attributes>
</Comment>
<Comment>
<Identifier>(0x00001e22, 0x0000145c)</Identifier>
<Text>&lt;b&gt;Configure the Matlab Scripting box:&lt;/b&gt;
&lt;span color="red"&gt; Set the matlab executable path
and the working directory before use !&lt;/span&gt;
You can select the number of channels
and size of data chunk.
Sampling frequency = box clock freqeuncy * samples per block
The box generates one sinus signal per channel
with frequency
F(channel i) = 10 * i Hz
The box sends one stimulation per second</Text>
<Attributes>
<Attribute>
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
<Value>32</Value>
</Attribute>
<Attribute>
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
<Value>272</Value>
</Attribute>
</Attributes>
</Comment>
</Comments>
<Metadata>
<Entry>
<Identifier>(0x0000775c, 0x000078ff)</Identifier>
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
<Data>[{"boxIdentifier":"(0x00002f39, 0x000039fc)","childCount":0,"identifier":"(0x00005e17, 0x00003f09)","parentIdentifier":"(0xffffffff, 0xffffffff)","type":3},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":320,"identifier":"(0x00006dc8, 0x00002e10)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":480},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x000023aa, 0x00003482)","index":0,"name":"Default tab","parentIdentifier":"(0x00006dc8, 0x00002e10)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x00005c13, 0x00001d05)","index":0,"name":"Empty","parentIdentifier":"(0x000023aa, 0x00003482)","type":0}]</Data>
</Entry>
</Metadata>
</OpenViBE-Scenario>
@@ -0,0 +1,38 @@
% tuto3_sinus_generator_Initialize.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
function box_out = tuto3_sinus_generator_Initialize(box_in)
% we display the setting values
disp('Box settings are:')
for i=1:size(box_in.settings,2)
fprintf('\t%s : %s\n',box_in.settings(i).name, num2str(box_in.settings(i).value));
end
% As we produce the signal ourselves, we already know the output header
% we construct the channel names
nb_channels = box_in.settings(1).value;
channel_names = cell(1,nb_channels);
for chan = 1 : nb_channels
channel_names{chan} = sprintf('channel %i',chan);
end
% and deduce the other header elements from the box settings
nb_samples_per_buffer = box_in.settings(2).value;
sampling_rate = box_in.clock_frequency * nb_samples_per_buffer;
box_in = OV_setSignalOutputHeader(box_in, 1, nb_channels, nb_samples_per_buffer, channel_names, sampling_rate);
box_in = OV_setStimulationOutputHeader(box_in,2);
% end time of the last chunk sent
box_in.user_data.last_end_time = 0;
% number of call to the process function
box_in.user_data.call_count = 0;
% sample count
box_in.user_data.nb_samples = 0;
box_out = box_in;
end
@@ -0,0 +1,46 @@
% tuto3_sinus_generator_Process.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
function box_out = tuto3_sinus_generator_Process(box_in)
channel_count = box_in.settings(1).value;
samples_per_buffer = box_in.settings(2).value;
amplitude = box_in.settings(3).value;
stimulation = box_in.settings(4).value;
start_time = box_in.user_data.last_end_time;
end_time = box_in.clock;
% We produce data of the past step (e.g. at t2 we produce the data of [t1,t2]), thus we skip the first call
if start_time ~= 0
T = 1/box_in.outputs{1}.header.sampling_rate;
t = (box_in.user_data.nb_samples:box_in.user_data.nb_samples+samples_per_buffer-1)*T;
signal = zeros(channel_count, samples_per_buffer);
freq = 10;
for chan = 1 : channel_count
sinus = amplitude * sin(2*pi* freq *t);
signal(chan,1:samples_per_buffer) = sinus;
freq = freq + 10;
end
if mod(box_in.user_data.call_count, box_in.clock_frequency) == 0
stim_set = [stimulation; box_in.clock; 0];
disp('Sending a stimulation...');
else
stim_set = [];
end
box_in = OV_addOutputBuffer(box_in,1,start_time,end_time,signal);
box_in = OV_addOutputBuffer(box_in,2,start_time,end_time,stim_set);
box_in.user_data.nb_samples = box_in.user_data.nb_samples + samples_per_buffer;
end
box_in.user_data.last_end_time = end_time;
box_in.user_data.call_count = box_in.user_data.call_count +1;
box_out = box_in;
end
@@ -0,0 +1,14 @@
% tuto3_sinus_generator_Uninitialize.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 25 May 2012
%
% The function tuto3_sinus_generator_Uninitialize is called when pressing 'stop' in the scenario.
%
function box_out = tuto3_sinus_generator_Uninitialize(box_in)
disp('Uninitializing the box...')
box_out = box_in;
end
@@ -0,0 +1,78 @@
/**
* \page BoxAlgorithm_MatlabScripting Matlab Scripting
__________________________________________________________________
Detailed description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Description|
The Matlab Scripting box uses the Matlab Engine to process data using Matlab.
This box can be configured with any number of inputs, outputs and settings, of any type.
You will need a valid Matlab installation and license at runtime. This box is currently compatible with
Matlab 32 and 64 bits on Linux, but only with Matlab 32 bits on Windows.
For a complete tutorial, please check <a href="http://openvibe.inria.fr/tutorial-using-matlab-with-openvibe">this documentation page</a>.
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Description|
__________________________________________________________________
Settings description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Settings|
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Settings|
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Setting1|
The box clock frequency can be an integer between 1 and 128Hz. This tells how many time per second the box "Process" function will be called.
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Setting1|
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Setting2|
User must set the place where to find the Matlab executables. On windows it should be in the bin/win32 directory.
On Linux, fill this setting with the command line you are using to launch Matlab on your computer.
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Setting2|
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Setting3|
Please enter the Matlab working directory in which this box will work. This should be the absolute adress of the folder where you have put all the function files.
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Setting3|
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Setting4|
The name of the matlab function called when initializing the box (i.e. when pressing play in the scenario).
This function is called only once.
Its signature must be: [box_out] = initialize(box_in), where box_out and box_in are specific structure.
Please see the dedicated <a href="http://openvibe.inria.fr/tutorial-using-matlab-with-openvibe">tutorial</a> for a complete reference.
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Setting4|
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Setting5|
The name of the matlab function called on every tick of the process loop.
This function is called at the box clock frequency.
Its signature must be: [box_out] = process(box_in), where box_out and box_in are specific structure.
Please see the dedicated <a href="http://openvibe.inria.fr/tutorial-using-matlab-with-openvibe">tutorial</a> for a complete reference.
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Setting5|
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Setting6|
The name of the matlab function called when uninitializing the box (i.e. when pressing stop in the scenario).
This function is called only once.
Its signature must be: [box_out] = uninitialize(box_in), where box_out and box_in are specific structure.
Please see the dedicated <a href="http://openvibe.inria.fr/tutorial-using-matlab-with-openvibe">tutorial</a> for a complete reference.
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Setting6|
__________________________________________________________________
Examples description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Examples|
The dedicated <a href="http://openvibe.inria.fr/tutorial-using-matlab-with-openvibe">tutorial</a> provides 3 examples:
- Signal filtering
- FFT computation and spectrum plot in Matlab
- Signal and stimulation generator
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Examples|
__________________________________________________________________
Miscellaneous description
__________________________________________________________________
* |OVP_DocBegin_BoxAlgorithm_MatlabScripting_Miscellaneous|
* |OVP_DocEnd_BoxAlgorithm_MatlabScripting_Miscellaneous|
*/
Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

@@ -0,0 +1,19 @@
% openvibe toolbox for Matlab
% OV_addInputBuffer.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 13 Jan. 2012
% Appends a new signal chunk to a signal input buffer in a matlab box instance.
% -------------------------------
% MEANT TO BE USED BY OPENVIBE
function box_out = OV_addInputBuffer(box_in, input_index, start_time, end_time, matrix_data)
chunk.start_time = start_time;
chunk.end_time = end_time;
chunk.matrix_data = matrix_data;
box_in.inputs{input_index}.buffer{size(box_in.inputs{input_index}.buffer,2)+1} = chunk;
box_out = box_in;
end
@@ -0,0 +1,20 @@
% openvibe toolbox for Matlab
% OV_addOutputBuffer.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 13 Jan. 2012
% Appends a new chunk in an output buffer,
% meant to be popped by the openvibe box.
% -------------------------------
% MEANT TO BE USED IN USER SCRIPT
function box_out = OV_addOutputBuffer(box_in, output_index, start_time, end_time, matrix_data)
chunk.start_time = start_time;
chunk.end_time = end_time;
chunk.matrix_data = matrix_data;
box_in.outputs{output_index}.buffer{size(box_in.outputs{output_index}.buffer,2)+1} = chunk;
box_out = box_in;
end
@@ -0,0 +1,35 @@
% OV_MATLAB toolkit
% OV_createBoxInstance.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
%
% This file is meant to be executed prior to any user defined script.
% It construct the objects used by the other functions of the toolkit
% MEANT TO BE USED BY OPENVIBE
%
%out
function box = OV_createBoxInstance(input_count, output_count)
box = [];
box.settings = [];
box.inputs = {};
for i = 1 : input_count
box.inputs{i}.header = {};
box.inputs{i}.buffer = {};
end
box.outputs = {};
for i = 1 : output_count
box.outputs{i}.header = {};
box.outputs{i}.buffer = {};
end
box.user_data = {};
box.clock = 0;
end
@@ -0,0 +1,70 @@
% OV_MATLAB toolkit
% OV_define.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% This file is meant to be executed prior to any user defined script.
% It declare all stim IDs as variable for use by the user.
% MEANT TO BE CALLED BY OPENVIBE
%
% Stimulation codes
% Originally from openvibe-toolkit/ovtk_defines.h
function OV_define()
% STREAM TYPES:
global OV_TypeId_EBMLStream;
OV_TypeId_EBMLStream = uint64(hex2dec('434F65872EFD2B7E'));
global OV_TypeId_ChannelLocalisation;
OV_TypeId_ChannelLocalisation = uint64(hex2dec('013DF452A3A8879A'));
global OV_TypeId_ExperimentationInformation; % deprecated
OV_TypeId_ExperimentationInformation = uint64(hex2dec('403488E7565D70B6')); % deprecated
global OV_TypeId_ExperimentInfo;
OV_TypeId_ExperimentInfo = uint64(hex2dec('403488E7565D70B6'));
global OV_TypeId_Stimulations;
OV_TypeId_Stimulations = uint64(hex2dec('6F752DD0082A321E'));
global OV_TypeId_StreamedMatrix;
OV_TypeId_StreamedMatrix = uint64(hex2dec('544A003E6DCBA5F6'));
global OV_TypeId_FeatureVector;
OV_TypeId_FeatureVector = uint64(hex2dec('17341935152FF448'));
global OV_TypeId_Signal;
OV_TypeId_Signal = uint64(hex2dec('5BA36127195FEAE1'));
global OV_TypeId_Spectrum;
OV_TypeId_Spectrum = uint64(hex2dec('1F261C0A593BF6BD'));
% SETTING TYPES:
global OV_TypeId_Boolean;
OV_TypeId_Boolean = uint64(hex2dec('2CDB2F0B12F231EA'));
global OV_TypeId_Integer;
OV_TypeId_Integer = uint64(hex2dec('007DEEF92F3E95C6'));
global OV_TypeId_Float;
OV_TypeId_Float = uint64(hex2dec('512A166F5C3EF83F'));
global OV_TypeId_String;
OV_TypeId_String = uint64(hex2dec('79A9EDEB245D83FC'));
global OV_TypeId_Filename;
OV_TypeId_Filename = uint64(hex2dec('330306DD74A95F98'));
global OV_TypeId_Script;
OV_TypeId_Script = uint64(hex2dec('B0D0DB4549CBC34A'));
global OV_TypeId_Stimulation;
OV_TypeId_Stimulation = uint64(hex2dec('2C132D6E44AB0D97'));
global OV_TypeId_LogLevel;
OV_TypeId_LogLevel = uint64(hex2dec('A88B36670871638C'));
global OV_TypeId_Color;
OV_TypeId_Color = uint64(hex2dec('7F45A2A97DB12219'));
global OV_TypeId_ColorGradient;
OV_TypeId_ColorGradient = uint64(hex2dec('3D3C7C7FEF0E7129'));
% STIM CODES:
global OVTK_StimulationId_LabelStart;
OVTK_StimulationId_LabelStart = uint64(hex2dec('00008100'));
global OVTK_StimulationId_LabelEnd;
OVTK_StimulationId_LabelEnd = uint64(hex2dec('000081ff'));
global OVTK_StimulationId_NumberStart;
OVTK_StimulationId_NumberStart = uint64(hex2dec('00000000'));
global OVTK_StimulationId_NumberEnd;
OVTK_StimulationId_NumberEnd = uint64(hex2dec('000000ff'));
end
@@ -0,0 +1,24 @@
% openvibe toolbox for Matlab
% OV_getSignalOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function [errno, nb_channels, channel_names, dynamic] = OV_getChannelLocalisationOutputHeader(box_in, output_index)
if(numel(box_in.outputs{output_index}.header) == 0)
nb_channels = 0;
channel_names = 0;
dynamic = 0;
errno = 1;
else
nb_channels = box_in.outputs{output_index}.header.nb_channels;
channel_names = box_in.outputs{output_index}.header.channel_names;
dynamic = box_in.outputs{output_index}.header.dynamic;
errno = 0;
end
end
@@ -0,0 +1,22 @@
% openvibe toolbox for Matlab
% OV_getSignalOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function [errno, nb_features, labels] = OV_getFeatureVectorOutputHeader(box_in, output_index)
if(numel(box_in.outputs{output_index}.header) == 0)
nb_features = 0;
labels = 0;
errno = 1;
else
nb_features = box_in.outputs{output_index}.header.nb_features;
labels = box_in.outputs{output_index}.header.labels;
errno = 0;
end
end
@@ -0,0 +1,20 @@
% OV_MATLAB toolkit
% OV_hasPendingInputChunk.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 13 Jan. 2012
% Tests if there is pending Input chunk in the buffer
% -------------------------------
% MEANT TO BE USED IN USER SCRIPT
function nb_pending = OV_getNbPendingInputChunk(box_in, input_index)
if(input_index > size(box_in.inputs,2))
disp('Error while calling OV_getNbPendingOutputChunk : output index out-of-range.')
nb_pending = 0;
else
nb_pending = size(box_in.inputs{input_index}.buffer,2);
end
end
@@ -0,0 +1,20 @@
% OV_MATLAB toolkit
% OV_hasPendingOutputChunk.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 13 Jan. 2012
% Tests if there is pending output chunk in the buffer
% -------------------------------
% MEANT TO BE USED IN USER SCRIPT
function nb_pending = OV_getNbPendingOutputChunk(box_in, output_index)
if(output_index > size(box_in.outputs,2))
disp('Error while calling OV_getNbPendingOutputChunk : output index out-of-range.')
nb_pending = 0;
else
nb_pending = size(box_in.outputs{output_index}.buffer,2);
end
end
@@ -0,0 +1,26 @@
% openvibe toolbox for Matlab
% OV_getSignalOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function [errno, nb_channels, nb_samples_per_buffer, channel_names, sampling_rate] = OV_getSignalOutputHeader(box_in, output_index)
if(numel(box_in.outputs{output_index}.header) == 0)
nb_channels = 0;
nb_samples_per_buffer = 0;
channel_names = 0;
sampling_rate = 0;
errno = 1;
else
nb_channels = box_in.outputs{output_index}.header.nb_channels;
nb_samples_per_buffer = box_in.outputs{output_index}.header.nb_samples_per_buffer;
channel_names = box_in.outputs{output_index}.header.channel_names;
sampling_rate = box_in.outputs{output_index}.header.sampling_rate;
errno = 0;
end
end
@@ -0,0 +1,31 @@
% openvibe toolbox for Matlab
% OV_getSpectrumOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function [errno, nb_channels, channel_names, nb_abscissas, abscissas_names, abscissas_linear, sampling_rate] = OV_getSpectrumOutputHeader(box_in, output_index)
if(numel(box_in.outputs{output_index}.header) == 0)
nb_channels = 0;
channel_names = 0;
nb_abscissas = 0;
abscissas_names = 0;
abscissas_linear = 0;
sampling_rate = 0;
errno = 1;
else
nb_channels = box_in.outputs{output_index}.header.nb_channels;
channel_names = box_in.outputs{output_index}.header.channel_names;
nb_abscissas = box_in.outputs{output_index}.header.nb_abscissas;
abscissas_names = box_in.outputs{output_index}.header.abscissas_names;
abscissas_linear = box_in.outputs{output_index}.header.abscissas;
%reshape(box_in.outputs{output_index}.header.bands,1,numel(box_in.outputs{output_index}.header.bands));
sampling_rate = box_in.outputs{output_index}.header.sampling_rate;
errno = 0;
end
end
@@ -0,0 +1,14 @@
% openvibe toolbox for Matlab
% OV_getStimulationOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function OV_getStimulationOutputHeader(box_in, output_index)
%This function does nothing, the stimulation header is empty.
end
@@ -0,0 +1,14 @@
% openvibe toolbox for Matlab
% OV_getStimulationOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function OV_getStimulationsOutputHeader(box_in, output_index)
%This function does nothing, the stimulation header is empty.
end
@@ -0,0 +1,24 @@
% openvibe toolbox for Matlab
% OV_getStreamedMatrixOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function [errno, nb_dimensions, dimension_sizes, dimension_labels] = OV_getStreamedMatrixOutputHeader(box_in, output_index)
if(numel(box_in.outputs{output_index}.header) == 0)
nb_dimensions = 0;
dimension_sizes = 0;
dimension_labels = 0;
errno = 1;
else
nb_dimensions = box_in.outputs{output_index}.header.nb_dimensions;
dimension_sizes = box_in.outputs{output_index}.header.dimension_sizes;
dimension_labels = box_in.outputs{output_index}.header.dimension_labels;
errno = 0;
end
end
@@ -0,0 +1,29 @@
% OV_MATLAB toolkit
% OV_popInputBuffer.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 13 Jan. 2012
% Pops the first signal chunk on an input
% -------------------------------
% output = matrix data (matlab format)
% -------------------------------
% MEANT TO BE USED IN USER SCRIPT
function [box_out, start_time,end_time, matrix_data] = OV_popInputBuffer(box_in, input_index)
if size(box_in.inputs{input_index}.buffer,2) == 0
start_time = -1;
end_time = -1;
matrix_data = [];
else
start_time = box_in.inputs{input_index}.buffer{1}.start_time;
end_time = box_in.inputs{input_index}.buffer{1}.end_time;
matrix_data = box_in.inputs{input_index}.buffer{1}.matrix_data;
end
box_in.inputs{input_index}.buffer = box_in.inputs{input_index}.buffer(2:end);
box_out = box_in;
end
@@ -0,0 +1,29 @@
% OV_MATLAB toolkit
% OV_popOutputBuffer.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% pops the last chunk in the output buffer
% MEANT TO BE USED IN OPENVIBE
function [box_out, start_time, end_time, linear_matrix_size, linear_data] = OV_popOutputBuffer(box_in, output_index)
if size(box_in.outputs{output_index}.buffer,1) == 0
start_time = -1;
end_time = -1;
linear_data = [];
linear_matrix_size = 0;
else
start_time = box_in.outputs{output_index}.buffer{1}.start_time;
end_time = box_in.outputs{output_index}.buffer{1}.end_time;
nb_elements = size(box_in.outputs{output_index}.buffer{1}.matrix_data(1:end),2);
linear_data = box_in.outputs{output_index}.buffer{1}.matrix_data;
linear_matrix_size = nb_elements;
end
box_in.outputs{output_index}.buffer = box_in.outputs{output_index}.buffer(2:end);
box_out = box_in;
end
@@ -0,0 +1,29 @@
% OV_MATLAB toolkit
% OV_popOutputBufferReshape.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% pops the last chunk in the output buffer
% MEANT TO BE USED IN OPENVIBE
function [box_out, start_time, end_time, linear_matrix_size, linear_data] = OV_popOutputBufferReshape(box_in, output_index)
if size(box_in.outputs{output_index}.buffer,1) == 0
start_time = -1;
end_time = -1;
linear_data = [];
linear_matrix_size = 0;
else
start_time = box_in.outputs{output_index}.buffer{1}.start_time;
end_time = box_in.outputs{output_index}.buffer{1}.end_time;
nb_elements = numel(box_in.outputs{output_index}.buffer{1}.matrix_data);
linear_data = reshape(box_in.outputs{output_index}.buffer{1}.matrix_data',1,nb_elements);
linear_matrix_size = nb_elements;
end
box_in.outputs{output_index}.buffer = box_in.outputs{output_index}.buffer(2:end);
box_out = box_in;
end
@@ -0,0 +1,19 @@
% OV_MATLAB toolkit
% OV_setChannelLocalizationInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Channel Localization input.
function box_out = OV_setChannelLocalisationInputHeader(box_in, input_index, nb_channels, channel_names, dynamic)
box_in.inputs{input_index}.header.type = 'Channel Localisation Stream';
box_in.inputs{input_index}.header.nb_channels = nb_channels;
box_in.inputs{input_index}.header.channel_names = channel_names;
box_in.inputs{input_index}.header.dynamic = dynamic;
box_in.inputs{input_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,19 @@
% OV_MATLAB toolkit
% OV_setChannelLocalizationInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Channel Localization input.
function box_out = OV_setChannelLocalisationOutputHeader(box_in, output_index, nb_channels, channel_names, dynamic)
box_in.output{output_index}.header.type = 'Channel Localisation Stream';
box_in.output{output_index}.header.nb_channels = nb_channels;
box_in.output{output_index}.header.channel_names = channel_names;
box_in.output{output_index}.header.dynamic = dynamic;
box_in.output{output_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,18 @@
% OV_MATLAB toolkit
% OV_setFeatureVectorInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Feature Vector input.
function box_out = OV_setFeatureVectorInputHeader(box_in, input_index, nb_features, labels)
box_in.inputs{input_index}.header.type = 'Feature Vector Stream';
box_in.inputs{input_index}.header.nb_features = nb_features;
box_in.inputs{input_index}.header.labels = labels;
box_in.inputs{input_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,18 @@
% OV_MATLAB toolkit
% OV_setFeatureVectorInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Feature Vector input.
function box_out = OV_setFeatureVectorOutputHeader(box_in, output_index, nb_features, labels)
box_in.outputs{output_index}.header.type = 'Feature Vector Stream';
box_in.outputs{output_index}.header.nb_features = nb_features;
box_in.outputs{output_index}.header.labels = labels;
box_in.outputs{output_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,15 @@
% OV_MATLAB toolkit
% OV_setSettings.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% This file is meant to be executed prior to any user defined script.
% It construct the objects used by the other functions of the toolkit
% MEANT TO BE USED BY OPENVIBE
function box_out = OV_setSettings(box_in, names, types, values)
box_in.settings = struct('name',names,'type',types,'value',values);
box_out = box_in;
end
@@ -0,0 +1,20 @@
% OV_MATLAB toolkit
% OV_setSignalInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal input.
function box_out = OV_setSignalInputHeader(box_in, input_index, nb_channel, nb_samples_per_buffer, channel_names, sampling_rate)
box_in.inputs{input_index}.header.type = 'Signal Stream';
box_in.inputs{input_index}.header.nb_channels = nb_channel;
box_in.inputs{input_index}.header.nb_samples_per_buffer = nb_samples_per_buffer;
box_in.inputs{input_index}.header.channel_names = channel_names;
box_in.inputs{input_index}.header.sampling_rate = sampling_rate;
box_in.inputs{input_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,21 @@
% OV_MATLAB toolkit
% OV_setSignalOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function box_out = OV_setSignalOutputHeader(box_in, output_index, nb_channel, nb_samples_per_buffer, channel_names, sampling_rate)
box_in.outputs{output_index}.header.type = 'Signal Stream';
box_in.outputs{output_index}.header.nb_channels = nb_channel;
box_in.outputs{output_index}.header.nb_samples_per_buffer = nb_samples_per_buffer;
box_in.outputs{output_index}.header.channel_names = channel_names;
box_in.outputs{output_index}.header.sampling_rate = sampling_rate;
box_in.outputs{output_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,22 @@
% OV_MATLAB toolkit
% OV_setSpectrumHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Spectrum input.
function box_out = OV_setSpectrumInputHeader(box_in, input_index, nb_channels, channel_names, nb_abscissas, abscissas_names, abscissas, sampling_rate)
box_in.inputs{input_index}.header.type = 'Spectrum Stream';
box_in.inputs{input_index}.header.nb_channels = nb_channels;
box_in.inputs{input_index}.header.channel_names = channel_names;
box_in.inputs{input_index}.header.nb_abscissas = nb_abscissas;
box_in.inputs{input_index}.header.abscissas_names = abscissas_names;
box_in.inputs{input_index}.header.abscissas = abscissas;
box_in.inputs{input_index}.header.sampling_rate = sampling_rate;
box_in.inputs{input_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,23 @@
% OV_MATLAB toolkit
% OV_setSpectrumOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Spectrum input.
function box_out = OV_setSpectrumOutputHeader(box_in, output_index, nb_channels, channel_names, nb_abscissas, abscissas_names, abscissas, sampling_rate)
box_in.outputs{output_index}.header.type = 'Spectrum Stream';
box_in.outputs{output_index}.header.nb_channels = nb_channels;
box_in.outputs{output_index}.header.channel_names = channel_names;
box_in.outputs{output_index}.header.nb_abscissas = nb_abscissas;
box_in.outputs{output_index}.header.abscissas_names = abscissas_names;
box_in.outputs{output_index}.header.abscissas = abscissas;
box_in.outputs{output_index}.header.sampling_rate = sampling_rate;
box_in.outputs{output_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,16 @@
% OV_MATLAB toolkit
% OV_setChannelLocalizationInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Stimulation input.
function box_out = OV_setStimulationInputHeader(box_in, input_index)
box_in.inputs{input_index}.header.type = 'Stimulation Stream';
box_in.inputs{input_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,16 @@
% OV_MATLAB toolkit
% OV_setStimulationOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Stimulation input.
function box_out = OV_setStimulationOutputHeader(box_in, output_index)
box_in.outputs{output_index}.header.type = 'Stimulation Stream';
box_in.outputs{output_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,16 @@
% OV_MATLAB toolkit
% OV_setChannelLocalizationInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Stimulation input.
function box_out = OV_setStimulationsInputHeader(box_in, input_index)
box_in.inputs{input_index}.header.type = 'Stimulation Stream';
box_in.inputs{input_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,16 @@
% OV_MATLAB toolkit
% OV_setStimulationOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a Stimulation input.
function box_out = OV_setStimulationsOutputHeader(box_in, output_index)
box_in.outputs{output_index}.header.type = 'Stimulation Stream';
box_in.outputs{output_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,19 @@
% OV_MATLAB toolkit
% OV_setStreamedMatrixInputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a streamed Matrix input.
function box_out = OV_setStreamedMatrixInputHeader(box_in, input_index, nb_dim, dim_sizes, dim_labels)
box_in.inputs{input_index}.header.type = 'Streamed Matrix Stream';
box_in.inputs{input_index}.header.nb_dimensions = nb_dim;
box_in.inputs{input_index}.header.dimension_sizes = dim_sizes;
box_in.inputs{input_index}.header.dimension_labels = dim_labels;
box_in.inputs{input_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,20 @@
% OV_MATLAB toolkit
% OV_setStreamedMatrixOutputHeader.m
% -------------------------------
% Author : Laurent Bonnet (INRIA)
% Date : 28/07/2011
% Set the header information on a signal output.
% MEANT TO BE USED IN USER SCRIPT
function box_out = OV_setStreamedMatrixOutputHeader(box_in, output_index, nb_dim, dim_sizes, dim_labels)
box_in.outputs{output_index}.header.type = 'Streamed Matrix Stream';
box_in.outputs{output_index}.header.nb_dimensions = nb_dim;
box_in.outputs{output_index}.header.dimension_sizes = dim_sizes;
box_in.outputs{output_index}.header.dimension_labels = dim_labels;
box_in.outputs{output_index}.buffer = {};
box_out = box_in;
end
@@ -0,0 +1,733 @@
#include <iomanip>
#if defined TARGET_HAS_ThirdPartyMatlab
#include "ovpCBoxAlgorithmMatlabScripting.h"
#include <system/ovCMath.h>
#include <iostream>
#include <stdio.h>
#include <sstream>
#include <string>
#include <ctime>
#include <algorithm>
#include <mex.h>
#include <engine.h>
#include <fs/Files.h>
#if defined TARGET_OS_Windows
#include <windows.h>
#include <direct.h>
#define getCurrentDir _getcwd
#else
#include <unistd.h>
#define getCurrentDir getcwd
#endif
// Size of the internal buffer storing matlab messages, in char
#define MATLAB_BUFFER 2048
#define MATLAB_ENGINE ((Engine*)m_engineHandle)
namespace OpenViBE {
namespace Plugins {
namespace Matlab {
// Sanitizes a path so that it only has / or \ characters and has a / or \ in the end.
// @fixme should move to plugins-FS possibly
void CBoxAlgorithmMatlabScripting::sanitizePath(CString& pathToModify)
{
std::string tmpPath(pathToModify);
// Append / to end of path if its not there already
if (tmpPath.length() > 0)
{
const char lastChar = tmpPath.at(tmpPath.length() - 1);
if (lastChar != '\\' && lastChar != '/') { tmpPath += "/"; }
}
#if defined TARGET_OS_Windows
std::replace(tmpPath.begin(), tmpPath.end(), '/', '\\'); // Convert '/' to '\'
#endif
pathToModify = tmpPath.c_str();
}
// The checkFailureRoutine() verifies the result of a matlab call (via engine or helper functions) given as argument.
// If the result is false (the matlab call failed), the message msg is printed in the Error Log Level, and the macro returns false.
// The Matlab output buffer is then printed. If an error message is detected in the buffer, the same error message is printed and
// the macro returns false.
bool CBoxAlgorithmMatlabScripting::checkFailureRoutine(const bool result, const CString& msg)
{
OV_ERROR_UNLESS_KRF(result, msg, Kernel::ErrorType::BadProcessing);
m_errorDetected = false;
this->printOutputBufferWithFormat();
OV_ERROR_UNLESS_KRF(!m_errorDetected, msg, Kernel::ErrorType::BadProcessing);
return true;
}
bool CBoxAlgorithmMatlabScripting::openMatlabEngineSafely()
{
this->getLogManager() << Kernel::LogLevel_Trace << "Trying to open the Matlab engine\n";
#if defined TARGET_OS_Linux
m_engineHandle = ::engOpen(m_matlabPath.toASCIIString());
OV_ERROR_UNLESS_KRF(m_matlabEngine, "Could not open the Matlab engine.\nThe configured path to the matlab executable was expanded as '" << m_matlabPath << "'.", Kernel::ErrorType::BadProcessing);
}
#elif defined TARGET_OS_Windows
__try { m_engineHandle = engOpen(nullptr); }
__except (EXCEPTION_EXECUTE_HANDLER)
{
this->getLogManager() << Kernel::LogLevel_Error << "First call to the MATLAB engine failed.\n";
this->getLogManager() << Kernel::LogLevel_Error << "To use this box you must have MATLAB installed on your computer.\n";
#if defined(TARGET_ARCHITECTURE_x64)
this->getLogManager() << Kernel::LogLevel_Error << "For this build of OpenViBE, MATLAB needs to be a 64bit version.\n";
#else
this->getLogManager() << Kernel::LogLevel_Error << "For this build of OpenViBE, MATLAB needs to be a 32bit version.\n";
#endif
m_engineHandle = nullptr;
}
if (!MATLAB_ENGINE)
{
this->getLogManager() << Kernel::LogLevel_Error << "Could not open the Matlab engine.\nThe matlab binary path was reasoned to be '" << m_matlabPath << "'.\n";
return false;
}
#else
OV_ERROR_KRF("Only Linux and Windows are supported", Kernel::ErrorType::BadVersion);
#endif
return true;
}
bool CBoxAlgorithmMatlabScripting::initialize()
{
m_engineHandle = nullptr;
m_matlabBuffer = nullptr;
m_helper = new CMatlabHelper(this->getLogManager(), this->getErrorManager());
m_clockFrequency = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
for (size_t i = 0; i < getStaticBoxContext().getInputCount(); ++i)
{
CIdentifier type;
getStaticBoxContext().getInputType(i, type);
Toolkit::TDecoder<CBoxAlgorithmMatlabScripting>* decoder = nullptr;
if (type == OV_TypeId_StreamedMatrix) { decoder = new Toolkit::TStreamedMatrixDecoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_ChannelLocalisation) { decoder = new Toolkit::TChannelLocalisationDecoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_FeatureVector) { decoder = new Toolkit::TFeatureVectorDecoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_Spectrum) { decoder = new Toolkit::TSpectrumDecoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_Signal) { decoder = new Toolkit::TSignalDecoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_Stimulations) { decoder = new Toolkit::TStimulationDecoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_ExperimentInfo) { decoder = new Toolkit::TExperimentInfoDecoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else { this->getLogManager() << Kernel::LogLevel_Warning << "Undefined type on input [" << i << "].\n"; }
if (decoder != nullptr)
{
m_decoders.insert(std::make_pair(i, decoder));
m_nInputHeaderSent = 0;
}
}
for (size_t i = 0; i < getStaticBoxContext().getOutputCount(); ++i)
{
CIdentifier type;
getStaticBoxContext().getOutputType(i, type);
Toolkit::TEncoder<CBoxAlgorithmMatlabScripting>* encoder = nullptr;
if (type == OV_TypeId_StreamedMatrix) { encoder = new Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_ChannelLocalisation) { encoder = new Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_FeatureVector) { encoder = new Toolkit::TFeatureVectorEncoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_Spectrum) { encoder = new Toolkit::TSpectrumEncoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_Signal) { encoder = new Toolkit::TSignalEncoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_Stimulations) { encoder = new Toolkit::TStimulationEncoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else if (type == OV_TypeId_ExperimentInfo) { encoder = new Toolkit::TExperimentInfoEncoder<CBoxAlgorithmMatlabScripting>(*this, i); }
else { this->getLogManager() << Kernel::LogLevel_Warning << "Undefined type on input [" << i << "].\n"; }
if (encoder != nullptr)
{
m_encoders.insert(std::make_pair(i, encoder));
m_oHeaderStates.insert(std::make_pair(i, false));
}
}
m_matlabPath = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
#if defined TARGET_OS_Windows
if (!FS::Files::directoryExists(m_matlabPath) && FS::Files::fileExists(m_matlabPath))
{
// The path might be pointing to the executable, try to extract the directory
char parentPath[MAX_PATH];
FS::Files::getParentPath(m_matlabPath, parentPath);
m_matlabPath = CString(parentPath);
}
sanitizePath(m_matlabPath);
this->getLogManager() << Kernel::LogLevel_Trace << "Interpreting Matlab path as '" << m_matlabPath << "'\n";
OV_ERROR_UNLESS_KRF(FS::Files::directoryExists(m_matlabPath), "Configured Matlab path '" << m_matlabPath << "' does not seem to be a directory",
Kernel::ErrorType::BadConfig);
char* path = getenv("PATH");
OV_ERROR_UNLESS_KRF(path, "Could not access the environment variable PATH to add Matlab path to it.", Kernel::ErrorType::BadSetting);
std::string strPath = std::string(path);
size_t found = strPath.find(m_matlabPath.toASCIIString());
if (found == std::string::npos)
{
CString pathModif = path + CString(";") + m_matlabPath;
OV_ERROR_UNLESS_KRF(_putenv_s("PATH", pathModif) == 0, "Failed to modify the environment PATH with the Matlab path.",
Kernel::ErrorType::BadProcessing);
this->getLogManager() << Kernel::LogLevel_Trace << "Matlab Path '" << m_matlabPath << "' added to Windows PATH environment variable.\n";
}
else { this->getLogManager() << Kernel::LogLevel_Trace << "No need to add matlab to PATH\n"; }
#endif
if (!openMatlabEngineSafely()) { return false; }
m_matlabBuffer = new char[MATLAB_BUFFER + 1];
m_matlabBuffer[MATLAB_BUFFER] = '\0';
engOutputBuffer(MATLAB_ENGINE, m_matlabBuffer, MATLAB_BUFFER);
m_errorDetected = false;
// add the openvibe toolbox to matlab path
char curDir[FILENAME_MAX];
OV_ERROR_UNLESS_KRF(getCurrentDir(curDir, FILENAME_MAX), "Failed to get the execution directory.", Kernel::ErrorType::BadProcessing);
std::string curDirString = curDir;
std::replace(curDirString.begin(), curDirString.end(), '\\', '/');
this->getConfigurationManager().addOrReplaceConfigurationToken(CString("Path_Bin_Abs"), CString(curDirString.c_str()));
CString cmd = CString("addpath('") + Directories::getDataDir() + "/plugins/matlab');";
engEvalString(MATLAB_ENGINE, cmd.toASCIIString());
//if(!checkFailureRoutine(engEvalString(m_matlabEngine, (const char * )l_sOpenvibeToolboxPath) == 0, "An error occurred while adding the path to openvibe toolbox\n")) return false;
// If there is more than 1 Matlab box in the scenario, the path is set repeatedly
// resulting in warning messages in the buffer. We don't print them.
// this->printOutputBufferWithFormat();
CString workingDir = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2);
sanitizePath(workingDir);
// Try to find an unused box instance variable name
while (true)
{
std::stringstream ss;
ss.fill('0');
ss << "OV_BOX_0x" << std::setw(8) << std::hex << System::Math::randomI() << "_0x" << std::setw(8) << std::hex << System::Math::randomI();
m_boxInstanceVariableName = ss.str().c_str();
this->getLogManager() << Kernel::LogLevel_Trace << "Checking if variable " << m_boxInstanceVariableName << " is in use...\n";
mxArray* tmp = engGetVariable(MATLAB_ENGINE, m_boxInstanceVariableName.toASCIIString());
if (!tmp)
{
// Found unused name
break;
}
mxDestroyArray(tmp);
}
this->getLogManager() << Kernel::LogLevel_Trace << "Selected variable name " << m_boxInstanceVariableName << "\n";
this->getLogManager() << Kernel::LogLevel_Trace << "Setting working directory to " << workingDir << "\n";
cmd = CString("cd '") + workingDir + CString("'");
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while changing the working directory\n")) { return false; }
// executes the pre-run routine that defines the global identifiers for streams and stimulations codes
cmd = CString("run '") + Directories::getDataDir() + "/plugins/matlab/OV_define.m'";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while calling OV_define.m")) { return false; }
cmd = CString("run '") + Directories::getDataDir() + "/plugins/matlab/OV_stimulations.m'";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while calling OV_stimulations.m")) { return false; }
// executes the pre-run routine that construct the ov_box object
cmd = m_boxInstanceVariableName + " = OV_createBoxInstance(" + std::to_string(this->getStaticBoxContext().getInputCount()).c_str() + ","
+ std::to_string(this->getStaticBoxContext().getOutputCount()).c_str() + ");";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while calling OV_createBoxInstance.m")) { return false; }
//First call to a function of the openvibe toolbox
// if it fails, the toolbox may be not installed
mxArray* box = engGetVariable(MATLAB_ENGINE, m_boxInstanceVariableName.toASCIIString());
OV_ERROR_UNLESS_KRF(box, "Failed to create the box instance with OV_createBoxInstance function.", Kernel::ErrorType::BadProcessing);
m_initializeFunc = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3);
m_processFunc = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 4);
m_uninitializeFunc = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 5);
// Check that the files actually exist
CString filename;
filename = workingDir + m_initializeFunc + ".m";
OV_ERROR_UNLESS_KRF(FS::Files::fileExists(filename.toASCIIString()), "Cannot open '" << filename << "'", Kernel::ErrorType::BadFileRead);
filename = workingDir + m_processFunc + ".m";
OV_ERROR_UNLESS_KRF(FS::Files::fileExists(filename.toASCIIString()), "Cannot open '" << filename << "'", Kernel::ErrorType::BadFileRead);
filename = workingDir + m_uninitializeFunc + ".m";
OV_ERROR_UNLESS_KRF(FS::Files::fileExists(filename.toASCIIString()), "Cannot open '" << filename << "'", Kernel::ErrorType::BadFileRead);
CString names = "{";
CString types = "{";
CString values = "{";
CString tmp;
CIdentifier typeID;
for (size_t i = 6; i < getStaticBoxContext().getSettingCount(); ++i)
{
// get the setting name
getStaticBoxContext().getSettingName(i, tmp);
names = names + "'" + tmp + "' ";
//setting type
getStaticBoxContext().getSettingType(i, typeID);
std::stringstream ss;
ss << typeID.id();
types = types + "uint64(" + ss.str().c_str() + ") ";
//setting value, typed
tmp = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i);
if (typeID == OV_TypeId_Stimulation)
{
uint64_t code = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i);
std::stringstream ss1;
ss1 << code;
values = values + CString(ss1.str().c_str()) + CString(" ");
// we keep the stimulation codes as doubles, to be able to put them in arrays with other doubles (such as timings).
// they are still comparable with uint64_t matlab values.
}
else
{
if (typeID == OV_TypeId_Stimulation || typeID == OV_TypeId_Boolean || typeID == OV_TypeId_Integer || typeID == OV_TypeId_Float)
{
values = values + tmp + " "; // we store the value, these types are readable by matlab directly
}
else { values = values + "'" + tmp + "' "; } // we store them as matlab strings using '
}
}
names += "}";
types += "}";
values += "}";
// On Windows, Matlab doesn't sometimes notice .m files have been changed, esp. if you have matlab box running while you change them
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, "clear functions;") == 0, "An error occurred while calling matlab 'clear functions;'\n"))
{
return false;
}
cmd = m_boxInstanceVariableName + " = OV_setSettings(" + m_boxInstanceVariableName + "," + names + "," + types + "," + values + ");";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd.toASCIIString()) == 0, "Error calling [OV_setSettings]\n")) { return false; }
// we set the box clock frequency in the box structure, so it's accessible in the user scripts if needed
tmp = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
cmd = m_boxInstanceVariableName + ".clock_frequency = " + tmp + ";";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while setting the clock frequency\n")) { return false; }
cmd = m_boxInstanceVariableName + " = " + m_initializeFunc + "(" + m_boxInstanceVariableName + ");";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while calling the initialize function\n")) { return false; }
m_helper->setMatlabEngine(MATLAB_ENGINE);
m_helper->setBoxInstanceVariableName(m_boxInstanceVariableName);
return true;
}
bool CBoxAlgorithmMatlabScripting::closeMatlabEngineSafely()
{
if (MATLAB_ENGINE == nullptr) { return true; }
this->getLogManager() << Kernel::LogLevel_Trace << "Trying to close Matlab engine\n";
#if defined TARGET_OS_Windows
__try
{
#endif
if (MATLAB_ENGINE) { if (engClose(MATLAB_ENGINE) != 0) { this->getLogManager() << Kernel::LogLevel_ImportantWarning << "Could not close Matlab engine.\n"; } }
#if defined TARGET_OS_Windows
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
this->getLogManager() << Kernel::LogLevel_Error << "Closing MATLAB engine failed.\n"
<< "\tTo use this box you must have MATLAB (32 bits version) installed on your computer.\n";
return false;
}
#endif
return true;
}
bool CBoxAlgorithmMatlabScripting::uninitialize()
{
delete m_helper;
if (MATLAB_ENGINE != nullptr)
{
CString cmd = m_boxInstanceVariableName + " = " + m_uninitializeFunc + "(" + m_boxInstanceVariableName + ");";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while calling the uninitialize function\n")
) { } // NOP, we still want to deallocate below
// Remove the box from the matlab workspace
cmd = "clear " + m_boxInstanceVariableName + ";";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, cmd) == 0, "An error occurred while clearing the box\n")
) { } // NOP, we still want to deallocate below
}
closeMatlabEngineSafely();
if (m_matlabBuffer)
{
delete[] m_matlabBuffer;
m_matlabBuffer = nullptr;
}
for (size_t i = 0; i < m_decoders.size(); ++i)
{
m_decoders[i]->uninitialize();
delete m_decoders[i];
}
for (size_t i = 0; i < m_encoders.size(); ++i)
{
m_encoders[i]->uninitialize();
delete m_encoders[i];
}
return true;
}
bool CBoxAlgorithmMatlabScripting::processClock(Kernel::CMessageClock& /*msg*/)
{
if (!MATLAB_ENGINE) { return true; }
const std::string cmd = std::string(m_boxInstanceVariableName) + ".clock = " + std::to_string(CTime(this->getPlayerContext().getCurrentTime()).toSeconds())
+ ";";
OV_ERROR_UNLESS_KRF(engEvalString(MATLAB_ENGINE, cmd.c_str()) == 0, "An error occurred while updating the box clock.", Kernel::ErrorType::BadProcessing);
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
return true;
}
bool CBoxAlgorithmMatlabScripting::process()
{
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
// In openvibe, pointers to managers can change between the calls to process(), so we need to provide current ones every time
m_helper->setManagers(&this->getLogManager(), &this->getErrorManager());
for (size_t i = 0; i < getStaticBoxContext().getInputCount(); ++i)
{
for (size_t j = 0; j < boxContext.getInputChunkCount(i); ++j)
{
m_decoders[i]->decode(j);
CIdentifier type;
getStaticBoxContext().getInputType(i, type);
bool unknownStream = true;
bool receivedSomething = false;
if (m_decoders[i]->isHeaderReceived())
{
receivedSomething = true;
// this->getLogManager() << Kernel::LogLevel_Debug << "Received header\n";
if (type == OV_TypeId_StreamedMatrix)
{
CMatrix* matrix = static_cast<Toolkit::TStreamedMatrixDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputMatrix();
if (!checkFailureRoutine(m_helper->setStreamedMatrixInputHeader(i, matrix), "Error calling [OV_setStreamMatrixInputHeader]\n"))
{
return false;
}
m_nInputHeaderSent++;
unknownStream = false;
}
if (type == OV_TypeId_Signal)
{
CMatrix* matrix = static_cast<Toolkit::TSignalDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputMatrix();
const uint64_t frequency = static_cast<Toolkit::TSignalDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputSamplingRate();
if (!checkFailureRoutine(m_helper->setSignalInputHeader(i, matrix, frequency),
"Error calling [OV_setSignalInputHeader]\n")) { return false; }
m_nInputHeaderSent++;
unknownStream = false;
}
if (type == OV_TypeId_FeatureVector)
{
CMatrix* matrix = static_cast<Toolkit::TFeatureVectorDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputMatrix();
if (!checkFailureRoutine(m_helper->setFeatureVectorInputHeader(i, matrix),
"Error calling [OV_setFeatureVectorInputHeader]\n")) { return false; }
m_nInputHeaderSent++;
unknownStream = false;
}
if (type == OV_TypeId_Spectrum)
{
CMatrix* matrix = static_cast<Toolkit::TSpectrumDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputMatrix();
CMatrix* freqAbscissa = static_cast<Toolkit::TSpectrumDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputFrequencyAbscissa();
const uint64_t frequency = static_cast<Toolkit::TSpectrumDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputSamplingRate();
if (!checkFailureRoutine(m_helper->setSpectrumInputHeader(i, matrix, freqAbscissa, frequency),
"Error calling [OV_setSpectrumInputHeader]\n")) { return false; }
m_nInputHeaderSent++;
unknownStream = false;
}
if (type == OV_TypeId_ChannelLocalisation)
{
CMatrix* matrix = static_cast<Toolkit::TChannelLocalisationDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputMatrix();
const bool dynamic = static_cast<Toolkit::TChannelLocalisationDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputDynamic();
if (!checkFailureRoutine(m_helper->setChannelLocalisationInputHeader(i, matrix, dynamic),
"Error calling [OV_setChannelLocalizationInputHeader]\n")) { return false; }
m_nInputHeaderSent++;
unknownStream = false;
}
if (type == OV_TypeId_ExperimentInfo)
{
OV_WARNING_K(
"The Experiment Information Stream is not implemented with the Matlab Scripting Box. If this is relevant for your usage, please contact the official development Team.")
;
m_nInputHeaderSent++;
unknownStream = false;
}
if (type == OV_TypeId_Stimulations)
{
if (!checkFailureRoutine(m_helper->setStimulationsInputHeader(i), "Error calling [OV_setStimulationsInputHeader]\n")) { return false; }
m_nInputHeaderSent++;
unknownStream = false;
}
}
if (m_decoders[i]->isBufferReceived())
{
// this->getLogManager() << Kernel::LogLevel_Debug << "Received buffer\n";
receivedSomething = true;
//
if (type == OV_TypeId_StreamedMatrix || this->getTypeManager().isDerivedFromStream(type, OV_TypeId_StreamedMatrix))
{
CMatrix* matrix = static_cast<Toolkit::TSignalDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputMatrix();
const uint64_t start = boxContext.getInputChunkStartTime(i, j);
const uint64_t end = boxContext.getInputChunkEndTime(i, j);
if (!checkFailureRoutine(m_helper->addStreamedMatrixInputBuffer(i, matrix, start, end),
"Error calling [OV_addInputBuffer (Streamed Matrix or child stream)]\n")) { return false; }
unknownStream = false;
}
if (type == OV_TypeId_Stimulations)
{
IStimulationSet* stimSet = static_cast<Toolkit::TStimulationDecoder<CBoxAlgorithmMatlabScripting>*>(m_decoders[i])->getOutputStimulationSet();
const uint64_t start = boxContext.getInputChunkStartTime(i, j);
const uint64_t end = boxContext.getInputChunkEndTime(i, j);
if (stimSet->getStimulationCount() > 0)
{
this->getLogManager() << Kernel::LogLevel_Trace << "Inserting stimulation set with size " << stimSet->getStimulationCount() << "\n";
}
if (!checkFailureRoutine(m_helper->addStimulationsInputBuffer(i, stimSet, start, end),
"Error calling [OV_addInputBuffer (Stimulations)]\n")) { return false; }
unknownStream = false;
}
}
if (m_decoders[i]->isEndReceived())
{
this->getLogManager() << Kernel::LogLevel_Info << "Received end\n";
receivedSomething = true;
unknownStream = false;
// @FIXME should something additional be done here?
}
OV_ERROR_UNLESS_KRF(!receivedSomething || !unknownStream, "Unknown Stream Type " << type.str() << " on input [" << i << "].",
Kernel::ErrorType::BadProcessing);
}
}
if (m_nInputHeaderSent < getStaticBoxContext().getInputCount())
{
// not ready to process
return true;
}
// CALL TO PROCESS FUNCTION
std::string command = std::string(m_boxInstanceVariableName.toASCIIString()) + " = " + m_processFunc.toASCIIString() + "("
+ m_boxInstanceVariableName.toASCIIString() + ");";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, command.c_str()) == 0, "Error calling the Process function.\n")) { return false; }
// Go through every output in the matlab box and copy the data to the C++ side
for (size_t i = 0; i < getStaticBoxContext().getOutputCount(); ++i)
{
// now we check for pending output chunk to be sent (output type independent call)
command = std::string("OV_PENDING_COUNT_TMP = OV_getNbPendingOutputChunk(") + m_boxInstanceVariableName.toASCIIString() + ", "
+ std::to_string(i + 1) + ");";
if (!checkFailureRoutine(engEvalString(MATLAB_ENGINE, command.c_str()) == 0, "Error calling [OV_getNbPendingOutputChunk].\n")) { return false; }
mxArray* pending = engGetVariable(MATLAB_ENGINE, "OV_PENDING_COUNT_TMP");
const double dPending = *mxGetPr(pending);
CIdentifier typeID;
getStaticBoxContext().getOutputType(i, typeID);
for (size_t c = 0; c < size_t(dPending); ++c)
{
// If no header were ever sent, we need to extract header information in the matlab box
// This header must have been set prior to sending the very first buffer.
// @FIXME the practice used below of assigning to getters is nasty, it should be refactored to e.g. using getter/setter pairs
if (!m_oHeaderStates[i])
{
bool unknownType = true;
if (typeID == OV_TypeId_StreamedMatrix)
{
CMatrix* matrixToSend = static_cast<Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputMatrix();
if (!checkFailureRoutine(m_helper->getStreamedMatrixOutputHeader(i, matrixToSend),
"Error calling [OV_getStreamedMatrixOutputHeader]. Did you correctly set the output header in the matlab structure ?\n")
) { return false; }
unknownType = false;
}
else if (typeID == OV_TypeId_Signal)
{
CMatrix* matrixToSend = static_cast<Toolkit::TSignalEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputMatrix();
uint64_t sampling = static_cast<Toolkit::TSignalEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputSamplingRate();
if (!checkFailureRoutine(m_helper->getSignalOutputHeader(i, matrixToSend, sampling),
"Error calling [OV_getSignalOutputHeader]. Did you correctly set the output header in the matlab structure ?\n")
) { return false; }
// Set the new sampling rate
static_cast<Toolkit::TSignalEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputSamplingRate() = sampling;
unknownType = false;
}
else if (typeID == OV_TypeId_FeatureVector)
{
CMatrix* matrixToSend = static_cast<Toolkit::TFeatureVectorEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputMatrix();
if (!checkFailureRoutine(m_helper->getFeatureVectorOutputHeader(i, matrixToSend),
"Error calling [OV_getFeatureVectorOutputHeader]. Did you correctly set the output header in the matlab structure ?\n")
) { return false; }
unknownType = false;
}
else if (typeID == OV_TypeId_Spectrum)
{
CMatrix* matrixToSend = static_cast<Toolkit::TSpectrumEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputMatrix();
CMatrix* freqAbscissa = static_cast<Toolkit::TSpectrumEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputFrequencyAbscissa();
uint64_t frequency = static_cast<Toolkit::TSpectrumEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputSamplingRate();
if (!checkFailureRoutine(m_helper->getSpectrumOutputHeader(i, matrixToSend, freqAbscissa, frequency),
"Error calling [OV_getSpectrumOutputHeader]. Did you correctly set the output header in the matlab structure ?\n")
) { return false; }
unknownType = false;
}
else if (typeID == OV_TypeId_ChannelLocalisation)
{
CMatrix* matrixToSend = static_cast<Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputMatrix();
bool dynamic = static_cast<Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputDynamic();
if (!checkFailureRoutine(m_helper->getChannelLocalisationOutputHeader(i, matrixToSend, dynamic),
"Error calling [OV_getChannelLocalizationOutputHeader]. Did you correctly set the output header in the matlab structure ?\n")
) { return false; }
// Set the new channel localisation
static_cast<Toolkit::TChannelLocalisationEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputDynamic() = dynamic;
unknownType = false;
}
else if (typeID == OV_TypeId_ExperimentInfo)
{
OV_WARNING_K(
"The Experiment Information Stream is not implemented with the Matlab Scripting Box. If this is relevant for your usage, please contact the official development Team.")
;
unknownType = false;
}
else if (typeID == OV_TypeId_Stimulations)
{
IStimulationSet* stimSet = static_cast<Toolkit::TStimulationEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputStimulationSet();
if (!checkFailureRoutine(m_helper->getStimulationsOutputHeader(i, stimSet),
"Error calling [OV_getStimulationsOutputHeader]. Did you correctly set the output header in the matlab structure ?\n")
) { return false; }
unknownType = false;
}
OV_ERROR_UNLESS_KRF(!unknownType, "Unknown Stream Type on output [" << i << "].", Kernel::ErrorType::BadProcessing);
m_encoders[i]->encodeHeader();
boxContext.markOutputAsReadyToSend(i, 0, 0);
m_oHeaderStates[i] = true;
}
bool unknownType = true;
uint64_t start = 0;
uint64_t end = 0;
if (typeID == OV_TypeId_StreamedMatrix || this->getTypeManager().isDerivedFromStream(typeID, OV_TypeId_StreamedMatrix))
{
CMatrix* matrixToSend = static_cast<Toolkit::TStreamedMatrixEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputMatrix();
if (!checkFailureRoutine(m_helper->popStreamedMatrixOutputBuffer(i, matrixToSend, start, end),
"Error calling [OV_popOutputBufferReshape] for Streamed Matrix stream or child stream.\n")) { return false; }
unknownType = false;
}
if (typeID == OV_TypeId_Stimulations)
{
IStimulationSet* stimSet = static_cast<Toolkit::TStimulationEncoder<CBoxAlgorithmMatlabScripting>*>(m_encoders[i])->getInputStimulationSet();
stimSet->clear();
if (!checkFailureRoutine(m_helper->popStimulationsOutputBuffer(i, stimSet, start, end),
"Error calling [OV_popOutputBuffer] for Stimulation stream.\n")) { return false; }
unknownType = false;
}
OV_ERROR_UNLESS_KRF(!unknownType, "Unknown Stream Type on output [" << i << "].", Kernel::ErrorType::BadProcessing);
m_encoders[i]->encodeBuffer();
boxContext.markOutputAsReadyToSend(i, start, end);
}
mxDestroyArray(pending);
}
return true;
}
bool CBoxAlgorithmMatlabScripting::processInput(const size_t /*index*/)
{
OV_ERROR_UNLESS_KRF(getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess(),
"Error while marking algorithm as ready to process", Kernel::ErrorType::Internal);
return true;
}
bool CBoxAlgorithmMatlabScripting::printOutputBufferWithFormat()
{
// the buffer for the console
// @FIXME allow seeing more of the error message!
std::stringstream ss;
ss << m_matlabBuffer;
if (!ss.str().empty())
{
const size_t errIdx1 = ss.str().find("??? ");
const size_t errIdx2 = ss.str().find("Error: ");
const size_t errIdx3 = ss.str().find("Error ");
// Find the earliest error message
size_t errIdx = std::string::npos;
if (errIdx == std::string::npos || (errIdx1 != std::string::npos && errIdx1 < errIdx)) { errIdx = errIdx1; }
if (errIdx == std::string::npos || (errIdx2 != std::string::npos && errIdx2 < errIdx)) { errIdx = errIdx2; }
if (errIdx == std::string::npos || (errIdx3 != std::string::npos && errIdx3 < errIdx)) { errIdx = errIdx3; }
size_t warnIdx = ss.str().find("Warning: ");
if (errIdx == std::string::npos && warnIdx == std::string::npos)
{
this->getLogManager() << Kernel::LogLevel_Info << "\n---- MATLAB BUFFER - INFO ----\n" << ss.str().substr(0, (warnIdx < errIdx) ? warnIdx : errIdx) << "\n";
}
if (warnIdx != std::string::npos)
{
this->getLogManager() << Kernel::LogLevel_Warning << "\n---- MATLAB BUFFER - WARNING ----\n" << ss.str().substr(warnIdx, errIdx) << "\n";
}
if (errIdx != std::string::npos)
{
this->getLogManager() << Kernel::LogLevel_Error << "\n---- MATLAB BUFFER - ERROR ! ----\n" << ss.str().substr(errIdx) << "\n";
m_errorDetected = true;
}
}
return true;
}
} // namespace Matlab
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyMatlab
@@ -0,0 +1,155 @@
#pragma once
#if defined TARGET_HAS_ThirdPartyMatlab
#include "../ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include "../ovpCMatlabHelper.h"
#include <map>
namespace OpenViBE {
namespace Plugins {
namespace Matlab {
class CBoxAlgorithmMatlabScripting final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
{
public:
void release() override { delete this; }
uint64_t getClockFrequency() override { return m_clockFrequency << 32; }
bool initialize() override;
bool uninitialize() override;
bool processClock(Kernel::CMessageClock& msg) override;
bool process() override;
bool processInput(const size_t index) override;
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_MatlabScripting)
private:
bool openMatlabEngineSafely();
bool closeMatlabEngineSafely();
uint64_t m_clockFrequency = 0;
std::map<size_t, Toolkit::TDecoder<CBoxAlgorithmMatlabScripting>*> m_decoders;
size_t m_nInputHeaderSent = 0;
std::map<size_t, Toolkit::TEncoder<CBoxAlgorithmMatlabScripting>*> m_encoders;
std::map<size_t, bool> m_oHeaderStates;
void* m_engineHandle = nullptr;
CString m_boxInstanceVariableName; //must be unique
CMatlabHelper* m_helper = nullptr;
CString m_matlabPath; // On Linux, path of the executable. On Windows, the executable directory.
CString m_processFunc;
CString m_initializeFunc;
CString m_uninitializeFunc;
char* m_matlabBuffer = nullptr;
bool m_errorDetected = false;
bool printOutputBufferWithFormat();
bool checkFailureRoutine(bool result, const CString& msg);
static void sanitizePath(CString& pathToModify);
//void sendOutputHeader(CIdentifier idOutputType);
//void sendOutputBuffer(CIdentifier idOutputType);
};
class CBoxAlgorithmMatlabScriptingListener final : public Toolkit::TBoxListener<IBoxListener>
{
public:
bool onSettingTypeChanged(Kernel::IBox& box, const size_t index) override
{
//we must have the first STATIC_SETTINGS_COUNT settings
if (index < 6)
{
this->getLogManager() << Kernel::LogLevel_Warning << "One of the predefined setting has changed type, falling back to default.\n";
box.setSettingType(index, OV_TypeId_String); // they are all strings
}
return true;
}
bool onSettingValueChanged(Kernel::IBox& box, const size_t index) override
{
//we must have the first STATIC_SETTINGS_COUNT settings
CString str;
box.getSettingValue(0, str);
const uint64_t value = atoi(str.toASCIIString());
if (index == 0 && (value < 1 || value > 128))
{
OV_WARNING_K("Clock Frequency must be an integer between 1 and 128 Hz. Falling back to default.");
box.setSettingValue(index, "64");
}
return true;
}
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
};
class CBoxAlgorithmMatlabScriptingDesc final : virtual public IBoxAlgorithmDesc
{
public:
void release() override { }
CString getName() const override { return CString("Matlab Scripting"); }
CString getAuthorName() const override { return CString("L. Bonnet"); }
CString getAuthorCompanyName() const override { return CString("INRIA"); }
CString getShortDescription() const override { return CString("Executes matlab scripts. To be used correctly, you must have Matlab installed."); }
CString getDetailedDescription() const override
{
return CString(
"User must implement the matlab functions:\n[box_out]=bci_Initialize(box_in)\n[box_out]=bci_Process(box_in)\n[box_out]=bci_Uninitialize(box_in)\nPlease refer to the dedicated documentation <openvibe.inria.fr/tutorial-using-matlab-with-openvibe> for more information.");
}
CString getCategory() const override { return CString("Scripting"); }
CString getVersion() const override { return CString("1.0"); }
CString getStockItemName() const override { return CString("gtk-execute"); }
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_MatlabScripting; }
IPluginObject* create() override { return new CBoxAlgorithmMatlabScripting; }
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
{
prototype.addSetting("Box clock frequency in Hz", OV_TypeId_Integer, "64");
#if defined TARGET_OS_Linux
prototype.addSetting("Matlab executable (path)", OV_TypeId_Filename, "[ssh user@host] /path/to/matlab");
#elif defined TARGET_OS_Windows
// On Windows, the executable is not actually used, but its path is parsed from it and added to PATH.
// Background: Matlab's engOpen() takes a different argument on Windows and on Linux. On Windows, we need to have Matlab
// on PATH, in Linux we need to provide a full path of the executable. However, we'd like our example scenarios to give
// correct instructions to the user on both platforms, hence we use a setting that contains the information for both use-cases.
prototype.addSetting("Matlab executable (path)", OV_TypeId_Filename, "C:/Program Files (x86)/MATLAB/R2013b/bin/win32/matlab.exe");
#else
#endif
prototype.addSetting("Matlab working directory", OV_TypeId_String, "${Player_ScenarioDirectory}");
prototype.addSetting("Initialize function", OV_TypeId_String, "matlab_Initialize");
prototype.addSetting("Process function", OV_TypeId_String, "matlab_Process");
prototype.addSetting("Uninitialize function", OV_TypeId_String, "matlab_Uninitialize");
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
prototype.addFlag(Kernel::BoxFlag_CanAddOutput);
prototype.addFlag(Kernel::BoxFlag_CanModifyOutput);
prototype.addFlag(Kernel::BoxFlag_CanAddSetting);
prototype.addFlag(Kernel::BoxFlag_CanModifySetting);
//prototype.addFlag(OV_AttributeId_Box_FlagIsUnstable);
return true;
}
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmMatlabScriptingListener; }
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_MatlabScriptingDesc)
};
} // namespace Matlab
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyMatlab
@@ -0,0 +1,493 @@
#if defined TARGET_HAS_ThirdPartyMatlab
#include "ovpCMatlabHelper.h"
#include <iostream>
#include <sstream>
#include <mex.h>
//#include <engine.h>
#include <string>
#if defined TARGET_OS_Windows
#include <windows.h>
#endif
namespace OpenViBE {
namespace Plugins {
namespace Matlab {
//---------------------------------------------------------------------------------------------------------------
static std::string escapeMatlabString(const char* sStringToEscape)
{
std::string str = std::string(sStringToEscape);
auto it = str.begin();
while (it != str.end())
{
if (*it == '\'')
{
str.insert(it, '\'');
++it;
}
++it;
}
return str;
}
static std::string genLabelsList(CMatrix* matrix, const size_t axis = 0)
{
std::string labelsList;
for (size_t i = 0; i < matrix->getDimensionSize(axis); ++i)
{
labelsList += std::string("'") + escapeMatlabString(matrix->getDimensionLabel(axis, i)) + "' ";
}
return labelsList;
}
static uint64_t convertFromMArray(mxArray* array, const size_t index)
{
const double* ptr = ::mxGetPr(array);
const double timeValue = double(ptr[index]);
return CTime(timeValue).time();
}
static uint64_t castFromMArray(mxArray* array, const size_t index)
{
const double* ptr = ::mxGetPr(array);
const double value = double(ptr[index]);
return uint64_t(value);
}
static CString getNameFromCell(mxArray* names, const size_t index)
{
mxArray* cell = mxGetCell(names, index);
if (!cell) { return CString(""); }
const mwSize* cellSizes = mxGetDimensions(cell);
char* name = new char[cellSizes[1] + 1];
name[cellSizes[1]] = '\0';
for (size_t cellsize = 0; cellsize < size_t(cellSizes[1]); ++cellsize) { name[cellsize] = static_cast<char*>(mxGetData(cell))[cellsize * 2]; }
CString res = name;
delete name;
return res;
}
std::vector<CString> CMatlabHelper::getNamelist(const char* name) const
{
std::vector<CString> res;
mxArray* marray = engGetVariable(m_matlabEngine, name);
if (!marray)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [" << name << "]\n";
return res;
}
const mwSize nbCells = mxGetNumberOfElements(marray);
for (size_t cell = 0; cell < nbCells; ++cell) { res.push_back(getNameFromCell(marray, cell)); }
mxDestroyArray(marray);
return res;
}
uint32_t CMatlabHelper::getUi32FromEnv(const char* name) const
{
mxArray* marray = engGetVariable(m_matlabEngine, name);
if (!marray)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [" << name << "]\n";
return 0;
}
const uint32_t res = uint32_t(*mxGetPr(marray));
mxDestroyArray(marray);
return res;
}
uint64_t CMatlabHelper::getUi64FromEnv(const char* name) const
{
mxArray* marray = engGetVariable(m_matlabEngine, name);
if (!marray)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [" << name << "]\n";
return 0;
}
const uint64_t res = uint64_t(*mxGetPr(marray));
mxDestroyArray(marray);
return res;
}
uint64_t CMatlabHelper::genUi64FromEnvConverted(const char* name) const
{
mxArray* marray = engGetVariable(m_matlabEngine, name);
if (!marray)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [" << name << "]\n";
return 0;
}
const double value = double(*mxGetPr(marray));
const uint64_t res = CTime(value).time();
mxDestroyArray(marray);
return res;
}
//---------------------------------------------------------------------------------------------------------------
bool CMatlabHelper::setStreamedMatrixInputHeader(const size_t index, CMatrix* matrix) const
{
std::string labelList;
std::string dimensionSizes;
for (size_t dim = 0; dim < matrix->getDimensionCount(); ++dim)
{
dimensionSizes += std::to_string(matrix->getDimensionSize(dim)) + " ";
labelList += std::string("{") + genLabelsList(matrix, dim) + "} ";
}
//function box_out = OV_setStreamedMatrixInputInputHeader(box_in, input_index, dimension_count, dimension_sizes, dimension_labels)
const std::string cmd = std::string(m_boxInstanceVariableName) + " = OV_setStreamedMatrixInputHeader(" + m_boxInstanceVariableName.toASCIIString() + ","
+ std::to_string(index + 1) + "," + std::to_string(matrix->getDimensionCount()) + "," + "[" + dimensionSizes + "],"
+ "{" + labelList + "});";
return engEvalString(m_matlabEngine, cmd.c_str()) == 0;
}
bool CMatlabHelper::setFeatureVectorInputHeader(const size_t index, CMatrix* matrix) const
{
const std::string labelList = genLabelsList(matrix, 0);
//function box_out = OV_setStreamedMatrixInputInputHeader(box_in, input_index, dimension_count, dimension_sizes, dimension_labels)
//box_out = OV_setFeatureVectorInputHeader(box_in, input_index, nb_features, labels)
const std::string cmd = std::string(m_boxInstanceVariableName.toASCIIString()) + " = OV_setFeatureVectorInputHeader("
+ m_boxInstanceVariableName.toASCIIString() + "," + std::to_string(index + 1) + ","
+ std::to_string(matrix->getDimensionSize(0)) + "," + "{" + labelList + "});";
return engEvalString(m_matlabEngine, cmd.c_str()) == 0;
}
bool CMatlabHelper::setSignalInputHeader(const size_t index, CMatrix* matrix, const uint64_t frequency) const
{
const std::string labelList = genLabelsList(matrix, 0);
//function box_out = ov_set_signal_input_header(box_in, input_index, nb_channel, nb_samples_per_buffer, channel_names, sampling_rate)
const std::string cmd = std::string(m_boxInstanceVariableName) + " = OV_setSignalInputHeader(" + m_boxInstanceVariableName.toASCIIString() + ","
+ std::to_string(index + 1) + "," + std::to_string(matrix->getDimensionSize(0)) + ","
+ std::to_string(matrix->getDimensionSize(1)) + "," + "{" + labelList + "}," + std::to_string(frequency) + ");";
return engEvalString(m_matlabEngine, cmd.c_str()) == 0;
}
bool CMatlabHelper::setChannelLocalisationInputHeader(const size_t index, CMatrix* matrix, const bool dynamic) const
{
const std::string labelList = genLabelsList(matrix, 0);
//function box_out = OV_setChannelLocalisationInputHeader(box_in, input_index, nb_channels, channel_names, dynamic)
const std::string cmd = std::string(m_boxInstanceVariableName) + " = OV_setChannelLocalisationInputHeader(" + m_boxInstanceVariableName.toASCIIString()
+ "," + std::to_string(index + 1) + "," + std::to_string(matrix->getDimensionSize(0)) + "," + "{" + labelList + "},"
+ (dynamic ? "true" : "false") + ");";
return engEvalString(m_matlabEngine, cmd.c_str()) == 0;
}
bool CMatlabHelper::setSpectrumInputHeader(const size_t index, CMatrix* matrix, CMatrix* frequencyAbscissa, const uint64_t frequency) const
{
const std::string labelList = genLabelsList(matrix, 0);
const std::string abscissaList = genLabelsList(matrix, 1);
// @FIXME CERT this is now one dim array
mxArray* matlabMatrix = ::mxCreateDoubleMatrix(frequencyAbscissa->getDimensionSize(0), 1, mxREAL);
memcpy(mxGetPr(matlabMatrix), frequencyAbscissa->getBuffer(), frequencyAbscissa->getBufferElementCount() * sizeof(double));
engPutVariable(m_matlabEngine, "OV_MATRIX_TMP", matlabMatrix);
mxDestroyArray(matlabMatrix);
//box_out = OV_setSpectrumInputHeader(box_in, input_index, nb_channels, channel_names, nb_bands, band_names, bands, sampling_rate)
const std::string cmd = std::string(m_boxInstanceVariableName.toASCIIString()) + " = OV_setSpectrumInputHeader("
+ std::string(m_boxInstanceVariableName.toASCIIString()) + ","
+ std::to_string(index + 1) + "," // input_index
+ std::to_string(matrix->getDimensionSize(0)) + "," // nb_channels
+ "{" + labelList + "}," // channel_names
+ std::to_string(matrix->getDimensionSize(1)) + "," // nb_freq abscissa
+ "{" + abscissaList + "}," //freq abscissa names
+ "OV_MATRIX_TMP," //bands
+ std::to_string(frequency) + ");"; //sampling rate
return engEvalString(m_matlabEngine, cmd.c_str()) == 0;
}
bool CMatlabHelper::setStimulationsInputHeader(const size_t index) const
{
//box_out = OV_setStimulationInputHeader(box_in, input_index)
const std::string cmd = std::string(m_boxInstanceVariableName) + " = OV_setStimulationsInputHeader(" + m_boxInstanceVariableName.toASCIIString() + "," +
std::to_string(index + 1) + ");";
return engEvalString(m_matlabEngine, cmd.c_str()) == 0;
}
//bool setExperimentInfoInputHeader(CMatrix * pMatrix);
//---------------------------------------------------------------------------------------------------------------
bool CMatlabHelper::addStreamedMatrixInputBuffer(const size_t index, CMatrix* matrix, const uint64_t startTime, const uint64_t endTime) const
{
mwSize* dims = new mwSize[matrix->getDimensionCount()];
size_t j = matrix->getDimensionCount() - 1;
for (size_t i = 0; i < matrix->getDimensionCount(); ++i)
{
dims[i] = matrix->getDimensionSize(j);
j--;
}
mxArray* matlabMatrix = ::mxCreateNumericArray(matrix->getDimensionCount(), dims, mxDOUBLE_CLASS, mxREAL);
//test : channel 1 samples to '10'
//for (size_t i = 0; i < 32;i++) matrix->getBuffer()[i] = 10;
memcpy(mxGetPr(matlabMatrix), matrix->getBuffer(), matrix->getBufferElementCount() * sizeof(double));
engPutVariable(m_matlabEngine, "OV_MATRIX_TMP", matlabMatrix);
mxDestroyArray(matlabMatrix);
const std::string cmd = std::string(m_boxInstanceVariableName) + " = OV_addInputBuffer(" + m_boxInstanceVariableName.toASCIIString() + ","
+ std::to_string(index + 1) + ","
+ std::to_string(CTime(startTime).toSeconds()) + ","
+ std::to_string(CTime(endTime).toSeconds()) + ",OV_MATRIX_TMP');";
// please note the transpose operator ' to put the matrix with 1 channel per line
delete[] dims;
return engEvalString(m_matlabEngine, cmd.c_str()) == 0;
}
bool CMatlabHelper::addStimulationsInputBuffer(const size_t index, IStimulationSet* stimSet, const uint64_t startTime, const uint64_t endTime) const
{
if (stimSet->getStimulationCount() == 0 && engEvalString(m_matlabEngine, "OV_MATRIX_TMP = 0") != 0) { return false; }
// we create a 3xN matrix for N stims (access is easier in that order)
mxArray* matrix = ::mxCreateDoubleMatrix(3, size_t(stimSet->getStimulationCount()), mxREAL);
for (size_t i = 0; i < stimSet->getStimulationCount(); ++i)
{
::mxGetPr(matrix)[i * 3] = double(stimSet->getStimulationIdentifier(i));
::mxGetPr(matrix)[i * 3 + 1] = CTime(stimSet->getStimulationDate(i)).toSeconds();
::mxGetPr(matrix)[i * 3 + 2] = CTime(stimSet->getStimulationDuration(i)).toSeconds();
}
engPutVariable(m_matlabEngine, "OV_MATRIX_TMP", matrix);
mxDestroyArray(matrix);
const std::string cmd = std::string(m_boxInstanceVariableName) + " = OV_addInputBuffer(" + m_boxInstanceVariableName.toASCIIString() + ","
+ std::to_string(index + 1) + ","
+ std::to_string(CTime(startTime).toSeconds()) + ","
+ std::to_string(CTime(endTime).toSeconds()) + ",OV_MATRIX_TMP');";
return (engEvalString(m_matlabEngine, cmd.c_str()) == 0);
}
//---------------------------------------------------------------------------------------------------------------
bool CMatlabHelper::getStreamedMatrixOutputHeader(const size_t index, CMatrix* matrix) const
{
const std::string cmd = std::string("[OV_ERRNO, OV_NB_DIMENSIONS, OV_DIMENSION_SIZES, OV_DIMENSION_LABELS] = OV_getStreamedMatrixOutputHeader(")
+ m_boxInstanceVariableName.toASCIIString() + "," + std::to_string(index + 1) + ");";
OV_ERROR_UNLESS_KRF(engEvalString(m_matlabEngine, cmd.c_str()) == 0 && getUi32FromEnv("OV_ERRNO") == 0,
"Could not get Streamed matrix output header", Kernel::ErrorType::BadProcessing);
const size_t nDimension = getUi32FromEnv("OV_NB_DIMENSIONS");
mxArray* dimensionSizes = engGetVariable(m_matlabEngine, "OV_DIMENSION_SIZES");
if (!dimensionSizes)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [OV_DIMENSION_SIZES]\n";
return false;
}
std::vector<CString> nameList = getNamelist("OV_DIMENSION_LABELS");
matrix->setDimensionCount(nDimension);
size_t idx = 0;
for (size_t i = 0; i < nDimension; ++i)
{
matrix->setDimensionSize(i, size_t(mxGetPr(dimensionSizes)[i]));
for (size_t x = 0; x < matrix->getDimensionSize(i) && idx < nameList.size(); ++x)
{
matrix->setDimensionLabel(i, x, escapeMatlabString(nameList[idx].toASCIIString()).c_str());
idx++;
}
}
mxDestroyArray(dimensionSizes);
return true;
}
bool CMatlabHelper::getFeatureVectorOutputHeader(const size_t index, CMatrix* matrix) const
{
const std::string cmd = std::string("[OV_ERRNO, OV_NB_FEATURES, OV_LABELS] = OV_getFeatureVectorOutputHeader(")
+ m_boxInstanceVariableName.toASCIIString() + "," + std::to_string(index + 1) + ");";
OV_ERROR_UNLESS_KRF(engEvalString(m_matlabEngine, cmd.c_str()) == 0 && getUi32FromEnv("OV_ERRNO") == 0,
"Could not get Feature Vector output header",
Kernel::ErrorType::BadProcessing);
const size_t nbFeatures = getUi32FromEnv("OV_NB_FEATURES");
std::vector<CString> nameList = getNamelist("OV_LABELS");
// Check nb features == nb names ?
matrix->resize(nbFeatures);
for (size_t x = 0; x < nbFeatures; ++x) { matrix->setDimensionLabel(0, x, escapeMatlabString(nameList[x].toASCIIString()).c_str()); }
return true;
}
bool CMatlabHelper::getSignalOutputHeader(const size_t index, CMatrix* matrix, uint64_t& frequency) const
{
const std::string cmd = std::string("[OV_ERRNO, OV_NB_CHANNELS, OV_NB_SAMPLES_PER_BUFFER, OV_CHANNEL_NAMES, OV_SAMPLING_RATE] = OV_getSignalOutputHeader(")
+ m_boxInstanceVariableName.toASCIIString() + "," + std::to_string(index + 1) + ");";
OV_ERROR_UNLESS_KRF(engEvalString(m_matlabEngine, cmd.c_str()) == 0 && getUi32FromEnv("OV_ERRNO") == 0, "Could not get Signal output header",
Kernel::ErrorType::BadProcessing);
const size_t nbChannels = getUi32FromEnv("OV_NB_CHANNELS");
const size_t nbSamples = getUi32FromEnv("OV_NB_SAMPLES_PER_BUFFER");
std::vector<CString> nameList = getNamelist("OV_CHANNEL_NAMES");
const size_t rate = getUi32FromEnv("OV_SAMPLING_RATE");
if (nameList.size() != nbChannels) { return false; }
matrix->resize(nbChannels, nbSamples);
frequency = rate;
for (size_t x = 0; x < nbChannels; ++x) { matrix->setDimensionLabel(0, x, escapeMatlabString(nameList[x].toASCIIString()).c_str()); }
return true;
}
bool CMatlabHelper::getChannelLocalisationOutputHeader(const size_t index, CMatrix* matrix, bool& /*dynamic*/) const
{
const std::string cmd = std::string("[OV_ERRNO, OV_NB_CHANNELS, OV_CHANNEL_NAMES, OV_DYNAMIC] = OV_getChannelLocalisationOutputHeader(")
+ m_boxInstanceVariableName.toASCIIString() + "," + std::to_string(index + 1) + ");";
OV_ERROR_UNLESS_KRF(engEvalString(m_matlabEngine, cmd.c_str()) == 0 && getUi32FromEnv("OV_ERRNO") == 0,
"Could not get Channel Localisation output header", Kernel::ErrorType::BadProcessing);
const size_t nChannel = getUi32FromEnv("OV_NB_CHANNELS");
std::vector<CString> nameList = getNamelist("OV_CHANNEL_NAMES");
mxArray* dynamic = engGetVariable(m_matlabEngine, "OV_DYNAMIC");
if (!dynamic)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [OV_DYNAMIC]\n";
return false;
}
if (nameList.size() != nChannel) { return false; }
matrix->resize(nChannel, 3);
for (size_t x = 0; x < nChannel; ++x) { matrix->setDimensionLabel(0, x, escapeMatlabString(nameList[x].toASCIIString()).c_str()); }
mxDestroyArray(dynamic);
return true;
}
bool CMatlabHelper::getSpectrumOutputHeader(const size_t index, CMatrix* matrix, CMatrix* frequencyAbscissa, uint64_t& frequency) const
{
const std::string command = std::string(
"[OV_ERRNO, OV_NB_CHANNELS, OV_CHANNEL_NAMES, OV_NB_BANDS, OV_BANDS_NAME, OV_BANDS_LINEAR, OV_SAMPLING_RATE] = OV_getSpectrumOutputHeader(")
+ m_boxInstanceVariableName.toASCIIString() + "," + std::to_string(index + 1) + ");";
OV_ERROR_UNLESS_KRF(engEvalString(m_matlabEngine, command.c_str()) == 0 && getUi32FromEnv("OV_ERRNO") == 0,
"Could not get Spectrum output header", Kernel::ErrorType::BadProcessing);
const size_t nChannel = getUi32FromEnv("OV_NB_CHANNELS");
std::vector<CString> nameList = getNamelist("OV_CHANNEL_NAMES");
const size_t nAbscissa = getUi32FromEnv("OV_NB_ABSCISSAS");
std::vector<CString> freqAbscissaNames = getNamelist("OV_ABSCISSAS_NAME");
mxArray* freqAbscissa = engGetVariable(m_matlabEngine, "OV_ABSCISSAS_LINEAR");
if (!freqAbscissa)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [OV_ABSCISSAS_LINEAR]\n";
return false;
}
frequency = getUi64FromEnv("OV_SAMPLING_RATE");
//The Frequency abscissa list has dimensions nb_bands
frequencyAbscissa->resize(nAbscissa);
for (size_t x = 0; x < nAbscissa; ++x) { frequencyAbscissa->setDimensionLabel(0, x, escapeMatlabString(freqAbscissaNames[x].toASCIIString()).c_str()); }
// Adding the bands:
memcpy(frequencyAbscissa->getBuffer(), ::mxGetPr(freqAbscissa), nAbscissa * sizeof(double));
matrix->resize(nChannel, nAbscissa);
for (size_t x = 0; x < nChannel; ++x) { matrix->setDimensionLabel(0, x, escapeMatlabString(nameList[x].toASCIIString()).c_str()); }
for (size_t x = 0; x < nAbscissa; ++x) { matrix->setDimensionLabel(1, x, escapeMatlabString(freqAbscissaNames[x].toASCIIString()).c_str()); }
// @FIXME CERT is it me or it never copy data to matrix ?
mxDestroyArray(freqAbscissa);
return true;
}
bool CMatlabHelper::getStimulationsOutputHeader(size_t /*index*/, IStimulationSet* /*stimulationSet*/)
{
// Nothing to do, the stimulation header is empty.
return true;
}
//---------------------------------------------------------------------------------------------------------------
bool CMatlabHelper::popStreamedMatrixOutputBuffer(const size_t index, CMatrix* matrix, uint64_t& startTime, uint64_t& endTime) const
{
const std::string buf = std::string("[") + m_boxInstanceVariableName.toASCIIString()
+ ", OV_START_TIME, OV_END_TIME, OV_LINEAR_DATA_SIZE, OV_LINEAR_DATA] = OV_popOutputBufferReshape("
+ m_boxInstanceVariableName.toASCIIString() + ", " + std::to_string(index + 1) + ");";
const size_t res = engEvalString(m_matlabEngine, buf.c_str());
if (res != 0) { return false; }
startTime = genUi64FromEnvConverted("OV_START_TIME");
endTime = genUi64FromEnvConverted("OV_END_TIME");
const uint64_t size = getUi64FromEnv("OV_LINEAR_DATA_SIZE");
mxArray* data = engGetVariable(m_matlabEngine, "OV_LINEAR_DATA");
if (!data)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [OV_LINEAR_DATA]\n";
return false;
}
// ti be copied direclty in openvibe buffer, the linear matrix must be ordered line by line
memcpy(matrix->getBuffer(), ::mxGetPr(data), size * sizeof(double));
mxDestroyArray(data);
return true;
}
bool CMatlabHelper::popStimulationsOutputBuffer(const size_t index, IStimulationSet* stimSet, uint64_t& startTime, uint64_t& endTime) const
{
const std::string buf = std::string("[") + m_boxInstanceVariableName.toASCIIString()
+ ", OV_START_TIME, OV_END_TIME, OV_LINEAR_MATRIX_SIZE, OV_LINEAR_DATA] = OV_popOutputBuffer("
+ m_boxInstanceVariableName.toASCIIString() + ", " + std::to_string(index + 1) + ");";
const size_t res = engEvalString(m_matlabEngine, buf.c_str());
if (res != 0) { return false; }
startTime = genUi64FromEnvConverted("OV_START_TIME");
endTime = genUi64FromEnvConverted("OV_END_TIME");
const size_t size = getUi32FromEnv("OV_LINEAR_MATRIX_SIZE");
mxArray* data = engGetVariable(m_matlabEngine, "OV_LINEAR_DATA");
if (!data)
{
this->getLogManager() << Kernel::LogLevel_Error << "Nonexisting variable [OV_LINEAR_DATA]\n";
return false;
}
for (size_t i = 0; i < size; i += 3)
{
const uint64_t id = castFromMArray(data, i + 0);
const uint64_t date = convertFromMArray(data, i + 1);
const uint64_t duration = convertFromMArray(data, i + 2);
stimSet->appendStimulation(id, date, duration);
}
mxDestroyArray(data);
return true;
}
//--------------------------------------------------------------------------------------------------------------
} // namespace Matlab
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyMatlab
@@ -0,0 +1,74 @@
#pragma once
#if defined TARGET_HAS_ThirdPartyMatlab
#include "ovp_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <engine.h>
namespace OpenViBE {
namespace Plugins {
namespace Matlab {
class CMatlabHelper
{
public:
CMatlabHelper(Kernel::ILogManager& /*logManager*/, Kernel::IErrorManager& /*errorManager*/) { }
bool setManagers(Kernel::ILogManager* logManager, Kernel::IErrorManager* errorManager)
{
m_logManager = logManager;
m_errorManager = errorManager;
return true;
}
bool setStreamedMatrixInputHeader(size_t index, CMatrix* matrix) const;
bool setFeatureVectorInputHeader(size_t index, CMatrix* matrix) const;
bool setSignalInputHeader(size_t index, CMatrix* matrix, uint64_t frequency) const;
bool setChannelLocalisationInputHeader(size_t index, CMatrix* matrix, bool dynamic) const;
bool setSpectrumInputHeader(size_t index, CMatrix* matrix, CMatrix* frequencyAbscissa, uint64_t frequency) const;
bool setStimulationsInputHeader(size_t index) const;
// The input buffers for streamed matrix and its children streams are the same.
bool addStreamedMatrixInputBuffer(size_t index, CMatrix* matrix, uint64_t startTime, uint64_t endTime) const;
bool addStimulationsInputBuffer(size_t index, IStimulationSet* stimSet, uint64_t startTime, uint64_t endTime) const;
bool getStreamedMatrixOutputHeader(size_t index, CMatrix* matrix) const;
bool getFeatureVectorOutputHeader(size_t index, CMatrix* matrix) const;
bool getSignalOutputHeader(size_t index, CMatrix* matrix, uint64_t& frequency) const;
bool getChannelLocalisationOutputHeader(size_t index, CMatrix* matrix, bool& dynamic) const;
bool getSpectrumOutputHeader(size_t index, CMatrix* matrix, CMatrix* frequencyAbscissa, uint64_t& frequency) const;
static bool getStimulationsOutputHeader(size_t index, IStimulationSet* stimSet);
// The output buffers for streamed matrix and its children streams are the same.
bool popStreamedMatrixOutputBuffer(size_t index, CMatrix* matrix, uint64_t& startTime, uint64_t& endTime) const;
bool popStimulationsOutputBuffer(size_t index, IStimulationSet* stimSet, uint64_t& startTime, uint64_t& endTime) const;
void setMatlabEngine(Engine* engine) { m_matlabEngine = engine; }
void setBoxInstanceVariableName(const CString& name) { m_boxInstanceVariableName = name; }
uint32_t getUi32FromEnv(const char* name) const;
uint64_t getUi64FromEnv(const char* name) const;
uint64_t genUi64FromEnvConverted(const char* name) const;
std::vector<CString> getNamelist(const char* name) const;
Kernel::ILogManager& getLogManager() const { return *m_logManager; }
Kernel::IErrorManager& getErrorManager() const { return *m_errorManager; }
private:
Engine* m_matlabEngine = nullptr;
// Need to be very careful that these pointers are still valid when the Helper will try to use them
Kernel::ILogManager* m_logManager = nullptr;
Kernel::IErrorManager* m_errorManager = nullptr;
CString m_boxInstanceVariableName; //must be unique
};
} // namespace Matlab
} // namespace Plugins
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyMatlab
@@ -0,0 +1,14 @@
#pragma once
// Boxes
//---------------------------------------------------------------------------------------------------
#define OVP_ClassId_BoxAlgorithm_MatlabScripting OpenViBE::CIdentifier(0x03303E0E, 0x39FE10DF)
#define OVP_ClassId_BoxAlgorithm_MatlabScriptingDesc OpenViBE::CIdentifier(0x46130E2F, 0x34F90BA1)
// Global defines
//---------------------------------------------------------------------------------------------------
#ifdef TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
#include "ovp_global_defines.h"
#endif // TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
#define OV_AttributeId_Box_FlagIsUnstable OpenViBE::CIdentifier(0x666FFFFF, 0x666FFFFF)
@@ -0,0 +1,26 @@
#include <openvibe/ov_all.h>
#include "ovp_defines.h"
#include "box-algorithms/ovpCBoxAlgorithmMatlabScripting.h"
#include <vector>
namespace OpenViBE {
namespace Plugins {
namespace Matlab {
OVP_Declare_Begin()
#if defined TARGET_HAS_ThirdPartyMatlab
OVP_Declare_New(CBoxAlgorithmMatlabScriptingDesc);
context.getTypeManager().registerEnumerationEntry(OV_TypeId_BoxAlgorithmFlag, OV_AttributeId_Box_FlagIsUnstable.toString(),
OV_AttributeId_Box_FlagIsUnstable.id());
#endif // TARGET_HAS_ThirdPartyMatlab
OVP_Declare_End()
} // namespace Matlab
} // namespace Plugins
} // namespace OpenViBE