Skip to content

Commit db67ca6

Browse files
committed
SendDataInChunks update
* use double-typed max_buffered * use integer-frequency sine waves so 1-sec pattern has no discontinuities. * add CLI option to not use test patterns (for debugging).
1 parent f90225f commit db67ca6

File tree

1 file changed

+14
-9
lines changed

1 file changed

+14
-9
lines changed

examples/SendDataInChunks.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ struct fake_device {
4444
pattern.reserve(pattern_samples * n_channels);
4545
for (auto sample_ix = 0; sample_ix < pattern_samples; ++sample_ix) {
4646
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);
4749
pattern.emplace_back(
4850
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)));
5052
}
5153
}
5254
last_time = std::chrono::steady_clock::now();
@@ -64,15 +66,15 @@ struct fake_device {
6466
return output;
6567
}
6668

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) {
6870
auto now = std::chrono::steady_clock::now();
6971
auto elapsed_nano =
7072
std::chrono::duration_cast<std::chrono::nanoseconds>(now - last_time).count();
7173
int64_t elapsed_samples = std::size_t(elapsed_nano * srate * 1e-9); // truncate OK.
7274
elapsed_samples = std::min(elapsed_samples, (int64_t)(buffer.size() / n_channels));
73-
if (false) {
75+
if (nodata) {
7476
// 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]);
7678
} else {
7779
std::size_t end_sample = head + elapsed_samples;
7880
std::size_t nowrap_samples = std::min(pattern_samples - head, elapsed_samples);
@@ -89,22 +91,24 @@ struct fake_device {
8991

9092
int main(int argc, char **argv) {
9193
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" << std::endl;
9395
std::cout << "- max_buffered -- duration in sec (or x100 samples if samplerate is 0) to buffer for each outlet" << std::endl;
9496
std::cout << "- chunk_rate -- number of chunks pushed per second. For this example, make it a common factor of samplingrate and 1000." << std::endl;
97+
std::cout << "- nodata -- Set non-zero to cause the fake device to not copy pattern data into the buffer." << std::endl;
9598

9699
std::string name{argc > 1 ? argv[1] : "MyAudioStream"}, type{argc > 2 ? argv[2] : "Audio"};
97100
int samplingrate = argc > 3 ? std::stol(argv[3]) : 44100; // Here we specify srate, but typically this would come from the device.
98101
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;
102+
double max_buffered = argc > 5 ? std::stod(argv[5]) : 360.;
100103
int32_t chunk_rate = argc > 6 ? std::stol(argv[6]) : 10; // Chunks per second.
104+
bool nodata = argc > 7;
101105
int32_t chunk_samples = samplingrate > 0 ? std::max((samplingrate / chunk_rate), 1) : 100; // Samples per chunk.
102106
int32_t chunk_duration = 1000 / chunk_rate; // Milliseconds per chunk
103107

104108
try {
105109
// Prepare the LSL stream.
106110
lsl::stream_info info(name, type, n_channels, samplingrate, lsl::cf_int16);
107-
lsl::stream_outlet outlet(info, 0, max_buffered);
111+
lsl::stream_outlet outlet(info, chunk_samples, max_buffered);
108112
lsl::xml_element desc = info.desc();
109113
desc.append_child_value("manufacturer", "LSL");
110114
lsl::xml_element chns = desc.append_child("channels");
@@ -121,6 +125,7 @@ int main(int argc, char **argv) {
121125
// Prepare buffer to get data from 'device'.
122126
// The buffer should be larger than you think you need. Here we make it 4x as large.
123127
std::vector<int16_t> chunk_buffer(4 * chunk_samples * n_channels);
128+
std::fill(chunk_buffer.begin(), chunk_buffer.end(), 0);
124129

125130
std::cout << "Now sending data..." << std::endl;
126131

@@ -133,11 +138,11 @@ int main(int argc, char **argv) {
133138
std::this_thread::sleep_until(next_chunk_time);
134139

135140
// Get data from device
136-
std::size_t returned_samples = my_device.get_data(chunk_buffer);
141+
std::size_t returned_samples = my_device.get_data(chunk_buffer, nodata);
137142

138143
// send it to the outlet. push_chunk_multiplexed is one of the more complicated approaches.
139144
// other push_chunk methods are easier but slightly slower.
140-
outlet.push_chunk_multiplexed(chunk_buffer.data(), returned_samples * n_channels, 0.0, true);
145+
outlet.push_chunk_multiplexed(chunk_buffer.data(), returned_samples * n_channels, 0.0, false);
141146
}
142147

143148
} catch (std::exception &e) { std::cerr << "Got an exception: " << e.what() << std::endl; }

0 commit comments

Comments
 (0)