LCOV - code coverage report
Current view: top level - src/gui/commands - command_preset.h (source / functions) Coverage Total Hit
Test: merged.info Lines: 98.4 % 63 62
Test Date: 2026-06-03 09:13:19 Functions: 91.7 % 12 11

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include "audio/engine/audio_engine.h"
       4              : #include "audio/effects/effect.h"
       5              : #include "gui/commands/command_base.h"
       6              : #include <vector>
       7              : #include <utility>
       8              : 
       9              : namespace Amplitron {
      10              : 
      11              : /**
      12              :  * @brief Command that captures the full effect-chain state before and after a
      13              :  *        preset load, enabling undo/redo of the entire preset switch.
      14              :  *
      15              :  * Uses AudioEngine::restore_effects_state() so the effect chain is replaced
      16              :  * atomically under the engine's mutex.
      17              :  */
      18              : class LoadPresetCommand : public Command {
      19              : public:
      20              :   /**
      21              :    * @brief Snapshot of a single effect's configuration at a point in time.
      22              :    */
      23          235 :   struct EffectSnapshot {
      24              :     std::shared_ptr<Effect> effect;  ///< The effect instance.
      25              :     bool enabled;                    ///< Whether the effect was enabled.
      26              :     float mix;                       ///< Dry/wet mix level.
      27              :     std::vector<float> param_values; ///< Ordered parameter values.
      28              :   };
      29              : 
      30              :   /**
      31              :    * @brief Construct a LoadPresetCommand.
      32              :    * @param engine             Reference to the audio engine.
      33              :    * @param before_state       Effect chain snapshot before the load.
      34              :    * @param before_input_gain  Input gain before the load.
      35              :    * @param before_output_gain Output gain before the load.
      36              :    * @param after_state        Effect chain snapshot after the load.
      37              :    * @param after_input_gain   Input gain after the load.
      38              :    * @param after_output_gain  Output gain after the load.
      39              :    */
      40           36 :   LoadPresetCommand(AudioEngine &engine,
      41              :                     std::vector<EffectSnapshot> before_state,
      42              :                     float before_input_gain, float before_output_gain,
      43              :                     std::vector<EffectSnapshot> after_state,
      44              :                     float after_input_gain, float after_output_gain)
      45           36 :       : engine_(engine), before_state_(std::move(before_state)),
      46           27 :         before_input_gain_(before_input_gain),
      47           27 :         before_output_gain_(before_output_gain),
      48           27 :         after_state_(std::move(after_state)),
      49           27 :         after_input_gain_(after_input_gain),
      50           45 :         after_output_gain_(after_output_gain) {}
      51              : 
      52              :   /** @brief Restore the after-load state (redo). */
      53            3 :   bool execute() override {
      54            3 :     apply_state(after_state_, after_input_gain_, after_output_gain_);
      55            3 :     return true;
      56              :   }
      57              : 
      58              :   /** @brief Restore the before-load state (undo). */
      59            3 :   void undo() override {
      60            3 :     apply_state(before_state_, before_input_gain_, before_output_gain_);
      61            3 :   }
      62              : 
      63              :   /** @brief Return "Load Preset". */
      64            0 :   const char *description() const override { return "Load Preset"; }
      65              : 
      66              : private:
      67              :   /**
      68              :    * @brief Replace the engine's effect chain and gains with the given snapshot.
      69              :    * @param state        Vector of EffectSnapshot to restore.
      70              :    * @param input_gain   Input gain to set.
      71              :    * @param output_gain  Output gain to set.
      72              :    */
      73            6 :   void apply_state(const std::vector<EffectSnapshot> &state, float input_gain,
      74              :                    float output_gain) {
      75              :     // Prepare effect list with restored params before swapping
      76            6 :     std::vector<std::shared_ptr<Effect>> new_effects;
      77            6 :     new_effects.reserve(state.size());
      78           15 :     for (auto &snap : state) {
      79            9 :       snap.effect->set_enabled(snap.enabled);
      80            9 :       snap.effect->set_mix(snap.mix);
      81            9 :       auto &params = snap.effect->params();
      82           59 :       for (int i = 0; i < static_cast<int>(params.size()) &&
      83           30 :                       i < static_cast<int>(snap.param_values.size());
      84           10 :            ++i) {
      85           30 :         params[i].value = snap.param_values[i];
      86           10 :       }
      87            9 :       new_effects.push_back(snap.effect);
      88              :     }
      89              : 
      90              :     // Atomic swap under engine lock — audio thread never sees half-applied
      91              :     // state
      92            6 :     engine_.restore_effects_state(std::move(new_effects));
      93              : 
      94            6 :     engine_.set_input_gain(input_gain);
      95            6 :     engine_.set_output_gain(output_gain);
      96            6 :   }
      97              : 
      98              :   AudioEngine &engine_;
      99              :   std::vector<EffectSnapshot> before_state_;
     100              :   float before_input_gain_;
     101              :   float before_output_gain_;
     102              :   std::vector<EffectSnapshot> after_state_;
     103              :   float after_input_gain_;
     104              :   float after_output_gain_;
     105              : };
     106              : 
     107              : /**
     108              :  * @brief Command that applies a stored in-session snapshot (A/B/C/D) to the
     109              :  * engine.
     110              :  *
     111              :  * Semantically identical to LoadPresetCommand but describes itself as
     112              :  * "Recall Snapshot" in the undo/redo menu. Constructed from a pair of
     113              :  * SnapshotManager::BoardSnapshot values (before/after) by GuiSnapshots.
     114              :  */
     115              : class RecallSnapshotCommand : public Command {
     116              : public:
     117              :   using EffectSnapshot = LoadPresetCommand::EffectSnapshot;
     118              : 
     119           36 :   RecallSnapshotCommand(AudioEngine &engine,
     120              :                         std::vector<EffectSnapshot> before_effects,
     121              :                         float before_input_gain, float before_output_gain,
     122              :                         std::vector<EffectSnapshot> after_effects,
     123              :                         float after_input_gain, float after_output_gain)
     124           36 :       : engine_(engine), before_effects_(std::move(before_effects)),
     125           27 :         before_input_gain_(before_input_gain),
     126           27 :         before_output_gain_(before_output_gain),
     127           27 :         after_effects_(std::move(after_effects)),
     128           27 :         after_input_gain_(after_input_gain),
     129           45 :         after_output_gain_(after_output_gain) {}
     130              : 
     131              :   /** @brief Restore the after-recall state (redo). */
     132           27 :   bool execute() override {
     133           27 :     apply_state(after_effects_, after_input_gain_, after_output_gain_);
     134           27 :     return true;
     135              :   }
     136              : 
     137              :   /** @brief Restore the before-recall state (undo). */
     138            6 :   void undo() override {
     139            6 :     apply_state(before_effects_, before_input_gain_, before_output_gain_);
     140            6 :   }
     141              : 
     142              :   /** @brief Return "Recall Snapshot". */
     143            3 :   const char *description() const override { return "Recall Snapshot"; }
     144              : 
     145              : private:
     146           33 :   void apply_state(const std::vector<EffectSnapshot> &state, float input_gain,
     147              :                    float output_gain) {
     148           33 :     std::vector<std::shared_ptr<Effect>> new_effects;
     149           33 :     new_effects.reserve(state.size());
     150           81 :     for (const auto &snap : state) {
     151           48 :       snap.effect->set_enabled(snap.enabled);
     152           48 :       snap.effect->set_mix(snap.mix);
     153           48 :       auto &params = snap.effect->params();
     154          318 :       for (int i = 0; i < static_cast<int>(params.size()) &&
     155          162 :                       i < static_cast<int>(snap.param_values.size());
     156           54 :            ++i) {
     157          162 :         params[i].value = snap.param_values[i];
     158           54 :       }
     159           48 :       new_effects.push_back(snap.effect);
     160              :     }
     161           33 :     engine_.restore_effects_state(std::move(new_effects));
     162           33 :     engine_.set_input_gain(input_gain);
     163           33 :     engine_.set_output_gain(output_gain);
     164           33 :   }
     165              : 
     166              :   AudioEngine &engine_;
     167              :   std::vector<EffectSnapshot> before_effects_;
     168              :   float before_input_gain_;
     169              :   float before_output_gain_;
     170              :   std::vector<EffectSnapshot> after_effects_;
     171              :   float after_input_gain_;
     172              :   float after_output_gain_;
     173              : };
     174              : 
     175              : } // namespace Amplitron
        

Generated by: LCOV version 2.0-1