LCOV - code coverage report
Current view: top level - src/audio/engine - audio_engine_process.cpp (source / functions) Coverage Total Hit
Test: merged.info Lines: 96.9 % 96 93
Test Date: 2026-06-07 15:51:50 Functions: 100.0 % 2 2

            Line data    Source code
       1              : #include <algorithm>
       2              : #include <cassert>
       3              : #include <chrono>
       4              : #include <cmath>
       5              : #include <cstring>
       6              : 
       7              : #include "audio/engine/analyzer_capture.h"
       8              : #include "audio/engine/audio_engine.h"
       9              : 
      10              : namespace Amplitron {
      11              : 
      12         4625 : void AudioEngine::process_audio(const float* input, float* output, int frame_count) {
      13         4625 :     auto t_start = std::chrono::steady_clock::now();
      14              : 
      15         4625 :     if (frame_count > static_cast<int>(process_buffer_.size())) {
      16            0 :         process_buffer_.resize(frame_count, 0.0f);
      17            0 :         process_buffer_right_.resize(frame_count, 0.0f);
      18            0 :     }
      19              : 
      20         4625 :     const bool analyzer_on = analyzer_capture_->is_analyzer_enabled();
      21              : 
      22         4625 :     float in_gain = input_gain_.load(std::memory_order_relaxed);
      23         4625 :     float peak_in = 0.0f;
      24         4625 :     if (analyzer_on) {
      25           16 :         float sum_sq_in = 0.0f;
      26           16 :         bool clipped_in = false;
      27         7320 :         for (int i = 0; i < frame_count; ++i) {
      28         7296 :             process_buffer_[i] = input[i] * in_gain;
      29         7296 :             float abs_val = std::fabs(process_buffer_[i]);
      30         7296 :             if (abs_val > peak_in) peak_in = abs_val;
      31         7296 :             if (abs_val >= 1.0f) clipped_in = true;
      32         7296 :             sum_sq_in += process_buffer_[i] * process_buffer_[i];
      33         2432 :         }
      34           24 :         input_rms_.store(std::sqrt(sum_sq_in / std::max(frame_count, 1)),
      35              :                          std::memory_order_relaxed);
      36           24 :         if (clipped_in) input_clipped_.store(true, std::memory_order_release);
      37           24 :         analyzer_capture_->capture_input(process_buffer_.data(), frame_count);
      38            8 :     } else {
      39       299129 :         for (int i = 0; i < frame_count; ++i) {
      40       294528 :             process_buffer_[i] = input[i] * in_gain;
      41       294528 :             float abs_val = std::fabs(process_buffer_[i]);
      42       294528 :             if (abs_val > peak_in) peak_in = abs_val;
      43       148672 :         }
      44              :     }
      45         4625 :     input_level_.store(peak_in);
      46              : 
      47         6956 :     std::memcpy(process_buffer_right_.data(), process_buffer_.data(),
      48         4625 :                 static_cast<size_t>(frame_count) * sizeof(float));
      49              : 
      50         4625 :     command_dispatcher_.drain_gain_commands(input_gain_, output_gain_, audio_shadow_executor_);
      51              : 
      52         4625 :     if (effect_mutex_.try_lock()) {
      53         6942 :         command_dispatcher_.drain_commands(input_gain_, output_gain_, audio_shadow_executor_,
      54         4618 :                                            main_graph_, dummy_effects_);
      55         4618 :         if (topology_dirty_.exchange(false, std::memory_order_acq_rel)) {
      56           52 :             audio_shadow_executor_ = main_executor_;
      57           52 :             audio_shadow_tuner_ = tuner_tap_;
      58           22 :         }
      59         4618 :         effect_mutex_.unlock();
      60         2324 :     }
      61              : 
      62         4625 :     if (audio_shadow_tuner_ && audio_shadow_tuner_->is_enabled()) {
      63            3 :         audio_shadow_tuner_->process(process_buffer_.data(), frame_count);
      64            4 :         std::memcpy(process_buffer_right_.data(), process_buffer_.data(),
      65            3 :                     static_cast<size_t>(frame_count) * sizeof(float));
      66            1 :     }
      67              :     // The executor handles all the looping, routing, and processing internally!
      68         4625 :     if (audio_shadow_executor_) {
      69              :         // Broadcast tempo/bpm
      70         4625 :         audio_shadow_executor_->update_transport_state(static_cast<float>(metronome_->get_bpm()));
      71              : 
      72              :         // Pass your mono/stereo buffers to the executor we built
      73         6956 :         audio_shadow_executor_->process(process_buffer_.data(), process_buffer_right_.data(),
      74         2331 :                                         frame_count);
      75         6956 :         std::memcpy(process_buffer_.data(), process_buffer_right_.data(),
      76         4625 :                     static_cast<size_t>(frame_count) * sizeof(float));
      77         2331 :     }
      78              : 
      79         4625 :     float out_gain = output_gain_.load(std::memory_order_relaxed);
      80         4625 :     float peak_out = 0.0f;
      81       305302 :     auto next_metronome_sample = [this]() -> float { return metronome_->next_sample(); };
      82         4625 :     if (analyzer_on) {
      83           16 :         float sum_sq_out = 0.0f;
      84           16 :         bool clipped_out = false;
      85         7320 :         for (int i = 0; i < frame_count; ++i) {
      86         7296 :             float click = next_metronome_sample();
      87         7296 :             float out_l = clamp(process_buffer_[i] * out_gain + click, -1.0f, 1.0f);
      88         7296 :             float out_r = clamp(process_buffer_right_[i] * out_gain + click, -1.0f, 1.0f);
      89         7296 :             if (std::fabs(out_l) >= 1.0f || std::fabs(out_r) >= 1.0f) clipped_out = true;
      90         7296 :             output[i * 2] = out_l;
      91         7296 :             output[i * 2 + 1] = out_r;
      92         7296 :             process_buffer_[i] = out_l;
      93         7296 :             float abs_val = std::fabs(out_l);
      94         7296 :             if (abs_val > peak_out) peak_out = abs_val;
      95         7296 :             sum_sq_out += out_l * out_l;
      96         2432 :         }
      97           24 :         output_rms_.store(std::sqrt(sum_sq_out / std::max(frame_count, 1)),
      98              :                           std::memory_order_relaxed);
      99           24 :         if (clipped_out) output_clipped_.store(true, std::memory_order_release);
     100           24 :         analyzer_capture_->capture_output(process_buffer_.data(), frame_count);
     101            8 :     } else {
     102       299129 :         for (int i = 0; i < frame_count; ++i) {
     103       294528 :             float click = next_metronome_sample();
     104       294528 :             float out_l = clamp(process_buffer_[i] * out_gain + click, -1.0f, 1.0f);
     105       294528 :             float out_r = clamp(process_buffer_right_[i] * out_gain + click, -1.0f, 1.0f);
     106       294528 :             output[i * 2] = out_l;
     107       294528 :             output[i * 2 + 1] = out_r;
     108       294528 :             process_buffer_[i] = out_l;
     109       294528 :             float abs_val = std::fabs(out_l);
     110       294528 :             if (abs_val > peak_out) peak_out = abs_val;
     111       148672 :         }
     112              :     }
     113         4625 :     output_level_.store(peak_out);
     114              : 
     115         4625 :     if (recorder_->is_recording()) {
     116            4 :         recorder_->write_samples_stereo(process_buffer_.data(), process_buffer_right_.data(),
     117            1 :                                         frame_count);
     118            1 :     }
     119              : 
     120         4625 :     auto t_end = std::chrono::steady_clock::now();
     121         4625 :     float duration_us = std::chrono::duration<float, std::micro>(t_end - t_start).count();
     122         4625 :     callback_duration_us_.store(duration_us, std::memory_order_relaxed);
     123         4625 :     float budget_us = (static_cast<float>(frame_count) / sample_rate_) * 1e6f;
     124         4625 :     cpu_load_.store(duration_us / budget_us, std::memory_order_relaxed);
     125         4625 : }
     126              : 
     127              : }  // namespace Amplitron
        

Generated by: LCOV version 2.0-1