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 % 61 60
Test Date: 2026-06-07 15:51:50 Functions: 91.7 % 12 11

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

Generated by: LCOV version 2.0-1