1
1
#include < cmath>
2
2
#include < iostream>
3
+ #include < map>
3
4
#include < lsl_cpp.h>
4
5
#include < thread>
6
+ #include < algorithm>
7
+ #include < random>
5
8
6
9
7
10
// define a packed sample struct (here: a 16 bit stereo sample).
@@ -10,31 +13,79 @@ struct stereo_sample {
10
13
int16_t l, r;
11
14
};
12
15
16
+ // fill buffer with data from device -- Normally your device SDK would provide such a function. Here we use a random number generator.
17
+ void get_data_from_device (std::vector<std::vector<int16_t >> buffer, uint64_t &sample_counter) {
18
+ static std::uniform_int_distribution<int16_t > distribution (
19
+ std::numeric_limits<int16_t >::min (), std::numeric_limits<int16_t >::max ());
20
+ static std::default_random_engine generator;
21
+
22
+ if (buffer[0 ].size () == 2 ) {
23
+ // If there are only 2 channels then we'll do a sine wave, pretending this is an audio device.
24
+ for (auto &frame : buffer) {
25
+ frame[0 ] = static_cast <int16_t >(100 * sin (sample_counter / 200 .));
26
+ frame[1 ] = static_cast <int16_t >(120 * sin (sample_counter / 400 .));
27
+ sample_counter++;
28
+ }
29
+ }
30
+ else {
31
+ for (auto &frame : buffer) {
32
+ for (std::size_t chan_idx = 0 ; chan_idx < frame.size (); ++chan_idx) {
33
+ frame[chan_idx] = distribution (generator);
34
+ }
35
+ sample_counter++;
36
+ }
37
+ }
38
+ }
39
+
13
40
int main (int argc, char **argv) {
41
+ std::cout << " SendDataInChunks" << std::endl;
42
+ std::cout << " SendDataInChunks StreamName StreamType samplerate n_channels max_buffered chunk_rate" << std::endl;
43
+ std::cout << " - max_buffered -- duration in sec (or x100 samples if samplerate is 0) to buffer for each outlet" << std::endl;
44
+ std::cout << " - chunk_rate -- number of chunks pushed per second. For this example, make it a common factor of samplingrate and 1000." << std::endl;
45
+
14
46
std::string name{argc > 1 ? argv[1 ] : " MyAudioStream" }, type{argc > 2 ? argv[2 ] : " Audio" };
15
47
int samplingrate = argc > 3 ? std::stol (argv[3 ]) : 44100 ;
48
+ int n_channels = argc > 4 ? std::stol (argv[4 ]) : 2 ;
49
+ int32_t max_buffered = argc > 5 ? std::stol (argv[5 ]) : 360 ;
50
+ int32_t chunk_rate = argc > 6 ? std::stol (argv[6 ]) : 10 ; // Chunks per second.
51
+ int32_t chunk_samples = samplingrate > 0 ? std::max ((samplingrate / chunk_rate), 1 ) : 100 ; // Samples per chunk.
52
+ int32_t chunk_duration = 1000 / chunk_rate; // Milliseconds per chunk
53
+
16
54
try {
17
- // make a new stream_info (44.1Khz, 16bit, audio, 2 channels) and open an outlet with it
18
- lsl::stream_info info (name, type, 2 , samplingrate, lsl::cf_int16);
19
- lsl::stream_outlet outlet (info);
55
+ lsl::stream_info info (name, type, n_channels, samplingrate, lsl::cf_int16);
56
+ lsl::stream_outlet outlet (info, 0 , max_buffered);
57
+ lsl::xml_element desc = info.desc ();
58
+ desc.append_child_value (" manufacturer" , " LSL" );
59
+ lsl::xml_element chns = desc.append_child (" channels" );
60
+ for (int c = 0 ; c < n_channels; c++) {
61
+ lsl::xml_element chn = chns.append_child (" channel" );
62
+ chn.append_child_value (" label" , " Chan-" + std::to_string (c));
63
+ chn.append_child_value (" unit" , " microvolts" );
64
+ chn.append_child_value (" type" , " EEG" );
65
+ }
66
+
67
+ // Prepare buffer to get data from 'device'
68
+ std::vector<std::vector<int16_t >> chunk_buffer (
69
+ chunk_samples,
70
+ std::vector<int16_t >(n_channels));
20
71
21
72
std::cout << " Now sending data..." << std::endl;
73
+
74
+ // Your device might have its own timer. Or you can decide how often to poll
75
+ // your device, as we do here.
22
76
auto nextsample = std::chrono::high_resolution_clock::now ();
23
- std::vector<stereo_sample> mychunk (info.nominal_srate () / 10 );
24
- int phase = 0 ;
77
+ uint64_t sample_counter = 0 ;
25
78
for (unsigned c = 0 ;; c++) {
26
- // wait a bit and generate a chunk of random data
27
- nextsample += std::chrono::milliseconds (100 );
79
+
80
+ // wait a bit
81
+ nextsample += std::chrono::milliseconds (chunk_duration);
28
82
std::this_thread::sleep_until (nextsample);
29
83
30
- for (stereo_sample &sample : mychunk) {
31
- sample.l = static_cast <int16_t >(100 * sin (phase / 200 .));
32
- sample.r = static_cast <int16_t >(120 * sin (phase / 400 .));
33
- phase++;
34
- }
84
+ // Get data from device
85
+ get_data_from_device (chunk_buffer, sample_counter);
35
86
36
- // send it
37
- outlet.push_chunk_numeric_structs (mychunk );
87
+ // send it to the outlet
88
+ outlet.push_chunk (chunk_buffer );
38
89
}
39
90
40
91
} catch (std::exception &e) { std::cerr << " Got an exception: " << e.what () << std::endl; }
0 commit comments