LCOV - code coverage report
Current view: top level - src/audio/engine - audio_engine.cpp (source / functions) Coverage Total Hit
Test: merged.info Lines: 71.1 % 114 81
Test Date: 2026-06-03 09:13:19 Functions: 100.0 % 9 9

            Line data    Source code
       1              : #include "audio/engine/audio_engine.h"
       2              : #include "audio/backend/audio_backend.h"
       3              : #include <iostream>
       4              : #include <algorithm>
       5              : #include <nlohmann/json.hpp>
       6              : 
       7              : namespace Amplitron
       8              : {
       9              : 
      10         1154 :     AudioEngine::AudioEngine()
      11          292 :     {
      12          862 :         process_buffer_.resize(MAX_BUFFER_SIZE, 0.0f);
      13          862 :         process_buffer_right_.resize(MAX_BUFFER_SIZE, 0.0f);
      14          862 :         backend_ = create_audio_backend();
      15              : 
      16              :         // Pre-allocate the graph memory pools immediately on startup
      17          862 :         main_executor_ = std::make_shared<AudioGraphExecutor>();
      18              :         // Assuming standard values, use your engine's actual sample rate / block size variables here
      19          862 :         main_executor_->prepare(48000, 512, 32);
      20              : 
      21              :         // Seed the shadow executor so the audio thread has something safe to read instantly
      22          862 :         audio_shadow_executor_ = main_executor_;
      23          862 :     }
      24              : 
      25         1154 :     AudioEngine::~AudioEngine()
      26          292 :     {
      27          862 :         shutdown();
      28              : 
      29          862 :         destroy_audio_backend(backend_);
      30          862 :         backend_ = nullptr;
      31         1737 :     }
      32              : 
      33              :     // --- Serialization Methods ---
      34              : 
      35            9 :     nlohmann::json AudioEngine::serialize()
      36              :     {
      37            9 :         std::lock_guard<std::mutex> lock(effect_mutex_);
      38            9 :         nlohmann::json j;
      39              : 
      40              :         // Read atomic variables safely
      41            9 :         j["input_gain"] = input_gain_.load(std::memory_order_relaxed);
      42              : 
      43            9 :         auto effects_array = nlohmann::json::array();
      44           15 :         for (const auto &fx : dummy_effects_)
      45              :         {
      46            6 :             if (fx)
      47              :             {
      48            6 :                 nlohmann::json fx_json;
      49            6 :                 fx_json["name"] = fx->name();
      50            6 :                 fx_json["params"] = fx->get_params();
      51            6 :                 effects_array.push_back(fx_json);
      52            6 :             }
      53              :         }
      54            9 :         j["effects"] = effects_array;
      55           12 :         return j;
      56            9 :     }
      57              : 
      58            6 :     void AudioEngine::deserialize(const nlohmann::json &j)
      59              :     {
      60            6 :         std::lock_guard<std::mutex> lock(effect_mutex_);
      61              : 
      62            6 :         if (j.contains("input_gain"))
      63              :         {
      64            6 :             set_input_gain(j["input_gain"]);
      65            2 :         }
      66              : 
      67            6 :         if (j.contains("effects"))
      68              :         {
      69           16 :             for (const auto &fx_data : j["effects"])
      70              :             {
      71            6 :                 std::string name = fx_data["name"];
      72           18 :                 for (auto &fx : dummy_effects_)
      73              :                 {
      74           20 :                     if (fx && std::string(fx->name()) == name)
      75              :                     {
      76            6 :                         fx->set_params(fx_data["params"]);
      77            2 :                     }
      78              :                 }
      79            6 :             }
      80            2 :         }
      81            6 :     }
      82              : 
      83              :     // --- Existing Methods ---
      84              : 
      85          162 :     void AudioEngine::set_buffer_size(int size)
      86              :     {
      87          162 :         size = std::max(MIN_BUFFER_SIZE, std::min(MAX_BUFFER_SIZE, size));
      88          162 :         int prev_size = buffer_size_;
      89          162 :         bool was_running = running_;
      90          162 :         if (was_running)
      91            0 :             stop();
      92          162 :         buffer_size_ = size;
      93          162 :         if (was_running)
      94              :         {
      95            0 :             if (!start())
      96              :             {
      97            0 :                 last_error_ = "Failed with buffer size " + std::to_string(size) + ". Reverting.";
      98            0 :                 std::cerr << "[Amplitron] " << last_error_ << std::endl;
      99            0 :                 buffer_size_ = prev_size;
     100            0 :                 start();
     101            0 :             }
     102              :             else
     103              :             {
     104            0 :                 last_error_.clear();
     105              :             }
     106            0 :         }
     107          162 :     }
     108              : 
     109           41 :     void AudioEngine::set_sample_rate(int rate)
     110              :     {
     111           41 :         int prev_rate = sample_rate_;
     112           41 :         bool was_running = running_;
     113           41 :         if (was_running)
     114            0 :             stop();
     115           41 :         sample_rate_ = rate;
     116              : 
     117           14 :         {
     118           41 :             std::lock_guard<std::mutex> lock(effect_mutex_);
     119              :             // FIX: Iterate over the nodes in the new AudioGraph
     120           53 :             for (const auto &node : main_graph_.get_nodes())
     121              :             {
     122           12 :                 if (node.pedal)
     123              :                 { // Check if it's a standard effect and not a bare merge node
     124            9 :                     node.pedal->set_sample_rate(rate);
     125            9 :                     node.pedal->reset();
     126            3 :                 }
     127              :             }
     128           41 :             if (tuner_tap_)
     129              :             {
     130            0 :                 tuner_tap_->set_sample_rate(rate);
     131            0 :                 tuner_tap_->reset();
     132            0 :             }
     133           27 :         }
     134              : 
     135           41 :         if (was_running)
     136              :         {
     137            0 :             if (!start())
     138              :             {
     139            0 :                 last_error_ = "Failed with sample rate " + std::to_string(rate) + " Hz. Reverting.";
     140            0 :                 std::cerr << "[Amplitron] " << last_error_ << std::endl;
     141            0 :                 sample_rate_ = prev_rate;
     142              : 
     143            0 :                 std::lock_guard<std::mutex> lock(effect_mutex_);
     144              :                 // FIX: Revert the sample rates using the graph nodes
     145            0 :                 for (const auto &node : main_graph_.get_nodes())
     146              :                 {
     147            0 :                     if (node.pedal)
     148              :                     {
     149            0 :                         node.pedal->set_sample_rate(prev_rate);
     150            0 :                         node.pedal->reset();
     151            0 :                     }
     152              :                 }
     153            0 :                 if (tuner_tap_)
     154              :                 {
     155            0 :                     tuner_tap_->set_sample_rate(prev_rate);
     156            0 :                     tuner_tap_->reset();
     157            0 :                 }
     158            0 :                 start();
     159            0 :             }
     160              :             else
     161              :             {
     162            0 :                 last_error_.clear();
     163              :             }
     164            0 :         }
     165           41 :     }
     166         1620 :     void AudioEngine::commit_graph_changes()
     167              :     {
     168         1620 :         std::lock_guard<std::mutex> lock(effect_mutex_);
     169              : 
     170              :         // 1. Create a brand new executor (so we don't mutate memory the audio thread is currently reading)
     171         1620 :         auto new_executor = std::make_shared<AudioGraphExecutor>();
     172         1620 :         new_executor->prepare(sample_rate_, buffer_size_, 32);
     173              : 
     174              :         // 2. Compile the latest UI graph into the new executor
     175         1620 :         new_executor->compile(main_graph_);
     176              : 
     177              :         // 3. Promote it to the main slot. The audio thread will grab it on the next try_lock!
     178         1620 :         main_executor_ = new_executor;
     179         1620 :         topology_dirty_.store(true, std::memory_order_release);
     180         1620 :     }
     181              : 
     182              : #ifdef AMPLITRON_TESTS
     183            1 :     void AudioEngine::replace_backend_for_test(AudioBackendState *backend)
     184              :     {
     185            1 :         if (backend_ == backend)
     186              :         {
     187            0 :             return;
     188              :         }
     189              : 
     190            1 :         destroy_audio_backend(backend_);
     191            1 :         backend_ = backend;
     192            0 :     }
     193              : #endif
     194              : }
        

Generated by: LCOV version 2.0-1