23#include <wx/osx/core/private.h>
53#define PRESET_FORMAT kCFPropertyListBinaryFormat_v1_0
56#define PRESET_KEY wxT("Data")
59#define PRESET_LOCAL_PATH wxT("/Library/Audio/Presets")
60#define PRESET_USER_PATH wxT("~/Library/Audio/Presets")
66#define USE_EXTENDED_NAMES
69 AudioUnit mUnit, AudioUnitParameterID parmID)
76 kAudioUnitProperty_ParameterInfo,
mInfo,
77 kAudioUnitScope_Global, parmID))
81 if (
mInfo.flags & kAudioUnitParameterFlag_HasCFNameString)
82 name = wxCFStringRef::AsString(
mInfo.cfNameString);
86#if defined(USE_EXTENDED_NAMES)
106 if (
mInfo.flags & kAudioUnitParameterFlag_HasClump) {
109 mInfo.clumpID, kAudioUnitParameterName_Full
113 kAudioUnitProperty_ParameterClumpName, clumpInfo)) {
114 clumpName = wxCFStringRef::AsString(clumpInfo.outName);
118 clumpName.Append(
idSep);
120 name = wxString::Format(
wxT(
"%c%s%x%c%s"),
126std::optional<AudioUnitParameterID>
131 if (
const auto rend =
key.rend(), riter = std::find_if(
key.rbegin(), rend,
132 [](wxChar c) { return c == idBeg || c == idSep; })
136 if (
const auto end =
key.end(), left = riter.base(),
137 right = std::find(left,
end, idEnd)
138 ; left != right && right !=
end
142 ; wxString{left, right}.ToLong(&value, 16))
157 if (
preset.presetNumber >= 0)
173 AudioUnitParameterValue value;
175 AudioUnitGetParameter(
176 mUnit.get(), ID, kAudioUnitScope_Global, 0, &value)) {
182 slot.emplace(
settings.Intern(*
pi.mName), value);
215 for (
auto pass : {0, 1}) {
219 if (auto iter = settings.values.find(ID);
220 iter != settings.values.end() && iter->second.has_value()
222 if (AudioUnitSetParameter(mUnit.get(), ID,
223 kAudioUnitScope_Global, 0, iter->second->second, 0)) {
244 auto &dstMap = dst.
values;
245 auto dstIter = dstMap.begin(), dstEnd = dstMap.end();
246 auto &srcMap = src.values;
247 for (
auto &[
key, oValue] : srcMap) {
248 while (dstIter != dstEnd && dstIter->first !=
key)
250 if (dstIter == dstEnd)
252 auto &[dstKey, dstOValue] = *dstIter;
253 assert(dstKey ==
key);
255 dstOValue.emplace(*oValue);
268 auto result = AudioComponentInstanceNew(
mComponent, &unit);
276 return (!result && unit !=
nullptr);
281 const RegistryPath &group,
const wxMemoryBuffer &buf)
const
283 size_t bufLen = buf.GetDataLen();
285 return XO(
"Failed to decode \"%s\" preset").Format(group);
288 const auto bufPtr =
static_cast<const uint8_t *
>(buf.GetData());
289 CF_ptr<CFDataRef> data{ CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
290 bufPtr, bufLen, kCFAllocatorNull)
293 return XO(
"Failed to convert \"%s\" preset to internal format")
297 CF_ptr<CFPropertyListRef> content{
298 CFPropertyListCreateWithData(kCFAllocatorDefault,
299 data.get(), kCFPropertyListImmutable,
nullptr,
304 return XO(
"Failed to create property list for \"%s\" preset")
308 if (
SetProperty(kAudioUnitProperty_ClassInfo, content.get()))
309 return XO(
"Failed to set class info for \"%s\" preset").Format(group);
343 if (!error.empty()) {
344 wxLogError(error.Debug());
364 CF_ptr<CFArrayRef> array;
366 id < 0 || id >= CFArrayGetCount(array.get()))
371 *
static_cast<const AUPreset*
>(CFArrayGetValueAtIndex(array.get(),
id))))
387 const wxCFStringRef &cfname,
bool binary)
const
396 CF_ptr<CFDataRef> data;
402 message =
XO(
"Failed to set preset name");
405 else if (CF_ptr<CFPropertyListRef> content;
407 message =
XO(
"Failed to retrieve preset content");
410 else if (data.reset(CFPropertyListCreateData(kCFAllocatorDefault,
416 message =
XO(
"Failed to convert property list to XML data");
419 else if (
auto length = CFDataGetLength(data.get()); length == 0)
421 message =
XO(
"XML data is empty after conversion");
423 return { move(data), message };
427 double sampleRate,
const wxString &identifier)
434 kAudioFormatLinearPCM,
437 (kAudioFormatFlagsNativeFloatPacked |
438 kAudioFormatFlagIsNonInterleaved),
459 AudioUnitScope
scope;
460 const char *
const msg;
462 { one, kAudioUnitScope_Global,
"global" },
463 {
mAudioIns, kAudioUnitScope_Input,
"input" },
464 {
mAudioOuts, kAudioUnitScope_Output,
"output" },
466 for (
const auto &[nChannels,
scope, msg] : infos) {
469 wxLogError(
"%ls Didn't accept sample rate on %s\n",
471 identifier.wx_str(), msg);
474 if (
scope != kAudioUnitScope_Global) {
479 streamFormat.mChannelsPerFrame = nChannels;
480 failed =
SetProperty(kAudioUnitProperty_StreamFormat,
481 streamFormat,
scope);
482 }
while(failed && nChannels > 0);
484 wxLogError(
"%ls didn't accept stream format on %s\n",
486 identifier.wx_str(), msg);
const RegistryPath & FactoryDefaultsGroup()
Component of a configuration key path, for default state of MakeSettings()
Generalized interface for discovery of plug-ins for one protocol.
static Settings & settings()
Encapsulates parameter information for an AudioUnit.
ParameterInfo(AudioUnit mUnit, AudioUnitParameterID parmID)
Make a structure holding a key for the config file and a value.
static constexpr char idSep
static constexpr char idBeg
static std::optional< AudioUnitParameterID > ParseKey(const wxString &key)
Recover the parameter ID from the key, if well formed.
static constexpr char idEnd
std::optional< wxString > mName
AudioUnitUtils::ParameterInfo mInfo
EffectDefinitionInterface is a ComponentInterface that adds some basic read-only information about ef...
Holds a msgid for the translation catalog; may also bind format arguments.
OSStatus GetFixedSizeProperty(AudioUnit unit, AudioUnitPropertyID inID, T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0)
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
constexpr auto sampleRate
static CommandContext::TargetFactory::SubstituteInUnique< InteractiveOutputTargets > scope
const char * end(const char *str) noexcept
Represents a cached copy of the state stored in an AudioUnit, but can outlive the original AudioUnit.
bool LoadPreset(const EffectDefinitionInterface &effect, const RegistryPath &group, EffectSettings &settings) const
bool StoreSettings(const EffectDefinitionInterface &effect, const AudioUnitEffectSettings &settings) const
bool LoadFactoryPreset(const EffectDefinitionInterface &effect, int id, EffectSettings *pSettings) const
OSStatus GetFixedSizeProperty(AudioUnitPropertyID inID, T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
std::function< bool(const ParameterInfo &pi, AudioUnitParameterID ID) > ParameterVisitor
Return value: if true, continue visiting.
static bool MoveSettingsContents(AudioUnitEffectSettings &&src, AudioUnitEffectSettings &dst, bool merge)
Copy, then clear the optionals in src.
OSStatus GetVariableSizeProperty(AudioUnitPropertyID inID, PackedArray::Ptr< T > &pObject, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
TranslatableString InterpretBlob(AudioUnitEffectSettings &settings, const wxString &group, const wxMemoryBuffer &buf) const
Interpret the dump made before by MakeBlob.
bool SetRateAndChannels(double sampleRate, const wxString &identifier)
AudioUnitCleanup< AudioUnit, AudioComponentInstanceDispose > mUnit
OSStatus SetProperty(AudioUnitPropertyID inID, const T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
static AudioUnitEffectSettings & GetSettings(EffectSettings &settings)
const AudioComponent mComponent
Parameters mOwnParameters
std::pair< CF_ptr< CFDataRef >, TranslatableString > MakeBlob(const EffectDefinitionInterface &effect, const AudioUnitEffectSettings &settings, const wxCFStringRef &cfname, bool binary) const
Obtain dump of the setting state of an AudioUnit instance.
void ForEachParameter(ParameterVisitor visitor) const
bool FetchSettings(AudioUnitEffectSettings &settings, bool fetchValues, bool fetchPreset=false) const
May allocate memory, so should be called only in the main thread.
Externalized state of a plug-in.