|
1 | 1 | # C# bindings |
2 | 2 |
|
3 | 3 | The is the C# interface to the lab streaming layer. To use it, you need to include the file LSL.cs in |
4 | | -your project, and make sure that the lsl library (e.g. liblsl32.dll) is found (e.g., in your application's |
| 4 | +your project, and make sure that the appropriate lsl library (e.g. lsl.dll) is findable (e.g., in your application's |
5 | 5 | root directory or in a system path). |
6 | 6 |
|
7 | | -If you are deploying for something other than Unity, and on a platform that requires a different binary |
8 | | -than liblsl32.dll (e.g., liblsl64.so on 64-bit Linux, or liblsl64.dylib on Mac OS) |
9 | | -then you need to replace the libname constant in LSL.cs by the corresponding file name. |
| 7 | +If LSL.cs fails to find the lsl shared library for your target platform, edit LSL.cs and update the following line with the name for your system: `const string libname = "lsl";` |
10 | 8 |
|
11 | | -These example applications can be debugged from within the IDE (i.e. Visual Studio). However, the built |
12 | | -products are DLL files, not EXE files. The DLL files can be run at console with `dotnet my_application` |
13 | | -(from within same folder as my_application.DLL). This will work anywhere the .NET Core Runtime works. |
14 | | -To make a more portable but platform-dependent product, use `dotnet publish -C Debug -r win10-x64` |
15 | | -(or Release instead of Debug) and this will generate an EXE file. |
| 9 | +# C# Example Programs |
16 | 10 |
|
| 11 | +The examples folder contains example C# code for sending and receiving data streams. The examples are described in the [online documentation](https://labstreaminglayer.readthedocs.io/dev/examples.html#id2). |
17 | 12 |
|
18 | | -## C# Example Programs |
| 13 | +These example applications can be debugged from within the IDE (i.e. Visual Studio). However, the built products are DLL files, not EXE files. The DLL files can be run at console with `dotnet my_application` (from within same folder as my_application.DLL). This will work anywhere the .NET Core Runtime works. To make a more portable but platform-dependent product, use `dotnet publish -C Debug -r win10-x64` (or Release instead of Debug) and this will generate an EXE file. |
19 | 14 |
|
20 | | -These examples show how to transmit a numeric multi-channel time series through LSL: |
| 15 | +# Unity |
21 | 16 |
|
22 | | -- [Sending a multi-channel time series into LSL.](https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/examples/SendData) |
23 | | -- [Receiving a multi-channel time series from LSL.](https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/examples/ReceiveData) |
| 17 | +The [LSL4Unity repository](https://github.com/labstreaminglayer/LSL4Unity) provides a more featureful integration of LSL into Unity. However, it is not as well-maintained as this repository. The recommended approach to integrating LSL into a Unity project is to use this repository's LSL.cs, and use LSL4Unity as a reference for more advanced use of LSL in Unity. |
24 | 18 |
|
25 | | -The following examples show how to transmit data in form of chunks instead of samples, which can be |
26 | | -more convenient. |
| 19 | +## Getting Started in Unity |
27 | 20 |
|
28 | | -- [Sending a multi-channel time series in chunks.](https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/examples/SendDataInChunks) |
29 | | -- [Receiving a multi-channel time series in chunks.](https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/examples/ReceiveDataInChunks) |
| 21 | +These instructions were written while using Unity 2020.1.0f1. |
30 | 22 |
|
31 | | -These examples show a special-purpose use case that is mostly relevant for stimulus-presentation |
32 | | -programs or other applications that want to emit 'event' markers or other application state. |
| 23 | +1. Drag and drop LSL.cs into the project Assets folder. |
| 24 | +1. Download the latest [liblsl release](https://github.com/sccn/liblsl/releases) for your platform and extract the library (e.g. liblsl64.dll) into the project root folder. |
| 25 | +1. In Unity, use the menu to place a cube in the scene: GameObject > 3D Object > Cube |
| 26 | +1. When the cube is selected, in the Inspector click on "Add Component", and create a new script called LSLInput. |
| 27 | +1. In the Project viewer, double click on LSLInput.cs. This should launch Visual Studio or another IDE. |
| 28 | +1. Fill in the script. Use [LSL4Unity AInlet](https://github.com/labstreaminglayer/LSL4Unity/blob/master/Scripts/AInlet.cs) for inspiration. |
| 29 | + ``` |
| 30 | +using System.Collections; |
| 31 | +using System.Collections.Generic; |
| 32 | +using UnityEngine; |
| 33 | +using LSL; |
33 | 34 |
|
34 | | -The stream here is single-channel and has irregular sampling rate, but the value per channel is a string: |
35 | | -- [Sending string-formatted irregular streams.](https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/examples/SendStringMarkers) |
36 | | -- [Receiving string-formatted irregular streams.](https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/examples/ReceiveStringMarkers) |
| 35 | +public class LSLInput : MonoBehaviour |
| 36 | +{ |
| 37 | + public string StreamType = "EEG"; |
| 38 | + public float scaleInput = 0.1f; |
| 39 | + liblsl.StreamInfo[] streamInfos; |
| 40 | + liblsl.StreamInlet streamInlet; |
| 41 | + liblsl.ContinuousResolver resolver; |
| 42 | + float[] sample; |
| 43 | + private int channelCount = 0; |
37 | 44 |
|
38 | | -The last example shows how to attach properly formatted meta-data to a stream, and how to read it |
39 | | -out again at the receiving end. |
40 | | -While meta-data is strictly optional, it is very useful to make streams self-describing. |
41 | | -LSL has adopted the convention to name meta-data fields according to the XDF file format |
42 | | -specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); |
43 | | -the spec is [here](https://github.com/sccn/xdf/wiki/Meta-Data). |
| 45 | + // Start is called before the first frame update |
| 46 | + void Start() |
| 47 | + { |
| 48 | + resolver = new liblsl.ContinuousResolver("type", StreamType); |
| 49 | + StartCoroutine(ResolveExpectedStream()); |
| 50 | + } |
44 | 51 |
|
45 | | -- [Handling stream meta-data.](https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/examples/HandleMetaData) |
| 52 | + IEnumerator ResolveExpectedStream() |
| 53 | + { |
| 54 | + var streamInfos = resolver.results(); |
| 55 | + yield return new WaitUntil(() => streamInfos.Length > 0); |
| 56 | + streamInlet = new liblsl.StreamInlet(streamInfos[0]); |
| 57 | + channelCount = streamInlet.info().channel_count(); |
| 58 | + streamInlet.open_stream(); |
| 59 | + yield return null; |
| 60 | + } |
| 61 | +
|
| 62 | + // Update is called once per frame |
| 63 | + void Update() |
| 64 | + { |
| 65 | + if (streamInlet != null) |
| 66 | + { |
| 67 | + sample = new float[channelCount]; |
| 68 | + double lastTimeStamp = streamInlet.pull_sample(sample, 0.0f); |
| 69 | + if (lastTimeStamp != 0.0) |
| 70 | + { |
| 71 | + Process(sample, lastTimeStamp); |
| 72 | + while ((lastTimeStamp = streamInlet.pull_sample(sample, 0.0f)) != 0) |
| 73 | + { |
| 74 | + Process(sample, lastTimeStamp); |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + } |
| 79 | + void Process(float[] newSample, double timeStamp) |
| 80 | + { |
| 81 | + var inputVelocity = new Vector3(scaleInput * (newSample[0] - 0.5f), scaleInput * (newSample[1] - 0.5f), scaleInput * (newSample[2] -0.5f)); |
| 82 | + gameObject.transform.position = gameObject.transform.position + inputVelocity; |
| 83 | + } |
| 84 | +} |
| 85 | + ``` |
| 86 | +1. Elsewhere, run one of the LSL outlet examples. For example, from a conda environment with pylsl installed: `python -m pylsl.examples.SendData` |
| 87 | +1. Run the Unity game. |
0 commit comments