File: AudioUnitWrapper.h

package info (click to toggle)
audacity 3.7.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 125,252 kB
  • sloc: cpp: 358,238; ansic: 75,458; lisp: 7,761; sh: 3,410; python: 1,503; xml: 1,385; perl: 854; makefile: 122
file content (226 lines) | stat: -rw-r--r-- 7,850 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*!********************************************************************

  Audacity: A Digital Audio Editor

  @file AudioUnitWrapper.h

  Dominic Mazzoni
  Leland Lucius

  Paul Licameli split from AudioUnitEffect.h

**********************************************************************/
#ifndef AUDACITY_AUDIOUNIT_WRAPPER_H
#define AUDACITY_AUDIOUNIT_WRAPPER_H

#if USE_AUDIO_UNITS

#include <optional>
#include <map>
#include <set>
#include <unordered_map>
#include <wx/string.h>

#include "AudioUnitUtils.h"
#include "Identifier.h"

class wxCFStringRef;
class wxMemoryBuffer;
class EffectDefinitionInterface;
class EffectSettings;
class TranslatableString;
class AudioUnitWrapper;

/**
 * @struct AudioUnitEffectSettings
 * @brief Represents a cached copy of the state stored in an AudioUnit, but can outlive the original AudioUnit.
 *
 * This structure handles the storage and management of settings and state information for AudioUnit effects.
 * It provides mechanisms for sharing settings between different instances and managing preset configurations.
 */
struct AudioUnitEffectSettings {
   /**
    * @brief Shared set of strings to optimize memory usage by avoiding repeated allocations.
    * 
    * All instances of AudioUnitEffectSettings share this set to reduce memory overhead and ensure consistency.
    * The effect object and all Settings objects coming from it share this set of strings.
    * Note: The names associated with parameter IDs are not invariant metadata of an AudioUnit effect.
    * For example, AUGraphicEQ changes names of slider parameters when you switch between 10 and 31 bands.
    */
   using StringSet = std::set<wxString>;
   const std::shared_ptr<StringSet> mSharedNames{
      std::make_shared<StringSet>() };

   //! Optionally store a preset
   std::optional<SInt32> mPresetNumber;
   
   //! Map from numerical parameter IDs (not always a small initial segment
   //! of the integers) to optional pairs of names and floating point values
   using Pair = std::pair<const wxString &, AudioUnitParameterValue>;
   using Map = std::map<AudioUnitParameterID, std::optional<Pair>>;
   Map values;

   AudioUnitEffectSettings() = default;
   AudioUnitEffectSettings(Map map) : values{ move(map) } {}
   
   //! Get a pointer to a durable copy of `name`
   //! May allocate memory
   const wxString &Intern(const wxString &name) {
      // std::set::insert guarantees this iterator is not at the end
      auto [iter, _] = mSharedNames->insert(name);
      // so dereference it merrily
      return *iter;
   }

   //! Associate nullopt with all keys already present in the map
   void ResetValues()
   {
      for (auto &[_, value] : values)
         value.reset();
   }
};

/**
 * @class AudioUnitWrapper
 * @brief Manages and interacts with an AudioUnit, providing operations on audio effects.
 *
 * This class hosts the functionality for managing AudioUnit settings, presets, and parameters,
 * allowing manipulation of audio processing units.
 */
struct AudioUnitWrapper
{
   using Parameters = PackedArray::Ptr<const AudioUnitParameterID>;

   static AudioUnitEffectSettings &GetSettings(EffectSettings &settings);
   static const AudioUnitEffectSettings &GetSettings(
      const EffectSettings &settings);

   /*!
    @param pParameters if non-null, use those; else, fetch from the AudioUnit
    */
   AudioUnitWrapper(AudioComponent component, Parameters *pParameters)
      : mComponent{ component }
      , mParameters{ pParameters ? *pParameters : mOwnParameters }
   {
   }

   // Supply most often used values as defaults for scope and element
   template<typename T>
   OSStatus GetFixedSizeProperty(AudioUnitPropertyID inID, T &property,
      AudioUnitScope inScope = kAudioUnitScope_Global,
      AudioUnitElement inElement = 0) const
   {
      // Supply mUnit.get() to the non-member function
      return AudioUnitUtils::GetFixedSizeProperty(mUnit.get(),
         inID, property, inScope, inElement);
   }

   // Supply most often used values as defaults for scope and element
   template<typename T>
   OSStatus GetVariableSizeProperty(AudioUnitPropertyID inID,
      PackedArray::Ptr<T> &pObject,
      AudioUnitScope inScope = kAudioUnitScope_Global,
      AudioUnitElement inElement = 0) const
   {
      return AudioUnitUtils::GetVariableSizeProperty(mUnit.get(),
         inID, pObject, inScope, inElement);
   }

   // Supply most often used values as defaults for scope and element
   template<typename T>
   OSStatus SetProperty(AudioUnitPropertyID inID, const T &property,
      AudioUnitScope inScope = kAudioUnitScope_Global,
      AudioUnitElement inElement = 0) const
   {
      // Supply mUnit.get() to the non-member function
      return AudioUnitUtils::SetProperty(mUnit.get(),
         inID, property, inScope, inElement);
   }

   class ParameterInfo;
   //! Return value: if true, continue visiting
   using ParameterVisitor =
      std::function< bool(const ParameterInfo &pi, AudioUnitParameterID ID) >;
   void ForEachParameter(ParameterVisitor visitor) const;

   bool LoadPreset(const EffectDefinitionInterface &effect,
      const RegistryPath & group, EffectSettings &settings) const;
   bool LoadFactoryPreset(const EffectDefinitionInterface &effect,
      int id, EffectSettings *pSettings) const;

   //! Obtain dump of the setting state of an AudioUnit instance
   /*!
    @param binary if false, then produce XML serialization instead; but
    AudioUnits does not need to be told the format again to reinterpret the blob
    @return smart pointer to data, and an error message
    */
   std::pair<CF_ptr<CFDataRef>, TranslatableString>
   MakeBlob(const EffectDefinitionInterface &effect,
      const AudioUnitEffectSettings &settings,
      const wxCFStringRef &cfname, bool binary) const;

   //! Interpret the dump made before by MakeBlob
   /*!
    @param group only for formatting error messages
    @return an error message
    */
   TranslatableString InterpretBlob(AudioUnitEffectSettings &settings,
      const wxString &group, const wxMemoryBuffer &buf) const;

   //! May allocate memory, so should be called only in the main thread
   bool FetchSettings(AudioUnitEffectSettings &settings,
      bool fetchValues, bool fetchPreset = false) const;
   bool StoreSettings(const EffectDefinitionInterface &effect,
      const AudioUnitEffectSettings &settings) const;

   //! Copy, then clear the optionals in src
   static bool MoveSettingsContents(
      AudioUnitEffectSettings &&src, AudioUnitEffectSettings &dst, bool merge);

   bool CreateAudioUnit();

   AudioUnit GetAudioUnit() const { return mUnit.get(); }
   AudioComponent GetComponent() const { return mComponent; }
   const Parameters &GetParameters() const
   { return mParameters; }

   // @param identifier only for logging messages
   bool SetRateAndChannels(double sampleRate, const wxString &identifier);

protected:
   const AudioComponent mComponent;
   AudioUnitCleanup<AudioUnit, AudioComponentInstanceDispose> mUnit;

   Parameters mOwnParameters;
   Parameters &mParameters;

   // Reassinged in GetRateAndChannels()
   unsigned mAudioIns{ 2 };
   unsigned mAudioOuts{ 2 };
};

/**
 * @class AudioUnitWrapper::ParameterInfo
 * @brief Encapsulates parameter information for an AudioUnit.
 * */
class AudioUnitWrapper::ParameterInfo final
{
public:
   //! Make a structure holding a key for the config file and a value
   ParameterInfo(AudioUnit mUnit, AudioUnitParameterID parmID);
   //! Recover the parameter ID from the key, if well formed
   static std::optional<AudioUnitParameterID> ParseKey(const wxString &key);

   std::optional<wxString> mName;
   AudioUnitUtils::ParameterInfo mInfo{};

private:
   // constants
   static constexpr char idBeg = wxT('<');
   static constexpr char idSep = wxT(',');
   static constexpr char idEnd = wxT('>');
};

#endif

#endif