@@ -44,9 +44,11 @@ struct fake_device {
44
44
pattern.reserve (pattern_samples * n_channels);
45
45
for (auto sample_ix = 0 ; sample_ix < pattern_samples; ++sample_ix) {
46
46
for (auto chan_ix = 0 ; chan_ix < n_channels; ++chan_ix) {
47
+ // sin(2*pi*f*t), where f cycles from 1 Hz to Nyquist: srate / 2
48
+ double f = (chan_ix + 1 ) % (int )(srate / 2 );
47
49
pattern.emplace_back (
48
50
offset_0 + chan_ix * offset_step +
49
- magnitude * static_cast <int16_t >(sin (M_PI * chan_ix * sample_ix / n_channels )));
51
+ magnitude * static_cast <int16_t >(sin (2 * M_PI * f * sample_ix / srate )));
50
52
}
51
53
}
52
54
last_time = std::chrono::steady_clock::now ();
@@ -64,15 +66,15 @@ struct fake_device {
64
66
return output;
65
67
}
66
68
67
- std::size_t get_data (std::vector<int16_t > &buffer) {
69
+ std::size_t get_data (std::vector<int16_t > &buffer, bool nodata = false ) {
68
70
auto now = std::chrono::steady_clock::now ();
69
71
auto elapsed_nano =
70
72
std::chrono::duration_cast<std::chrono::nanoseconds>(now - last_time).count ();
71
73
int64_t elapsed_samples = std::size_t (elapsed_nano * srate * 1e-9 ); // truncate OK.
72
74
elapsed_samples = std::min (elapsed_samples, (int64_t )(buffer.size () / n_channels));
73
- if (false ) {
75
+ if (nodata ) {
74
76
// The fastest but no patterns.
75
- memset (&buffer[0 ], 23 , buffer.size () * sizeof buffer[0 ]);
77
+ // memset(&buffer[0], 23, buffer.size() * sizeof buffer[0]);
76
78
} else {
77
79
std::size_t end_sample = head + elapsed_samples;
78
80
std::size_t nowrap_samples = std::min (pattern_samples - head, elapsed_samples);
@@ -89,22 +91,26 @@ struct fake_device {
89
91
90
92
int main (int argc, char **argv) {
91
93
std::cout << " SendDataInChunks" << std::endl;
92
- std::cout << " SendDataInChunks StreamName StreamType samplerate n_channels max_buffered chunk_rate" << std::endl;
94
+ std::cout << " SendDataInChunks StreamName StreamType samplerate n_channels max_buffered chunk_rate nodata use_sync " << std::endl;
93
95
std::cout << " - max_buffered -- duration in sec (or x100 samples if samplerate is 0) to buffer for each outlet" << std::endl;
94
96
std::cout << " - chunk_rate -- number of chunks pushed per second. For this example, make it a common factor of samplingrate and 1000." << std::endl;
95
-
97
+ std::cout << " - nodata -- Set non-zero to cause the fake device to not copy pattern data into the buffer." << std::endl;
98
+ std::cout << " - use_sync -- Set to non-zero to use blocking send." << std::endl;
99
+
96
100
std::string name{argc > 1 ? argv[1 ] : " MyAudioStream" }, type{argc > 2 ? argv[2 ] : " Audio" };
97
101
int samplingrate = argc > 3 ? std::stol (argv[3 ]) : 44100 ; // Here we specify srate, but typically this would come from the device.
98
102
int n_channels = argc > 4 ? std::stol (argv[4 ]) : 2 ; // Here we specify n_chans, but typically this would come from theh device.
99
- int32_t max_buffered = argc > 5 ? std::stol (argv[5 ]) : 360 ;
103
+ double max_buffered = argc > 5 ? std::stod (argv[5 ]) : 360 . ;
100
104
int32_t chunk_rate = argc > 6 ? std::stol (argv[6 ]) : 10 ; // Chunks per second.
105
+ bool nodata = argc > 7 ;
106
+ bool do_sync = argc > 8 ? (bool )std::stol (argv[8 ]) : true ;
107
+
101
108
int32_t chunk_samples = samplingrate > 0 ? std::max ((samplingrate / chunk_rate), 1 ) : 100 ; // Samples per chunk.
102
109
int32_t chunk_duration = 1000 / chunk_rate; // Milliseconds per chunk
103
110
104
111
try {
105
112
// Prepare the LSL stream.
106
- lsl::stream_info info (name, type, n_channels, samplingrate, lsl::cf_int16);
107
- lsl::stream_outlet outlet (info, 0 , max_buffered);
113
+ lsl::stream_info info (name, type, n_channels, samplingrate, lsl::cf_int16, " example-SendDataInChunks" );
108
114
lsl::xml_element desc = info.desc ();
109
115
desc.append_child_value (" manufacturer" , " LSL" );
110
116
lsl::xml_element chns = desc.append_child (" channels" );
@@ -114,13 +120,19 @@ int main(int argc, char **argv) {
114
120
chn.append_child_value (" unit" , " microvolts" );
115
121
chn.append_child_value (" type" , " EEG" );
116
122
}
123
+ int32_t buf_samples = max_buffered * samplingrate;
124
+ lsl::stream_outlet outlet (info, chunk_samples, buf_samples,
125
+ transp_bufsize_samples | (do_sync ? transp_sync_blocking: transp_default));
126
+ info = outlet.info (); // Refresh info with whatever the outlet captured.
127
+ std::cout << " Stream UID: " << info.uid () << std::endl;
117
128
118
129
// Create a connection to our device.
119
130
fake_device my_device (n_channels, (float )samplingrate);
120
131
121
132
// Prepare buffer to get data from 'device'.
122
133
// The buffer should be larger than you think you need. Here we make it 4x as large.
123
134
std::vector<int16_t > chunk_buffer (4 * chunk_samples * n_channels);
135
+ std::fill (chunk_buffer.begin (), chunk_buffer.end (), 0 );
124
136
125
137
std::cout << " Now sending data..." << std::endl;
126
138
@@ -133,11 +145,12 @@ int main(int argc, char **argv) {
133
145
std::this_thread::sleep_until (next_chunk_time);
134
146
135
147
// Get data from device
136
- std::size_t returned_samples = my_device.get_data (chunk_buffer);
148
+ std::size_t returned_samples = my_device.get_data (chunk_buffer, nodata );
137
149
138
150
// send it to the outlet. push_chunk_multiplexed is one of the more complicated approaches.
139
151
// other push_chunk methods are easier but slightly slower.
140
- outlet.push_chunk_multiplexed (chunk_buffer.data (), returned_samples * n_channels, 0.0 , true );
152
+ double ts = lsl::local_clock ();
153
+ outlet.push_chunk_multiplexed (chunk_buffer.data (), returned_samples * n_channels, ts, true );
141
154
}
142
155
143
156
} catch (std::exception &e) { std::cerr << " Got an exception: " << e.what () << std::endl; }
0 commit comments