Skip to content

Commit fd2a85f

Browse files
committed
gather-write directly to asio when using sync mode and pushing a sample of buffers.
raw buffs use void**; incorporate other suggestions from tstenner. Currently not working properly!
1 parent e24da34 commit fd2a85f

File tree

11 files changed

+543
-138
lines changed

11 files changed

+543
-138
lines changed

examples/ReceiveDataInChunks.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ int main(int argc, char **argv) {
1818
try {
1919

2020
std::string name{argc > 1 ? argv[1] : "MyAudioStream"};
21-
double max_buflen = argc > 2 ? std::stod(argv[2]) : 360.;
21+
double max_buffered = argc > 2 ? std::stod(argv[2]) : 360.;
2222
bool flush = argc > 3;
2323
// resolve the stream of interest & make an inlet
24-
int32_t buf_samples = (int32_t)(max_buflen * 1000);
24+
int32_t buf_samples = (int32_t)(max_buffered * 1000);
2525
lsl::stream_info inlet_info = lsl::resolve_stream("name", name).at(0);
26-
lsl::stream_inlet inlet(inlet_info, max_buflen, transp_bufsize_thousandths);
26+
lsl::stream_inlet inlet(inlet_info, buf_samples, transp_bufsize_thousandths);
2727

2828
// Use set_postprocessing to get the timestamps in a common base clock.
2929
// Do not use if this application will record timestamps to disk -- it is better to

examples/SendData.cpp

Lines changed: 116 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,116 @@
1-
#include "lsl_cpp.h"
2-
#include <array>
3-
#include <chrono>
4-
#include <iostream>
5-
#include <stdlib.h>
6-
#include <thread>
7-
8-
/**
9-
* This example program offers an 8-channel stream, float-formatted, that resembles EEG data.
10-
* The example demonstrates also how per-channel meta-data can be specified using the .desc() field
11-
* of the stream information object.
12-
*
13-
* Note that the timer used in the send loop of this program is not particularly accurate.
14-
*/
15-
16-
17-
const char *channels[] = {"C3", "C4", "Cz", "FPz", "POz", "CPz", "O1", "O2"};
18-
19-
int main(int argc, char *argv[]) {
20-
std::string name, type;
21-
if (argc < 3) {
22-
std::cout
23-
<< "This opens a stream under some user-defined name and with a user-defined content "
24-
"type."
25-
<< std::endl;
26-
std::cout << "SendData Name Type [n_channels=8] [srate=100] [max_buffered=360]"
27-
<< std::endl;
28-
std::cout
29-
<< "Please enter the stream name and the stream type (e.g. \"BioSemi EEG\" (without "
30-
"the quotes)):"
31-
<< std::endl;
32-
std::cin >> name >> type;
33-
} else {
34-
name = argv[1];
35-
type = argv[2];
36-
}
37-
int n_channels = argc > 3 ? std::stol(argv[3]) : 8;
38-
n_channels = n_channels < 8 ? 8 : n_channels;
39-
int samplingrate = argc > 4 ? std::stol(argv[4]) : 100;
40-
int max_buffered = argc > 5 ? std::stol(argv[5]) : 360;
41-
42-
try {
43-
44-
// make a new stream_info (100 Hz)
45-
lsl::stream_info info(
46-
name, type, n_channels, samplingrate, lsl::cf_float32, std::string(name) += type);
47-
48-
// add some description fields
49-
info.desc().append_child_value("manufacturer", "LSL");
50-
lsl::xml_element chns = info.desc().append_child("channels");
51-
for (int k = 0; k < n_channels; k++)
52-
chns.append_child("channel")
53-
.append_child_value("label", k < 8 ? channels[k] : "Chan-" + std::to_string(k + 1))
54-
.append_child_value("unit", "microvolts")
55-
.append_child_value("type", type);
56-
57-
// make a new outlet
58-
lsl::stream_outlet outlet(info, 0, max_buffered);
59-
std::vector<float> sample(n_channels, 0.0);
60-
61-
// Your device might have its own timer. Or you can decide how often to poll
62-
// your device, as we do here.
63-
int32_t sample_dur_us = 1000000 / (samplingrate > 0 ? samplingrate : 100);
64-
auto t_start = std::chrono::high_resolution_clock::now();
65-
auto next_sample_time = t_start;
66-
67-
// send data forever
68-
std::cout << "Now sending data... " << std::endl;
69-
double starttime = ((double)clock()) / CLOCKS_PER_SEC;
70-
for (unsigned t = 0;; t++) {
71-
// Create random data for the first 8 channels.
72-
for (int c = 0; c < 8; c++) sample[c] = (float)((rand() % 1500) / 500.0 - 1.5);
73-
// For the remaining channels, fill them with a sample counter (wraps at 1M).
74-
std::fill(sample.begin() + 8, sample.end(), (float)(t % 1000000));
75-
76-
// Wait until the next expected sample time.
77-
next_sample_time += std::chrono::microseconds(sample_dur_us);
78-
std::this_thread::sleep_until(next_sample_time);
79-
80-
// send the sample
81-
std::cout << sample[0] << "\t" << sample[n_channels-1] << std::endl;
82-
outlet.push_sample(sample);
83-
}
84-
85-
} catch (std::exception &e) { std::cerr << "Got an exception: " << e.what() << std::endl; }
86-
std::cout << "Press any key to exit. " << std::endl;
87-
std::cin.get();
88-
return 0;
89-
}
1+
#include "lsl_cpp.h"
2+
#include <array>
3+
#include <iostream>
4+
#include <stdlib.h>
5+
#include <thread>
6+
#include <time.h>
7+
8+
/**
9+
* This example program offers an 8-channel stream, float-formatted, that resembles EEG data.
10+
* The example demonstrates also how per-channel meta-data can be specified using the .desc() field
11+
* of the stream information object.
12+
*
13+
* Note that the timer used in the send loop of this program is not particularly accurate.
14+
*/
15+
16+
17+
const char *channels[] = {"C3", "C4", "Cz", "FPz", "POz", "CPz", "O1", "O2"};
18+
19+
int main(int argc, char *argv[]) {
20+
std::string name, type;
21+
if (argc < 3) {
22+
std::cout
23+
<< "This opens a stream under some user-defined name and with a user-defined content "
24+
"type."
25+
<< std::endl;
26+
std::cout << "SendData Name Type n_channels[8] srate[100] max_buffered[360] sync[false] "
27+
"contig[true]"
28+
<< std::endl;
29+
std::cout
30+
<< "Please enter the stream name and the stream type (e.g. \"BioSemi EEG\" (without "
31+
"the quotes)):"
32+
<< std::endl;
33+
std::cin >> name >> type;
34+
} else {
35+
name = argv[1];
36+
type = argv[2];
37+
}
38+
int n_channels = argc > 3 ? std::stol(argv[3]) : 8;
39+
n_channels = n_channels < 8 ? 8 : n_channels;
40+
int samplingrate = argc > 4 ? std::stol(argv[4]) : 100;
41+
int max_buffered = argc > 5 ? std::stol(argv[5]) : 360;
42+
bool sync = argc > 6 ? std::stol(argv[6]) > 0 : false;
43+
bool contig = argc > 7 ? std::stol(argv[7]) > 0 : true;
44+
45+
try {
46+
// if (!sync && !contig) {
47+
// throw std::invalid_argument( "async is incompatible with discontig
48+
//push_numeric_bufs (except for strings, not used here)." );
49+
// }
50+
51+
// make a new stream_info (100 Hz)
52+
lsl::stream_info info(
53+
name, type, n_channels, samplingrate, lsl::cf_float32, std::string(name) += type);
54+
55+
// add some description fields
56+
info.desc().append_child_value("manufacturer", "LSL");
57+
lsl::xml_element chns = info.desc().append_child("channels");
58+
for (int k = 0; k < n_channels; k++)
59+
chns.append_child("channel")
60+
.append_child_value("label", k < 8 ? channels[k] : "Chan-" + std::to_string(k + 1))
61+
.append_child_value("unit", "microvolts")
62+
.append_child_value("type", type);
63+
64+
// make a new outlet
65+
lsl::stream_outlet outlet(
66+
info, 0, max_buffered, sync ? transp_sync_blocking : transp_default);
67+
68+
// Initialize 2 discontiguous data arrays.
69+
std::vector<float> sample(8, 0.0);
70+
std::vector<float> extra(n_channels - 8, 0.0);
71+
// If this is contiguous mode (default) then we combine the arrays.
72+
if (contig) sample.insert(sample.end(), extra.begin(), extra.end());
73+
74+
// bytes is used in !contig mode because we need to know how big each buffer is.
75+
std::array<uint32_t, 2> bytes = {
76+
8 * sizeof(float), static_cast<uint32_t>((n_channels - 8) * sizeof(float))};
77+
78+
// Your device might have its own timer. Or you can decide how often to poll
79+
// your device, as we do here.
80+
int32_t sample_dur_us = 1000000 / (samplingrate > 0 ? samplingrate : 100);
81+
auto t_start = std::chrono::high_resolution_clock::now();
82+
auto next_sample_time = t_start;
83+
84+
// send data forever
85+
std::cout << "Now sending data... " << std::endl;
86+
for (unsigned t = 0;; t++) {
87+
88+
// Create random data for the first 8 channels.
89+
for (int c = 0; c < 8; c++) sample[c] = (float)((rand() % 1500) / 500.0 - 1.5);
90+
// For the remaining channels, fill them with a sample counter (wraps at 1M).
91+
if (contig)
92+
std::fill(sample.begin() + 8, sample.end(), (float)(t % 1000000));
93+
else
94+
std::fill(extra.begin(), extra.end(), (float)(t % 1000000));
95+
96+
// Wait until the next expected sample time.
97+
next_sample_time += std::chrono::microseconds(sample_dur_us);
98+
std::this_thread::sleep_until(next_sample_time);
99+
100+
// send the sample
101+
if (contig) {
102+
std::cout << sample[0] << "\t" << sample[n_channels-1] << std::endl;
103+
outlet.push_sample(sample);
104+
} else {
105+
// Advanced: Push set of discontiguous buffers.
106+
std::array<float *, 2> bufs = {sample.data(), extra.data()};
107+
outlet.push_numeric_bufs(
108+
(void **)bufs.data(), bytes.data(), 2, lsl::local_clock(), true);
109+
}
110+
}
111+
112+
} catch (std::exception &e) { std::cerr << "Got an exception: " << e.what() << std::endl; }
113+
std::cout << "Press any key to exit. " << std::endl;
114+
std::cin.get();
115+
return 0;
116+
}

0 commit comments

Comments
 (0)