Commit b0168524 authored by Günter Windau's avatar Günter Windau

added lsl glnxa64 source code

parent 7de3773f
% Set up matlab path for the labstreaminglayer library
pathdirs = { ...
[ biofysica_root '/liblsl/glnxa64' ]
};
for i = 1:size(pathdirs,1)
d = pathdirs{i};
if exist(d,'dir')
p=genpath(d);
addpath(p);
exclude_d=[d '/init.d'];
exclude_p=genpath(exclude_d);
rmpath(exclude_p);
exclude_d=[d '/.svn'];
exclude_p=genpath(exclude_d);
rmpath(exclude_p);
exclude_d=[d '/.git'];
exclude_p=genpath(exclude_d);
rmpath(exclude_p);
exclude_d=[d '/liblsl'];
exclude_p=genpath(exclude_d);
rmpath(exclude_p);
% disp(['added directory ', d, ' to the MATLAB path']);
else
disp(['directory ', d, ' does not exist, not added to the MATLAB path']);
end
clear pathdirs d p exclude_d i exclude_p
end
GW 20200806 This is source code only
{
"package": {
"name": "liblsl-Matlab",
"repo": "LSL",
"subject": "labstreaminglayer",
"desc": "Travis CI build",
"website_url": "https://github.com/labstreaminglayer/liblsl-matlab",
"issue_tracker_url": "https://github.com/labstreaminglayer/liblsl-matlab/issues",
"vcs_url": "https://github.com/labstreaminglayer/liblsl-matlab.git",
"github_use_tag_release_notes": true,
"licenses": ["MIT"],
"public_download_numbers": false,
"public_stats": false
},
"version": {
"name": "1.12",
"desc": "Matlab bindings for liblsl",
"released": "2018-05-02",
"vcs_tag": "",
"gpgSign": false
},
"files": [ {
"includePattern": "./((.)[^/]*\.tar\.bz2)",
"uploadPattern": "$1",
"matrixParams": { "override": 1 }
}],
"publish": true
}
language: c
env:
LSLDIST_URL="https://dl.bintray.com/labstreaminglayer/LSL/"
UBUNTU_DIST="trusty"
LSL_VERSION="1.1.2"
- CMakeArgs=""
script:
- cp ${LSL_INSTALL_ROOT}/lib/* bin/
- octave-cli --eval build_mex
- rm bin/*.o
- tar --transform "s/^\.\?/liblsl-matlab/" -cjf liblsl-matlab-${LSL_VERSION}.tar.bz2 . || true
matrix:
include:
- os: linux
addons:
apt:
packages:
- liboctave-dev
before_script:
- travis_retry wget --quiet ${LSLDIST_URL}/lsl-liblsl{,-dev}_${LSL_VERSION}-${UBUNTU_DIST}_amd64.deb
- for deb in *.deb; do dpkg -x ${deb} LSL; done
- export LSL_INSTALL_ROOT=LSL/usr
- os: osx
before_install:
- brew install octave
before_script:
- travis_retry wget --quiet ${LSLDIST_URL}/LSL-${LSL_VERSION}-Darwin-liblsl{,-dev}.tar.bz2
- mkdir LSL; for file in *.tar.bz2; do tar -xf ${file} -C LSL; done
- export LSL_INSTALL_ROOT=LSL
deploy:
skip_cleanup: true
provider: bintray
user: tstenner
key:
secure: "PoHMsNdp5UgFtAPljabOVC+6r5wjwHZwGgVDLEgKs0b+EwgkShj42Li03vQCz2u0cRkgHutv5cGCe8L5+ez4zyqnF98gXrgflbhcfdjhHEB6hp65kV2+9myNOPcrlsm+gR0Ex1kN1owfDRfBIasa6SMp2+4Ii4mxm/aiSaLnvaB1lM6zknNZMpW0lucdQVqKH+HatUaHRc0EB1KgzSRU7jKxA/XWqHQ8lRk2Hnk5bVOWCu755DLbKquuZUV1KmxvF5TolDahhwh/DuCFa/UJ9G2eHdt/1/7Pb2w1Dx+9oyW4D6kjbxuYLuUjeeRBnRg/XUNQ6HPywC9b4jMgyu7bRnfKgXmM323FYRp3iybuK8BQpv7QbRbX3s4VEjEp/LbPqLBIqiSShy2lRloNI2YfCFyaOunYVSPCavXslzyURdx/l/RiweZe9YDUq03GL8QNs2vMmnS5ieVIqW6X2PNGZqitV5nXNnTPfU+mJk51vzv32C1vQQFZTJ9qBg57GAfp3WfRI3MVfx62ix8Zc1TTjevSB1ISQKRuqv5zFrMsx+5Ymj7mZxokkGqYA1/OS9SxWISZ8+nd9veYB4ykKA3qZEvmF3vaC559pY00IpjlSoI38cQADsSd1EivMhM9JuIxFpOmnLtZJyk1AvW47hxXgXupf099Vfea3ycBElk7eqQ="
file: .bintray.json
This is the MATLAB interface for liblsl.
* You need to add this directory to your MATLAB path recursively
* Using the MATLAB GUI, use File/Set Path...
* Alternatively, in a script, use `addpath(genpath('path/to/liblsl-Matlab'));`
* The bin/ directory needs to contain an up-to-date build of the library file for your MATLAB version.
* e.g. liblsl64.dll for 64-bit MATLAB on Windows.
* e.g. `liblsl64.dylib` and `liblsl64.1.4.0.dylib` for 64-bit MATLAB on MacOS.
* e.g. `liblsl64.so` and `liblsl64.so.1.4.0` for 64-bit MATLAB in Linux
* Once this taken care of, see the example files in the examples/ directory for how to use this interface in a MATLAB program.
### Troubleshooting
If you get an error similar to `lsl_loadlib_ undefined`, then you may need to run the `build_mex.m` script from within the liblsl-Matlab directory.
(From the command line: `matlab -nodesktop -nosplash -r 'build_mex'`)
On MacOS, you may still get an error similar to `Invalid MEX-file [...] lsl_loadlib_.mexmaci64; Reason: image not found.`. To fix this run the following command in a Terminal window from within the liblsl-Matlab directory: `install_name_tool -add_rpath "@loader_path/" bin/lsl_loadlib_.mexmaci64`
version: 1.12.0.{build}
pull_requests:
do_not_increment_build_number: true
shallow_clone: true
environment:
LSLVERSION: 1.12
OCTAVE_VER: 4.4.0-w64
VCVER: 14.0
install:
- cmd: >-
appveyor DownloadFile https://ftp.gnu.org/gnu/octave/windows/octave-%OCTAVE_VER%.7z -FileName octave.7z
7z x octave.7z -o"c:\dev" -y
build_script:
- cmd: >-
call "C:\Program Files (x86)\Microsoft Visual Studio %VCVER%\VC\vcvarsall.bat" x64
appveyor DownloadFile https://bintray.com/labstreaminglayer/LSL/download_file?file_path=liblsl_x64_%LSLVERSION%.zip -FileName liblsl.zip
7z x liblsl.zip
cp LSL/lib/liblsl64.dll bin/
c:\dev\octave-%OCTAVE_VER%\bin\octave-gui.exe --eval build_mex
del bin\*.o
artifacts:
- path: .
name: ${APPVEYOR_PROJECT_NAME}_x64_${APPVEYOR_BUILD_VERSION}
deploy:
- provider: BinTray
username: tstenner
api_key:
secure: Fo9tIQnGjVnCXB3euItvYrt85A5O9FPqq7LEpsdOuwW+eOg1rwA5Q1HLp4yWDXAl
subject: labstreaminglayer
version: 1.12
repo: LSL
package: liblsl-matlab
override: true
% Build mex bindings
% For Octave on Linux, you need the package liboctave-dev installed
% You also need the liblsl64 binary in the bin folder and a configured
% C compiler (mex -setup)
libs = {'-llsl64'};
if ispc
dllext = 'dll';
elseif ismac
dllext = 'dylib';
elseif isunix
dllext = 'so';
libs = {'-llsl64','-ldl'};
end
if isempty(dir(['bin/liblsl64.', dllext]))
error(['liblsl64.' dllext ' not found in bin/']);
end
ext = ['.' mexext];
files = dir('mex/*.c');
cd('bin');
for i = 1:length(files)
f = files(i);
[~, base, ~] = fileparts(f.name);
targetstats = dir([base, ext]);
if isempty(targetstats) || f.datenum > targetstats.datenum
mex('-I../../liblsl/include','-L.', libs{:}, ['../mex/', f.name]);
else
disp([base, ext, ' up to date']);
end
end
cd('..');
% This file is here only so that you can put this directory into the dependencies folder of a BCILAB installation.
\ No newline at end of file
%% instantiate the library
lib = lsl_loadlib();
% create a new StreamInfo and declare some meta-data (in accordance with XDF format)
info = lsl_streaminfo(lib,'MetaTester','EEG',8,100,'cf_float32','myuid56872');
chns = info.desc().append_child('channels');
for label = {'C3','C4','Cz','FPz','POz','CPz','O1','O2'}
ch = chns.append_child('channel');
ch.append_child_value('label',label{1});
ch.append_child_value('unit','microvolts');
ch.append_child_value('type','EEG');
end
info.desc().append_child_value('manufacturer','SCCN');
cap = info.desc().append_child('cap');
cap.append_child_value('name','EasyCap');
cap.append_child_value('size','54');
cap.append_child_value('labelscheme','10-20');
% create outlet for the stream
outlet = lsl_outlet(info);
% === the following could run on another computer ===
% resolve the stream and open an inlet
lib = lsl_loadlib();
result = {};
while isempty(result)
result = lsl_resolve_byprop(lib,'type','EEG'); end
inlet = lsl_inlet(result{1});
% get the full stream info (including custom meta-data) and dissect it
inf = inlet.info();
fprintf('The stream''s XML meta-data is: \n');
fprintf([inf.as_xml() '\n']);
fprintf(['The manufacturer is: ' inf.desc().child_value('manufacturer') '\n']);
fprintf(['The cap circumference is: ' inf.desc().child('cap').child_value('size') '\n']);
fprintf('The channel labels are as follows:\n');
ch = inf.desc().child('channels').child('channel');
for k = 1:inf.channel_count()
fprintf([' ' ch.child_value('label') '\n']);
ch = ch.next_sibling();
end
disp('Loading library...');
lib = lsl_loadlib();
disp('Displaying library version');
version = lsl_library_version(lib)
# MATLAB Example Programs: Basic to Advanced
These examples show how to transmit a numeric multi-channel time series through LSL:
* [Sending a multi-channel time series into LSL.](SendData.m)
* [Receiving a multi-channel time series from LSL.](ReceiveData.m)
These examples do the same as before, but now transmit the data at the granularity of chunks.
For the purposes of network transmission the same effect can be achieved by creating the inlet or
outlet with an extra argument to indicate that multiple samples should be batched into a chunk for
transmission.
However, since MATLAB's interpreter is relatively slow, the library calls should be made in a
vectorized manner, i.e. at chunk granularity, whenever possible (at least for high-rate streams).
Note that for LSL the data is always a linear sequence of samples and data that is pushed as
samples can be pulled out as chunks or vice versa:
* [Sending data at chunk granularity.](SendDataInChunks.m)
* [Receiving data at chunk granularity.](ReceiveDataInChunks.m)
These examples show a special-purpose use case that is mostly relevant for stimulus-presentation
programs or other applications that want to emit 'event' markers or other application state.
The stream here is single-channel and has irregular sampling rate, but the value per channel is a
string:
* [Sending string-formatted irregular streams.](SendStringMarkers.m)
* [Receiving string-formatted irregular streams.](ReceiveStringMarkers.m)
The last example shows how to attach properly formatted meta-data to a stream, and how to read it
out again at the receiving end.
While meta-data is strictly optional, it is very useful to make streams self-describing.
LSL has adopted the convention to name meta-data fields according to the XDF file format
specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc);
the spec is [here](https://github.com/sccn/xdf/wiki/Meta-Data).
Note that some older example programs (SendData/ReceiveData) predate this convention and name the
channels inconsistently.
* [Handling stream meta-data.](HandleMetaData.m)
## Running the examples
To run these examples, you must have added the folder `include/lsl_matlab` to your MATLAB path (recursively).
You can do this either via the File/Path... menu or via the command `addpath(genpath('your_path_to/liblsl-1.xx/include/lsl_matlab'))`
Also, if you have rebuilt the library, make sure that `liblsl-1.xx/include/lsl_matlab/bin` contains a copy of the library files in the `liblsl-1.xx/bin`.
%% instantiate the library
disp('Loading the library...');
lib = lsl_loadlib();
% resolve a stream...
disp('Resolving an EEG stream...');
result = {};
while isempty(result)
result = lsl_resolve_byprop(lib,'type','EEG'); end
% create a new inlet
disp('Opening an inlet...');
inlet = lsl_inlet(result{1});
disp('Now receiving data...');
while true
% get data from the inlet
[vec,ts] = inlet.pull_sample();
% and display it
fprintf('%.2f\t',vec);
fprintf('%.5f\n',ts);
end
\ No newline at end of file
% instantiate the library
disp('Loading the library...');
lib = lsl_loadlib();
% resolve a stream...
disp('Resolving an EEG stream...');
result = {};
while isempty(result)
result = lsl_resolve_byprop(lib,'type','EEG'); end
% create a new inlet
disp('Opening an inlet...');
inlet = lsl_inlet(result{1});
disp('Now receiving chunked data...');
while true
% get chunk from the inlet
[chunk,stamps] = inlet.pull_chunk();
for s=1:length(stamps)
% and display it
fprintf('%.2f\t',chunk(:,s));
fprintf('%.5f\n',stamps(s));
end
pause(0.05);
end
\ No newline at end of file
% instantiate the library
addpath(genpath('./../../liblsl-Matlab/'))
disp('Loading the library...');
lib = lsl_loadlib();
% resolve a stream...
disp('Resolving a Markers stream...');
result = {};
while isempty(result)
result = lsl_resolve_byprop(lib,'type','Markers'); end
% create a new inlet
disp('Opening an inlet...');
inlet = lsl_inlet(result{1});
disp('Now receiving data...');
while true
% get data from the inlet
[mrks,ts] = inlet.pull_sample();
% and display it
fprintf('got %s at time %.5f\n',mrks{1},ts);
end
%% instantiate the library
disp('Loading library...');
lib = lsl_loadlib();
% make a new stream outlet
disp('Creating a new streaminfo...');
info = lsl_streaminfo(lib,'BioSemi','EEG',8,100,'cf_float32','sdfwerr32432');
disp('Opening an outlet...');
outlet = lsl_outlet(info);
% send data into the outlet, sample by sample
disp('Now transmitting data...');
while true
outlet.push_sample(randn(8,1));
pause(0.01);
end
\ No newline at end of file
% instantiate the library
disp('Loading library...');
lib = lsl_loadlib();
% make a new stream outlet
disp('Creating a new streaminfo...');
info = lsl_streaminfo(lib,'BioSemi','EEG',8,100,'cf_float32','sdfwerr32432');
disp('Opening an outlet...');
outlet = lsl_outlet(info);
% send data into the outlet
disp('Now transmitting chunked data...');
while true
outlet.push_chunk(randn(8,50));
pause(0.5);
end
\ No newline at end of file
% instantiate the library
disp('Loading library...');
lib = lsl_loadlib();
% make a new stream outlet
% the name (here MyMarkerStream) is visible to the experimenter and should be chosen so that
% it is clearly recognizable as your MATLAB software's marker stream
% The content-type should be Markers by convention, and the next three arguments indicate the
% data format (1 channel, irregular rate, string-formatted).
% The so-called source id is an optional string that allows for uniquely identifying your
% marker stream across re-starts (or crashes) of your script (i.e., after a crash of your script
% other programs could continue to record from the stream with only a minor interruption).
disp('Creating a new marker stream info...');
info = lsl_streaminfo(lib,'MyMarkerStream','Markers',1,0,'cf_string','myuniquesourceid23443');
disp('Opening an outlet...');
outlet = lsl_outlet(info);
% send markers into the outlet
disp('Now transmitting data...');
markers = {'Test', 'Blah', 'Marker', 'XXX', 'Testtest', 'Test-1-2-3'};
while true
pause(rand()*3);
mrk = markers{min(length(markers), 1+floor(rand()*(length(markers))))};
disp(['now sending ' mrk]);
outlet.push_sample({mrk}); % note that the string is wrapped into a cell-array
end
classdef lsl_inlet < handle
% A stream inlet.
% Inlets are used to receive streaming data (and meta-data) from the lab network.
%
% Note:
% Most functions of the inlet can throw an error of type 'lsl:lost_error' if the stream
% read by this inlet has been lost irretrievably. Those functions that take a timeout can in
% addition throw an error of type 'lsl:timeout_error'.
properties (Hidden)
LibHandle = 0; % this is a handle to the liblsl library (to call its functions)
InletHandle = 0; % this is a handle to an lsl_inlet object within the library.
ChannelCount = 0; % copy of the inlet's channel count
IsString = 0; % whether this is a string-formatted inlet
end
methods
function self = lsl_inlet(info, maxbuffered, chunksize, recover, process)
% Inlet = lsl_inlet(Streaminfo, MaxBuffered, ChunkSize, Recover)
% Construct a new stream inlet from a resolved stream info.
%
% In:
% Streaminfo : A resolved stream info object (as coming from one of the lsl_resolve_* functions).
%
% MaxBuffered : Optionally the maximum amount of data to buffer (in seconds if there is a nominal
% sampling rate, otherwise x100 in samples). Recording applications want to use a fairly
% large buffer size here, while real-time applications would only buffer as much as
% they need to perform their next calculation. (default: 360)
%
% ChunkSize : Optionally the maximum size, in samples, at which chunks are transmitted
% (0 corresponds to the chunk sizes used by the sender).
% Recording applications can use a generous size here (leaving it to the network how
% to pack things), while real-time applications may want a finer (perhaps 1-sample) granularity.
% (default 0)
%
% Recover : Try to silently recover lost streams that are recoverable (=those that that have a source_id set).
% In all other cases (recover is false or the stream is not recoverable) functions may throw a
% lost_error if the stream's source is lost (e.g., due to an app or computer crash).
% (default: 1)
%
if ~exist('maxbuffered','var') || isempty(maxbuffered) maxbuffered = 360; end
if ~exist('chunksize','var') || isempty(chunksize) chunksize = 0; end
if ~exist('recover','var') || isempty(recover) recover = 1; end
self.LibHandle = info.LibHandle;
self.ChannelCount = info.channel_count();
self.IsString = strcmp(info.channel_format(),'cf_string');
self.InletHandle = lsl_create_inlet(info.LibHandle,info.InfoHandle,maxbuffered,chunksize,recover);
end
function delete(self)
% Destroy the inlet when it is deleted.
% The inlet will automatically disconnect if destroyed.
lsl_destroy_inlet(self.LibHandle,self.InletHandle);
end
function result = info(self, timeout)
% Retrieve the complete information of the given stream, including the extended description.
% Fullinfo = info(Timeout)
%
% Can be invoked at any point of the stream's lifetime.
%
% In:
% Timeout : Timeout of the operation, in seconds (default: 60).
%
% Out:
% Fullinfo : the full information, including description field, of the stream.
if ~exist('timeout','var') || isempty(timeout) timeout = 60; end
result = lsl_streaminfo(self.LibHandle,lsl_get_fullinfo(self.LibHandle, self.InletHandle, timeout));
end
function open_stream(self, timeout)
% Subscribe to the data stream from this moment onwards.
% open_stream(Timeout)
%
% All samples pushed in at the other end from this moment onwards will be queued and
% eventually be delivered in response to pull_sample() or pull_chunk() calls.
% Pulling a sample without some preceding open_stream is permitted (the stream will then
% be opened implicitly).
%
% In:
% Timeout : Timeout of the operation (default: 60).
%
% Out:
% Fullinfo : the full information, including description field, of the stream.
if ~exist('timeout','var') || isempty(timeout) timeout = 60; end
lsl_open_stream(self.LibHandle, self.InletHandle, timeout);
end
function close_stream(self)
% Drop the current data stream.
% close_stream()
%
% All samples that are still buffered or in flight will be dropped and the source will halt its buffering of data for this inlet.
% If an application stops being interested in data from a source (temporarily or not) but keeps the outlet alive, it should
% call close_streams() to not pressure the source outlet to buffer unnecessarily large amounts of data.
lsl_close_stream(self.LibHandle, self.InletHandle);
end
function result = time_correction(self,timeout)
% Retrieve an estimated time correction offset for the given stream.
%
% The first call to this function takes several miliseconds until a reliable first estimate is obtained.
% Subsequent calls are instantaneous (and rely on periodic background updates).
% The precision of these estimates should be below 1 ms (empirically within +/-0.2 ms).
%
% In:
% Timeout : Timeout to acquire the first time-correction estimate (default: 60).
%
% Out:
% Offset : The time correction estimate. If the first estimate cannot within the alloted time,
% the result is NaN.
if ~exist('timeout','var') || isempty(timeout) timeout = 60; end
result = lsl_time_correction(self.LibHandle, self.InletHandle,timeout);
end
function result = set_postprocessing(self, processing_flags)
% Set timestamp correction postprocessing flags. This should
% only be done in online scenarios. This option will destroy a
% stream's original, ground-truth timestamps.
%
% In:
% processing_flags :
% 0 : no automatic post_processing
% 1 : perform automatic clock synchronization
% 2 : remove jitter from time stamps
% 4 : force time-stamps to be monotonically ascending (only makes sense if also dejittered)
% 8 : post-processing is threadsafe (same inlet can be read from by multiple threads)
% 15 : combination of all options
% These options can be combined by adding them