296{
299
300 if (op.m_capture.m_data_ready_callback) {
301 op.m_capture.m_data_ready_callback(buffer_data, cycle);
302 }
303
304 auto capture_mode = op.m_capture.get_mode();
305
306 switch (capture_mode) {
309 break;
310
315 } else {
316 try {
317 auto&
existing = std::get<std::vector<double>>(it->second);
318 const auto& new_data = std::get<std::vector<double>>(buffer_data);
320
321 } catch (const std::bad_variant_access& e) {
324 "Data type mismatch during ACCUMULATE capture: {}",
325 e.what());
327 }
328 }
329 break;
330 }
332 uint32_t circular_size = op.m_capture.get_circular_size();
333 if (circular_size == 0) {
334 circular_size = 4096;
335 }
336
340 } else {
341 try {
342 auto& circular = std::get<std::vector<double>>(it->second);
343 const auto& new_data = std::get<std::vector<double>>(buffer_data);
344
345 circular.insert(circular.end(), new_data.begin(), new_data.end());
346
347 if (circular.size() > circular_size) {
348 circular.erase(circular.begin(),
349 circular.begin() + static_cast<int64_t>(circular.size() - circular_size));
350 }
351
352 } catch (const std::bad_variant_access& e) {
355 "Data type mismatch during CIRCULAR capture: {}",
356 e.what());
358 } catch (std::exception& e) {
361 std::source_location::current(),
362 "Error during CIRCULAR capture: {}",
363 e.what());
365 }
366 }
367 break;
368 }
370 uint32_t window_size = op.m_capture.get_window_size();
371 float overlap_ratio = op.m_capture.get_overlap_ratio();
372
373 if (window_size == 0) {
374 window_size = 512;
375 }
376
377 auto hop_size = static_cast<uint32_t>((float)window_size * (1.0F - overlap_ratio));
378 if (hop_size == 0)
379 hop_size = 1;
380
384 } else {
385 try {
386 auto& windowed = std::get<std::vector<double>>(it->second);
387 const auto& new_data = std::get<std::vector<double>>(buffer_data);
388
389 if (windowed.size() >= window_size) {
390 if (hop_size >= windowed.size()) {
391 windowed = std::get<std::vector<double>>(buffer_data);
392 } else {
393 windowed.erase(windowed.begin(),
394 windowed.begin() + hop_size);
395
396 windowed.insert(windowed.end(), new_data.begin(), new_data.end());
397
398 if (windowed.size() > window_size) {
399 size_t excess = windowed.size() - window_size;
400 windowed.erase(windowed.begin(),
401 windowed.begin() + excess);
402 }
403 }
404 } else {
405 windowed.insert(windowed.end(), new_data.begin(), new_data.end());
406
407 if (windowed.size() > window_size) {
408 size_t excess = windowed.size() - window_size;
409 windowed.erase(windowed.begin(),
410 windowed.begin() + excess);
411 }
412 }
413
414 } catch (const std::bad_variant_access& e) {
416 "Data type mismatch during WINDOWED capture: {}", e.what());
418 }
419 }
420 break;
421 }
422
424 if (op.m_capture.m_stop_condition && op.m_capture.m_stop_condition()) {
426 }
427 break;
428 }
429
430 default:
432 break;
433 }
434
437 [&op](const BufferOperation& o) { return &o == &op; });
438
440 auto next_it = std::next(current_it);
442
443 if (next_it->m_target_buffer) {
445 } else if (next_it->m_target_container) {
447 }
448
449 size_t route_index = std::distance(
m_operations.begin(), next_it);
452 }
453 }
454 }
455 }
456}
#define MF_ERROR(comp, ctx,...)
Cycle Behavior: The for_cycles(N) configuration controls how many times the capture operation execute...
@ TRANSIENT
Single cycle capture (default) - data expires after 1 cycle.
@ CIRCULAR
Circular buffer with overwrite.
@ ACCUMULATE
Accumulate over multiple cycles in container.
@ WINDOWED
Rolling window capture with overlap.
@ TRIGGERED
Capture only when condition met.
@ ROUTE
Route data to destination (buffer or container)
std::unordered_map< BufferOperation *, Kakshya::DataVariant > m_operation_data
@ CONSUMED
Data has been processed.
static void write_to_container(const std::shared_ptr< Kakshya::DynamicSoundStream > &container, const Kakshya::DataVariant &data)
std::vector< BufferOperation > m_operations
std::vector< DataState > m_data_states
static void write_to_buffer(const std::shared_ptr< Buffers::AudioBuffer > &buffer, const Kakshya::DataVariant &data)
bool has_immediate_routing(const BufferOperation &op) const
static Kakshya::DataVariant extract_buffer_data(const std::shared_ptr< Buffers::AudioBuffer > &buffer, bool should_process=false)
@ CoroutineScheduling
Coroutine scheduling and temporal coordination (Vruta::TaskScheduler)
void error_rethrow(Component component, Context context, std::source_location location=std::source_location::current(), std::string_view additional_context="")
Catch and log an exception, then rethrow it.
@ Kriya
Automatable tasks and fluent scheduling api for Nodes and Buffers.