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

◆ process_batch()

void MayaFlux::Nodes::Network::ModalNetwork::process_batch ( unsigned int  num_samples)
overridevirtual

Process the network for the given number of samples.

Parameters
num_samplesNumber of samples/frames to process

Subclasses implement their specific processing logic:

  1. Update internal state (physics, relationships, etc.)
  2. Process individual nodes
  3. Apply inter-node interactions
  4. Aggregate outputs if needed

Called by NodeGraphManager during token processing.

Implements MayaFlux::Nodes::Network::NodeNetwork.

Definition at line 313 of file ModalNetwork.cpp.

314{
316
317 if (!is_enabled()) {
318 while (m_audio_buffer_lock.test_and_set(std::memory_order_acquire))
319 std::this_thread::yield();
320
321 m_last_audio_buffer.assign(num_samples, 0.0);
322 m_audio_buffer_lock.clear(std::memory_order_release);
323 return;
324 }
325
326 thread_local std::vector<double> scratch;
327 scratch.assign(num_samples, 0.0);
328
330
331 m_node_buffers.assign(m_modes.size(), {});
332 for (auto& nb : m_node_buffers)
333 nb.reserve(num_samples);
334
335 if (m_exciter_node) {
337 m_exciter_node_buffer_pos, num_samples);
338
341 if (!peaks.empty()) {
342 const double peak_scale = 1.0 / static_cast<double>(peaks.size());
343 for (size_t peak_idx : peaks) {
344 const double strength = std::abs(m_exciter_node_buffer[peak_idx])
345 * m_exciter_strength * peak_scale;
346 for (auto& mode : m_modes) {
347 const double target = mode.initial_amplitude * strength;
348 mode.amplitude = std::max(mode.amplitude, target);
349 }
350 }
351 }
354 if (m_exciter_active) {
356 if (!peaks.empty()) {
357 const auto max_peak = *std::ranges::max_element(peaks,
358 [this](size_t a, size_t b) {
359 return std::abs(m_exciter_node_buffer[a]) < std::abs(m_exciter_node_buffer[b]);
360 });
361 const double strength = std::abs<double>(m_exciter_node_buffer[max_peak]) * m_exciter_strength;
362 for (auto& mode : m_modes) {
363 const double target = mode.initial_amplitude * strength;
364 mode.amplitude = std::max<double>(mode.amplitude, target);
365 }
366 }
367 }
368 }
369 }
370
371 for (size_t i = 0; i < num_samples; ++i) {
372 double exciter_signal = generate_exciter_sample();
373
374 if (exciter_signal != 0.0) {
376 for (auto& mode : m_modes) {
377 mode.amplitude += exciter_signal * mode.initial_amplitude
379 }
380 }
381 }
382
383 if (m_coupling_enabled && !m_couplings.empty())
385
386 for (size_t m = 0; m < m_modes.size(); ++m) {
387 auto& mode = m_modes[m];
388
389 if (mode.amplitude > 0.0001) {
390 mode.amplitude *= mode.decay_coefficient;
391 } else {
392 mode.amplitude = 0.0;
393 }
394
395 double sample = mode.oscillator->process_sample(0.0) * mode.amplitude;
396 m_node_buffers[m].push_back(sample);
397 scratch[i] += sample;
398 }
399 }
400
401 while (m_audio_buffer_lock.test_and_set(std::memory_order_acquire))
402 std::this_thread::yield();
403
404 m_last_audio_buffer.assign(scratch.begin(), scratch.end());
406 m_audio_buffer_lock.clear(std::memory_order_release);
407}
size_t a
size_t b
std::vector< std::vector< double > > m_node_buffers
Per-mode sample buffers populated each process_batch()
@ FILTERED_NOISE
Spectrally-shaped noise burst.
@ CONTINUOUS
External node as continuous exciter.
std::vector< ModeCoupling > m_couplings
void compute_mode_coupling()
Apply modal coupling energy transfer.
double generate_exciter_sample()
Generate exciter signal for current sample.
std::vector< double > m_exciter_node_buffer
void update_mapped_parameters()
Update mapped parameters before processing.
void apply_output_scale()
Apply m_output_scale to m_last_audio_buffer.
static void extract_node_samples(const std::shared_ptr< Nodes::Node > &node, std::vector< double > &buffer, size_t &buffer_pos, size_t num_samples)
Extract num_samples from node into buffer using snapshot guard.
bool is_enabled() const
Check if network is enabled.
std::atomic_flag m_audio_buffer_lock
Spinlock guarding m_last_audio_buffer.
void ensure_initialized()
Ensure initialize() is called exactly once.
std::vector< double > m_last_audio_buffer
std::vector< double > mode(std::span< const double > data, size_t n_windows, uint32_t hop_size, uint32_t window_size)
Mode per window via tolerance-bucketed frequency count.
Definition Analysis.cpp:559
std::vector< size_t > peak_positions(std::span< const double > data, double threshold, size_t min_distance)
Sample indices of local peak maxima in the full span.
Definition Analysis.cpp:669

References a, MayaFlux::Nodes::Network::NodeNetwork::apply_output_scale(), b, compute_mode_coupling(), CONTINUOUS, MayaFlux::Nodes::Network::NodeNetwork::ensure_initialized(), MayaFlux::Nodes::Network::NodeNetwork::extract_node_samples(), FILTERED_NOISE, generate_exciter_sample(), MayaFlux::Nodes::Network::NodeNetwork::is_enabled(), MayaFlux::Nodes::Network::NodeNetwork::m_audio_buffer_lock, m_coupling_enabled, m_couplings, m_exciter_active, m_exciter_node, m_exciter_node_buffer, m_exciter_node_buffer_pos, m_exciter_strength, m_exciter_type, MayaFlux::Nodes::Network::NodeNetwork::m_last_audio_buffer, m_modes, m_node_buffers, NOISE_BURST, MayaFlux::Kinesis::Discrete::peak_positions(), and update_mapped_parameters().

+ Here is the call graph for this function: