MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ processing_function()

void MayaFlux::Buffers::FeedbackProcessor::processing_function ( const std::shared_ptr< Buffer > &  buffer)
overridevirtual

The core processing function that must be implemented by derived classes.

Parameters
bufferBuffer to process

This method is where the actual transformation logic is implemented. It should contain the algorithmic details of how the buffer's data is transformed, analyzed, or processed. The implementation can utilize any backend capabilities available to the processor, including:

  • Parallel Processing: Using multi-threading or GPU compute for large datasets
  • Data Transformations: Applying mathematical operations, filters, or effects
  • Feature Extraction: Analyzing data characteristics for further processing

Derived classes must override this method to provide specific processing behavior.

Implements MayaFlux::Buffers::BufferProcessor.

Definition at line 314 of file FeedbackBuffer.cpp.

315{
316 auto audio = std::dynamic_pointer_cast<AudioBuffer>(buffer);
317 if (!audio) {
318 return;
319 }
320
321 const bool use_step = static_cast<bool>(m_step);
322 const bool use_kernel = !use_step && !m_combine && static_cast<bool>(m_kernel);
323 if (!use_step && !use_kernel && !m_combine) {
324 return;
325 }
326
327 auto& data = audio->get_data();
328 const size_t samples = data.size();
329 const size_t taps = m_taps.size();
330 if (samples == 0 || taps == 0) {
331 return;
332 }
333
334 State& state = state_for(buffer);
335 auto& ring = *state.ring;
336
337 if (ring.capacity() < m_capacity) {
338 ring.resize(m_capacity);
339 }
340
341 if (state.values.size() != taps) {
342 state.values.assign(taps, 0.0);
343 state.window.assign(taps + 1, 0.0);
344 state.lag_prev.assign(taps, 1.0);
345 state.lag_now.assign(taps, 1.0);
346 state.primed = false;
347 }
348
349 const auto source = m_lag_source.lock();
350 const bool foreign = source && static_cast<const Buffer*>(source.get()) != buffer.get();
351
352 const Memory::HistoryBuffer<double>* read_ring = &ring;
353 double offset = 0.0;
354 if (foreign) {
355 auto& source_ring = source->get_history_buffer();
356 if (source_ring.capacity() < m_capacity + samples) {
357 source_ring.resize(m_capacity + samples);
358 }
359 read_ring = &source_ring;
360 offset = static_cast<double>(source->get_write_count()) - static_cast<double>(state.elapsed);
361 }
362
363 const size_t extra = m_order > 1 ? m_order : 0;
364 const auto rate = static_cast<double>(s_registered_sample_rate);
365 const auto seconds = static_cast<double>(state.elapsed) / rate;
366 const double lowest = foreign ? std::max(1.0, static_cast<double>(samples)) : 1.0;
367 const double highest = std::max(static_cast<double>((foreign ? m_capacity : ring.capacity()) - extra), lowest);
368
369 for (size_t t = 0; t < taps; ++t) {
370 const double raw = m_taps[t].map ? (*m_taps[t].map)(seconds) * rate : m_taps[t].samples;
371 state.lag_now[t] = std::clamp(raw, lowest, highest);
372 }
373 if (!state.primed) {
374 state.lag_prev = state.lag_now;
375 state.primed = true;
376 }
377
378 const double inverse = 1.0 / static_cast<double>(samples);
379 const bool plain_read = !foreign && m_order <= 1;
380
381 for (size_t i = 0; i < samples; ++i) {
382 const double ramp = static_cast<double>(i + 1) * inverse;
383 const double shift = foreign ? offset - static_cast<double>(i) : 0.0;
384
385 for (size_t t = 0; t < taps; ++t) {
386 const double lag = state.lag_prev[t] + (state.lag_now[t] - state.lag_prev[t]) * ramp;
387 state.values[t] = plain_read ? read(ring, lag) : read_at(*read_ring, lag - 1.0 + shift, m_order);
388 }
389
390 const std::span<const double> tap_values(state.values);
391 const std::span<double> coefs(state.coefs);
392
393 double out {};
394 double carry {};
395 if (use_step) {
396 const auto [step_out, step_carry] = m_step(data[i], tap_values, coefs);
397 out = step_out;
398 carry = step_carry;
399 } else if (use_kernel) {
400 state.window[0] = data[i];
401 std::copy(state.values.begin(), state.values.end(), state.window.begin() + 1);
402 out = m_kernel(std::span<double>(state.window), coefs);
403 carry = out;
404 } else {
405 out = m_combine(data[i], tap_values, coefs);
406 carry = out;
407 }
408
409 data[i] = out;
410 ring.push(carry);
411 }
412
413 state.lag_prev = state.lag_now;
414 state.elapsed += samples;
415
416 if (auto owner = std::dynamic_pointer_cast<FeedbackBuffer>(buffer)) {
417 owner->mark_written(samples);
418 }
419}
uint64_t offset
Definition Composite.cpp:10
float rate
std::shared_ptr< NetworkGeometryBuffer > buffer
std::vector< float > * out
std::weak_ptr< FeedbackBuffer > m_lag_source
static double read_at(const Memory::HistoryBuffer< double > &ring, double position, size_t order) noexcept
State & state_for(const std::shared_ptr< Buffer > &buffer)
static double read(const Memory::HistoryBuffer< double > &ring, double lag)
uint64_t s_registered_sample_rate
Global default sample rate.
double ramp(double edge0, double edge1, double x) noexcept
Hermite ramp from 0 at edge0 to 1 at edge1.
Source source()
Begin a Source chain.
Definition Plot.hpp:127

References buffer, MayaFlux::Buffers::FeedbackProcessor::State::coefs, MayaFlux::Buffers::FeedbackProcessor::State::elapsed, MayaFlux::Buffers::FeedbackProcessor::State::lag_now, MayaFlux::Buffers::FeedbackProcessor::State::lag_prev, m_capacity, m_combine, m_kernel, m_lag_source, m_order, m_step, m_taps, offset, out, MayaFlux::Buffers::FeedbackProcessor::State::primed, rate, read(), read_at(), MayaFlux::Memory::HistoryBuffer< T >::resize(), MayaFlux::Buffers::FeedbackProcessor::State::ring, MayaFlux::Buffers::s_registered_sample_rate, state_for(), MayaFlux::Buffers::FeedbackProcessor::State::values, and MayaFlux::Buffers::FeedbackProcessor::State::window.

+ Here is the call graph for this function: