Audacity 3.2.0
AudioUnitEffect.cpp
Go to the documentation of this file.
1/*!********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file AudioUnitEffect.cpp
6
7 Dominic Mazzoni
8 Leland Lucius
9
10*******************************************************************//*******************************************************************/
16
17
18
19#if USE_AUDIO_UNITS
20#include "AudioUnitEffect.h"
22#include "AudacityException.h"
23#include "AUControl.h"
24#include "SampleCount.h"
25#include "ConfigInterface.h"
26
27#include <wx/defs.h>
28#include <wx/base64.h>
29#include <wx/button.h>
30#include <wx/control.h>
31#include <wx/crt.h>
32#include <wx/dir.h>
33#include <wx/ffile.h>
34
35#ifdef __WXMAC__
36#include <wx/evtloop.h>
37#endif
38
39#include <wx/filename.h>
40#include <wx/frame.h>
41#include <wx/listctrl.h>
42#include <wx/log.h>
43#include <wx/sizer.h>
44#include <wx/settings.h>
45#include <wx/stattext.h>
46#include <wx/textctrl.h>
47
48#include "../../SelectFile.h"
49#include "../../ShuttleGui.h"
50#include "../../widgets/AudacityMessageBox.h"
51#include "../../widgets/valnum.h"
52
53//
54// When a plug-in's state is saved to the settings file (as a preset),
55// it is in binary and gets base64 encoded before storing.
56//
57// When exporting, save as XML without base64 encoding.
58//
59// The advantages of XML format is less chance of failures occurring
60// when exporting. But, it can take a bit more space per preset int
61// the Audacity settings file.
62//
63// Using binary for now. Use kCFPropertyListXMLFormat_v1_0 if XML
64// format is desired.
65//
66#define PRESET_FORMAT kCFPropertyListBinaryFormat_v1_0
67
68// Name of the settings key to use for the above value
69#define PRESET_KEY wxT("Data")
70
71// Where the presets are located
72#define PRESET_LOCAL_PATH wxT("/Library/Audio/Presets")
73#define PRESET_USER_PATH wxT("~/Library/Audio/Presets")
74
75// Uncomment to include parameter IDs in the final name. Only needed if it's
76// discovered that many effects have duplicate names. It could even be done
77// at runtime by scanning an effects parameters to determine if dups are present
78// and, if so, enable the clump and parameter IDs.
79#define USE_EXTENDED_NAMES
80class ParameterInfo final
81{
82public:
84 {
85 info = {};
86 }
87
88 bool Get(AudioUnit mUnit, AudioUnitParameterID parmID)
89 {
90 UInt32 dataSize;
91
92 info = {};
93 // Note non-default element parameter, parmID
95 kAudioUnitProperty_ParameterInfo, info,
96 kAudioUnitScope_Global, parmID))
97 return false;
98
99 if (info.flags & kAudioUnitParameterFlag_HasCFNameString)
100 name = wxCFStringRef::AsString(info.cfNameString);
101 else
102 name = wxString(info.name);
103
104#if defined(USE_EXTENDED_NAMES)
105 // If the parameter has a non-empty name, then the final parameter name will
106 // be either:
107 //
108 // <parmID,ParameterName>
109 //
110 // or (if the name isn't available):
111 //
112 // <parmID>
113 if (!name.empty())
114 {
115 name.Replace(idBeg, wxT('_'));
116 name.Replace(idSep, wxT('_'));
117 name.Replace(idEnd, wxT('_'));
118 name.Append(idSep);
119 }
120 name = wxString::Format(wxT("%c%s%x%c"),
121 idBeg,
122 name,
123 parmID,
124 idEnd);
125
126 // If the parameter has a clumpID, then the final parameter name will be
127 // either:
128 //
129 // <clumpID,clumpName><parmID,ParameterName>
130 //
131 // or (if the clumpName isn't available):
132 //
133 // <clumpID><parmID,ParameterName>
134 if (info.flags & kAudioUnitParameterFlag_HasClump)
135 {
136 wxString clumpName;
138 info.clumpID, kAudioUnitParameterName_Full
139 };
140
142 kAudioUnitProperty_ParameterClumpName, clumpInfo)) {
143 clumpName = wxCFStringRef::AsString(clumpInfo.outName);
144 clumpName.Replace(idBeg, wxT('_'));
145 clumpName.Replace(idSep, wxT('_'));
146 clumpName.Replace(idEnd, wxT('_'));
147 clumpName.Append(idSep);
148 }
149 name = wxString::Format(wxT("%c%s%x%c%s"),
150 idBeg,
151 clumpName,
152 info.clumpID,
153 idEnd,
154 name);
155 }
156#endif
157
158 return true;
159 }
160
161 static const char idBeg = wxT('<');
162 static const char idSep = wxT(',');
163 static const char idEnd = wxT('>');
164
165 wxString name;
166 AudioUnitParameterInfo info;
167};
168
170 const RegistryPath &group, const wxString &path,
171 const void *blob, size_t len, bool allowEmpty) const
172{
173 // Base64 encode the returned binary property list
174 auto parms = wxBase64Encode(blob, len);
175 if (!allowEmpty && parms.IsEmpty())
176 return XO("Failed to encode preset from \"%s\"").Format(path);
177
178 // And write it to the config
179 if (!SetConfig(*this, PluginSettings::Private, group, PRESET_KEY, parms))
180 return XO("Unable to store preset in config file");
181 return {};
182}
183
185//
186// AudioUnitEffect
187//
189
191 const wxString & name,
192 AudioComponent component,
193 AudioUnitEffect *master)
194 : AudioUnitWrapper{ component }
195 , mPath{ path }
196 , mName{ name.AfterFirst(wxT(':')).Trim(true).Trim(false) }
197 , mVendor{ name.BeforeFirst(wxT(':')).Trim(true).Trim(false) }
198 , mMaster{ master }
199{
200}
201
203{
204}
205
206// ============================================================================
207// ComponentInterface implementation
208// ============================================================================
209
211{
212 return mPath;
213}
214
216{
217 return mName;
218}
219
221{
222 return { mVendor };
223}
224
226{
227 UInt32 version;
228
229 OSStatus result = AudioComponentGetVersion(mComponent, &version);
230
231 return wxString::Format(wxT("%d.%d.%d"),
232 (version >> 16) & 0xffff,
233 (version >> 8) & 0xff,
234 version & 0xff);
235}
236
238{
239 /* i18n-hint: Can mean "not available," "not applicable," "no answer" */
240 return XO("n/a");
241}
242
243// ============================================================================
244// EffectDefinitionInterface implementation
245// ============================================================================
246
248{
249 if (mAudioIns == 0 && mAudioOuts == 0)
250 {
251 return EffectTypeNone;
252 }
253
254 if (mAudioIns == 0)
255 {
256 return EffectTypeGenerate;
257 }
258
259 if (mAudioOuts == 0)
260 {
261 return EffectTypeAnalyze;
262 }
263
264 return EffectTypeProcess;
265}
266
268{
270}
271
273{
274 return mInteractive;
275}
276
278{
279 return false;
280}
281
283{
284 return GetType() == EffectTypeProcess;
285}
286
288{
290 if (GetVariableSizeProperty(kAudioUnitProperty_ParameterList, array))
291 return false;
292 for (const auto &ID : array) {
293 ParameterInfo pi;
294 if (pi.Get(mUnit.get(), ID))
295 if (pi.info.flags & kAudioUnitParameterFlag_IsWritable)
296 // All we need is one
297 return true;
298 }
299 return false;
300}
301
303{
304 AudioUnit unit{};
305 auto result = AudioComponentInstanceNew(mComponent, &unit);
306 if (!result)
307 mUnit.reset(unit);
308 return (!result && unit != nullptr);
309}
310
312{
313 if (!CreateAudioUnit())
314 return false;
315
316 mSampleRate = 44100;
319
320 // Retrieve the desired number of frames per slice
322 kAudioUnitProperty_MaximumFramesPerSlice, mBlockSize))
323 // Call failed? Then supply a default:
324 mBlockSize = 512;
325
326 // Is this really needed here or can it be done in MakeInstance()
327 // only? I think it can, but this is more a conservative change for now,
328 // preserving what SetHost() did
329 return MakeListener();
330}
331
332std::shared_ptr<EffectInstance> AudioUnitEffect::MakeInstance() const
333{
334 return const_cast<AudioUnitEffect*>(this)->DoMakeInstance();
335}
336
337std::shared_ptr<EffectInstance> AudioUnitEffect::DoMakeInstance()
338{
339 if (mMaster)
340 // This is a slave
342 return std::make_shared<Instance>(*this);
343}
344
345constexpr auto OptionsKey = L"Options";
346constexpr auto UseLatencyKey = L"UseLatency";
347constexpr auto UITypeKey = L"UIType";
348
350{
351 // To implement the services of EffectPlugin -- such as, a query of the
352 // set of effect parameters, so that we can implement MakeSettings -- we
353 // also need what is called an AudioComponentInstance, also called an
354 // AudioUnit.
355 // It's not just for implementing EffectInstance. AudioUnits is unlike other
356 // third party effect families that distinguish the notions of plug-in and
357 // instance.
358
359 // When AudioUnitEffect implements its own proper Instance class, this
360 // should call CreateAudioUnit() directly and not do the rest of
361 // InitializeInstance.
362 if (!InitializeInstance())
363 return false;
364
365
366 // Consult preferences
367 // Decide mUseLatency, which affects GetLatency(), which is actually used
368 // so far only in destructive effect processing
370 mUseLatency, true);
371 // Decide whether to build plain or fancy user interfaces
373 mUIType, FullValue.MSGID().GET() /* Config stores un-localized string */);
374
375 return true;
376}
377
379{
380 if (!mMaster)
381 {
382 // Don't have a master -- so this IS the master.
383 OSStatus result;
384 AUEventListenerRef eventListenerRef{};
385 result = AUEventListenerCreate(AudioUnitEffect::EventListenerCallback,
386 this,
387 (CFRunLoopRef)GetCFRunLoopFromEventLoop(GetCurrentEventLoop()),
388 kCFRunLoopDefaultMode,
389 0.0,
390 0.0,
391 &eventListenerRef);
392 if (result != noErr)
393 return false;
394 mEventListenerRef.reset(eventListenerRef);
395
396 AudioUnitEvent event;
397
398 event.mEventType = kAudioUnitEvent_ParameterValueChange;
399 event.mArgument.mParameter.mAudioUnit = mUnit.get();
400 event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
401 event.mArgument.mParameter.mElement = 0;
402
403 // Retrieve the list of parameters
405 if (GetVariableSizeProperty(kAudioUnitProperty_ParameterList, array))
406 return false;
407
408 // Register them as something we're interested in
409 for (const auto &ID : array) {
410 event.mArgument.mParameter.mParameterID = ID;
411 if (AUEventListenerAddEventType(mEventListenerRef.get(), this, &event))
412 return false;
413 }
414
415 event.mEventType = kAudioUnitEvent_PropertyChange;
416 event.mArgument.mProperty.mAudioUnit = mUnit.get();
417 event.mArgument.mProperty.mPropertyID = kAudioUnitProperty_Latency;
418 event.mArgument.mProperty.mScope = kAudioUnitScope_Global;
419 event.mArgument.mProperty.mElement = 0;
420
421 result = AUEventListenerAddEventType(mEventListenerRef.get(),
422 this,
423 &event);
424 if (result != noErr)
425 {
426 return false;
427 }
428
429 // Check for a Cocoa UI
430 // This could retrieve a variable-size property, but we only look at
431 // the first element.
432 AudioUnitCocoaViewInfo cocoaViewInfo;
433 bool hasCocoa =
434 !GetFixedSizeProperty(kAudioUnitProperty_CocoaUI, cocoaViewInfo);
435
436 // Check for a Carbon UI
437 // This could retrieve a variable sized array but we only need the first
438 AudioComponentDescription compDesc;
439 bool hasCarbon =
440 !GetFixedSizeProperty(kAudioUnitProperty_GetUIComponentList, compDesc);
441
442 mInteractive = (PackedArray::Count(array) > 0) || hasCocoa || hasCarbon;
443 }
444
445 return true;
446}
447
449{
450 return mAudioIns;
451}
452
454{
455 return mAudioOuts;
456}
457
459{
460 return 0;
461}
462
464{
465 return 0;
466}
467
469{
470 mSampleRate = rate;
471}
472
473size_t AudioUnitEffect::SetBlockSize(size_t maxBlockSize)
474{
475 return mBlockSize;
476}
477
479{
480 return mBlockSize;
481}
482
484{
485 // Retrieve the latency (can be updated via an event)
486 if (mUseLatency && !mLatencyDone) {
487 Float64 latency = 0.0;
488 if (!GetFixedSizeProperty(kAudioUnitProperty_Latency, latency)) {
489 mLatencyDone = true;
490 return sampleCount{ latency * mSampleRate };
491 }
492 }
493 return 0;
494}
495
496#if 0
497// TODO move to AudioUnitEffect::Instance when that class exists
498size_t AudioUnitEffect::GetTailSize() const
499{
500 // Retrieve the tail time
501 Float64 tailTime = 0.0;
502 if (!GetFixedSizeProperty(kAudioUnitProperty_TailTime, tailTime))
503 return tailTime * mSampleRate;
504 return 0;
505}
506#endif
507
510{
511 mInputList =
512 PackedArray::AllocateCount<AudioBufferList>(mAudioIns)(mAudioIns);
514 PackedArray::AllocateCount<AudioBufferList>(mAudioOuts)(mAudioOuts);
515
516 memset(&mTimeStamp, 0, sizeof(AudioTimeStamp));
517 mTimeStamp.mSampleTime = 0; // This is a double-precision number that should
518 // accumulate the number of frames processed so far
519 mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
520
521 if (!SetRateAndChannels())
522 return false;
523
524 if (SetProperty(kAudioUnitProperty_SetRenderCallback,
526 kAudioUnitScope_Input)) {
527 wxLogError("Setting input render callback failed.\n");
528 return false;
529 }
530
531 if (AudioUnitReset(mUnit.get(), kAudioUnitScope_Global, 0))
532 return false;
533
534 if (!BypassEffect(false))
535 return false;
536
537 mLatencyDone = false;
538 return true;
539}
540
542{
543 mOutputList.reset();
544 mInputList.reset();
545 return true;
546}
547
549 const float *const *inBlock, float *const *outBlock, size_t blockLen)
550{
551 // mAudioIns and mAudioOuts don't change after plugin initialization,
552 // so ProcessInitialize() made sufficient allocations
554 for (size_t i = 0; i < mAudioIns; ++i)
555 mInputList[i] = { 1, static_cast<UInt32>(sizeof(float) * blockLen),
556 const_cast<float*>(inBlock[i]) };
557
558 // See previous comment
560 for (size_t i = 0; i < mAudioOuts; ++i)
561 mOutputList[i] = { 1, static_cast<UInt32>(sizeof(float) * blockLen),
562 outBlock[i] };
563
564 AudioUnitRenderActionFlags flags = 0;
565 OSStatus result;
566
567 result = AudioUnitRender(mUnit.get(),
568 &flags,
569 &mTimeStamp,
570 0,
571 blockLen,
572 mOutputList.get());
573 if (result != noErr) {
574 wxLogError("Render failed: %d %4.4s\n",
575 static_cast<int>(result), reinterpret_cast<char *>(&result));
576 return 0;
577 }
578
579 mTimeStamp.mSampleTime += blockLen;
580 return blockLen;
581}
582
584{
585 return ProcessInitialize(settings, 0, nullptr);
586}
587
589 EffectSettings &settings, unsigned, float sampleRate)
590{
591 auto slave = std::make_unique<AudioUnitEffect>(mPath, mName, mComponent, this);
592 if (!slave->InitializeInstance())
593 return false;
594
595 slave->SetBlockSize(mBlockSize);
596 slave->SetSampleRate(sampleRate);
597
598 if (!CopyParameters(mUnit.get(), slave->mUnit.get()))
599 {
600 return false;
601 }
602
603 auto pSlave = slave.get();
604 mSlaves.push_back(std::move(slave));
605
606 return pSlave->ProcessInitialize(settings, 0, nullptr);
607}
608
610{
611return GuardedCall<bool>([&]{
612 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
613 {
614 mSlaves[i]->ProcessFinalize();
615 }
616 mSlaves.clear();
617 return ProcessFinalize();
618});
619}
620
622{
623 if (!BypassEffect(true))
624 {
625 return false;
626 }
627
628 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
629 {
630 if (!mSlaves[i]->BypassEffect(true))
631 {
632 return false;
633 }
634 }
635
636 return true;
637}
638
640{
641return GuardedCall<bool>([&]{
642 if (!BypassEffect(false))
643 {
644 return false;
645 }
646
647 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
648 {
649 if (!mSlaves[i]->BypassEffect(false))
650 {
651 return false;
652 }
653 }
654
655 return true;
656});
657}
658
660{
661 return true;
662}
663
665 const float *const *inbuf, float *const *outbuf, size_t numSamples)
666{
667 wxASSERT(numSamples <= mBlockSize);
668 return mSlaves[group]->ProcessBlock(settings, inbuf, outbuf, numSamples);
669}
670
672{
673 return true;
674}
675
677 wxWindow &parent, wxDialog &dialog, bool forceModal)
678{
679 // Remember the dialog with a weak pointer, but don't control its lifetime
680 mDialog = &dialog;
681 if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal)
682 {
683 mDialog->Show();
684 return 0;
685 }
686
687 return mDialog->ShowModal();
688}
689
691 const EffectSettings &, CommandParameters & parms) const
692{
694 if (GetVariableSizeProperty(kAudioUnitProperty_ParameterList, array))
695 return false;
696 for (const auto &ID : array) {
697 ParameterInfo pi;
698 if (!pi.Get(mUnit.get(), ID))
699 // Probably failed because of invalid parameter which can happen
700 // if a plug-in is in a certain mode that doesn't contain the
701 // parameter. In any case, just ignore it.
702 continue;
703 AudioUnitParameterValue value;
704 if (AudioUnitGetParameter(mUnit.get(), ID, kAudioUnitScope_Global, 0,
705 &value))
706 // Probably failed because of invalid parameter which can happen
707 // if a plug-in is in a certain mode that doesn't contain the
708 // parameter. In any case, just ignore it.
709 continue;
710 parms.Write(pi.name, value);
711 }
712 return true;
713}
714
716 const CommandParameters & parms, EffectSettings &settings) const
717{
719 if (GetVariableSizeProperty(kAudioUnitProperty_ParameterList, array))
720 return false;
721 for (const auto &ID : array) {
722 ParameterInfo pi;
723 if (!pi.Get(mUnit.get(), ID))
724 // Probably failed because of invalid parameter which can happen
725 // if a plug-in is in a certain mode that doesn't contain the
726 // parameter. In any case, just ignore it.
727 continue;
728 double d = 0.0;
729 if (parms.Read(pi.name, &d)) {
730 if (AudioUnitSetParameter(mUnit.get(), ID, kAudioUnitScope_Global,
731 0, d, 0))
732 return false;
733 Notify(mUnit.get(), ID);
734 }
735 }
736 return true;
737}
738
741{
742 // To do: externalize state so const_cast isn't needed
743 return const_cast<AudioUnitEffect*>(this)->LoadPreset(name, settings);
744}
745
747 const RegistryPath & name, const EffectSettings &) const
748{
749 return SavePreset(name);
750}
751
753{
754 // Retrieve the list of factory presets
755 CF_ptr<CFArrayRef> array;
756 if (GetFixedSizeProperty(kAudioUnitProperty_FactoryPresets, array) ||
757 id < 0 || id >= CFArrayGetCount(array.get()))
758 return false;
759
760 if (!SetProperty(kAudioUnitProperty_PresentPreset,
761 *static_cast<const AUPreset*>(CFArrayGetValueAtIndex(array.get(), id)))) {
762 // Notify interested parties of change and propagate to slaves
763 Notify(mUnit.get(), kAUParameterListener_AnyParameter);
764 return true;
765 }
766 return false;
767}
768
770{
771 RegistryPaths presets;
772
773 // Retrieve the list of factory presets
774 CF_ptr<CFArrayRef> array;
775 if (!GetFixedSizeProperty(kAudioUnitProperty_FactoryPresets, array))
776 for (CFIndex i = 0, cnt = CFArrayGetCount(array.get()); i < cnt; ++i)
777 presets.push_back(wxCFStringRef::AsString(
778 static_cast<const AUPreset*>(CFArrayGetValueAtIndex(array.get(), i))
779 ->presetName));
780 return presets;
781}
782
783// ============================================================================
784// EffectUIClientInterface Implementation
785// ============================================================================
786
787std::unique_ptr<EffectUIValidator> AudioUnitEffect::PopulateUI(ShuttleGui &S,
789{
790 // OSStatus result;
791
792 auto parent = S.GetParent();
793 mDialog = static_cast<wxDialog *>(wxGetTopLevelParent(parent));
794 mParent = parent;
795 mpControl = NULL;
796
797 wxPanel *container;
798 {
799 auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
800
801 wxASSERT(mParent); // To justify safenew
802 container = safenew wxPanelWrapper(mParent, wxID_ANY);
803 mainSizer->Add(container, 1, wxEXPAND);
804
805 mParent->SetSizer(mainSizer.release());
806 }
807
808#if defined(HAVE_AUDIOUNIT_BASIC_SUPPORT)
809 if (mUIType == BasicValue.MSGID().GET()) {
810 if (!CreatePlain(mParent))
811 return nullptr;
812 }
813 else
814#endif
815 {
817 if (!pControl)
818 {
819 return nullptr;
820 }
821
822 if (!pControl->Create(container, mComponent, mUnit.get(),
823 mUIType == FullValue.MSGID().GET()))
824 return nullptr;
825
826 {
827 auto innerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
828
829 innerSizer->Add((mpControl = pControl.release()), 1, wxEXPAND);
830 container->SetSizer(innerSizer.release());
831 }
832
833 mParent->SetMinSize(wxDefaultSize);
834
835#ifdef __WXMAC__
836#ifdef __WX_EVTLOOP_BUSY_WAITING__
837 wxEventLoop::SetBusyWaiting(true);
838#endif
839#endif
840 }
841
842 if (mpControl)
843 {
844 mParent->PushEventHandler(this);
845 }
846
847 return std::make_unique<DefaultEffectUIValidator>(*this, access);
848}
849
851{
852 return mUIType != wxT("Plain");
853}
854
856{
857#if 0
859 settings.extra.SetDuration(mDuration->GetValue());
860#endif
861 return true;
862}
863
864#if defined(HAVE_AUDIOUNIT_BASIC_SUPPORT)
865bool AudioUnitEffect::CreatePlain(wxWindow *parent)
866{
867 // TODO??? Never implemented...
868 return false;
869}
870#endif
871
873{
874#ifdef __WXMAC__
875#ifdef __WX_EVTLOOP_BUSY_WAITING__
876 wxEventLoop::SetBusyWaiting(false);
877#endif
878 if (mpControl)
879 {
880 mParent->RemoveEventHandler(this);
881
882 mpControl->Close();
883 mpControl = nullptr;
884 }
885#endif
886
887 mParent = NULL;
888 mDialog = NULL;
889
890 return true;
891}
892
894{
895 return true;
896}
897
899{
900 // Generate the user domain path
901 wxFileName fn;
902 fn.SetPath(PRESET_USER_PATH);
903 fn.AppendDir(mVendor);
904 fn.AppendDir(mName);
905 fn.Normalize();
906 FilePath path = fn.GetFullPath();
907
908 if (!fn.Mkdir(fn.GetFullPath(), 0755, wxPATH_MKDIR_FULL))
909 {
910 wxLogError(wxT("Couldn't create the \"%s\" directory"), fn.GetPath());
911 return;
912 }
913
914 // Ask the user for the name to use
915 //
916 // Passing a valid parent will cause some effects dialogs to malfunction
917 // upon returning from the SelectFile().
918 path = SelectFile(FileNames::Operation::_None,
919 XO("Export Audio Unit Preset As %s:").Format(fn.GetFullPath()),
920 fn.GetFullPath(),
921 wxEmptyString,
922 wxT("aupreset"),
923 {
924 { XO("Standard Audio Unit preset file"), { wxT("aupreset") }, true },
925 },
926 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
927 NULL);
928
929 // User canceled...
930 if (path.empty())
931 {
932 return;
933 }
934
935 auto msg = Export(path);
936 if (!msg.empty())
937 {
939 XO("Could not export \"%s\" preset\n\n%s").Format(path, msg),
940 XO("Export Audio Unit Presets"),
941 wxOK | wxCENTRE,
942 mParent);
943 }
944}
945
947{
948 // Generate the user domain path
949 wxFileName fn;
950 fn.SetPath(PRESET_USER_PATH);
951 fn.AppendDir(mVendor);
952 fn.AppendDir(mName);
953 fn.Normalize();
954 FilePath path = fn.GetFullPath();
955
956 // Ask the user for the name to use
957 //
958 // Passing a valid parent will cause some effects dialogs to malfunction
959 // upon returning from the SelectFile().
960 path = SelectFile(FileNames::Operation::_None,
961 XO("Import Audio Unit Preset As %s:").Format(fn.GetFullPath()),
962 fn.GetFullPath(),
963 wxEmptyString,
964 wxT("aupreset"),
965 {
966 { XO("Standard Audio Unit preset file"), { wxT("aupreset") }, true },
967 },
968 wxFD_OPEN | wxRESIZE_BORDER,
969 NULL);
970
971 // User canceled...
972 if (path.empty())
973 {
974 return;
975 }
976
977 auto msg = Import(path);
978 if (!msg.empty())
979 {
981 XO("Could not import \"%s\" preset\n\n%s").Format(path, msg),
982 XO("Import Audio Unit Presets"),
983 wxOK | wxCENTRE,
984 mParent);
985 }
986}
987
989{
990 return true;
991}
992
994{
996 if (dlg.ShowModal()) {
997 // Save changed values to the config file
1001 }
1002}
1003
1004// ============================================================================
1005// AudioUnitEffect Implementation
1006// ============================================================================
1007
1009 const RegistryPath & group, EffectSettings &settings) const
1010{
1011 wxString parms;
1012
1013 // Attempt to load old preset parameters and resave using new method
1014 if (GetConfig(*this, PluginSettings::Private, group, wxT("Parameters"),
1015 parms, wxEmptyString)) {
1017 if (eap.SetParameters(parms))
1018 if (LoadSettings(eap, settings))
1019 if (SavePreset(group))
1021 group, wxT("Parameters"));
1022 return true;
1023 }
1024
1025 // Retrieve the preset
1026 if (!GetConfig(*this, PluginSettings::Private, group, PRESET_KEY, parms,
1027 wxEmptyString)) {
1028 // Commented "CurrentSettings" gets tried a lot and useless messages appear
1029 // in the log
1030 //wxLogError(wxT("Preset key \"%s\" not found in group \"%s\""), PRESET_KEY, group);
1031 return false;
1032 }
1033
1034 // Decode it, complementary to what SaveBlobToConfig did
1035 auto error = InterpretBlob(group, wxBase64Decode(parms));
1036 if (!error.empty()) {
1037 wxLogError(error.Debug());
1038 return false;
1039 }
1040
1041 // See AUView::viewWillDraw
1042 if (mpControl)
1044
1045 // Notify interested parties of change and propagate to slaves
1046 Notify(mUnit.get(), kAUParameterListener_AnyParameter);
1047 return true;
1048}
1049
1051 const RegistryPath &group, const wxMemoryBuffer &buf) const
1052{
1053 size_t bufLen = buf.GetDataLen();
1054 if (!bufLen)
1055 return XO("Failed to decode \"%s\" preset").Format(group);
1056
1057 // Create a CFData object that references the decoded preset
1058 const auto bufPtr = static_cast<const uint8_t *>(buf.GetData());
1059 CF_ptr<CFDataRef> data{ CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
1060 bufPtr, bufLen, kCFAllocatorNull)
1061 };
1062 if (!data)
1063 return XO("Failed to convert \"%s\" preset to internal format")
1064 .Format(group);
1065
1066 // Convert it back to a property list
1067 CF_ptr<CFPropertyListRef> content{
1068 CFPropertyListCreateWithData(kCFAllocatorDefault,
1069 data.get(), kCFPropertyListImmutable, nullptr,
1070 // TODO might retrieve more error information
1071 nullptr)
1072 };
1073 if (!content)
1074 return XO("Failed to create property list for \"%s\" preset")
1075 .Format(group);
1076
1077 // Finally, update the properties and parameters
1078 if (SetProperty(kAudioUnitProperty_ClassInfo, content.get()))
1079 return XO("Failed to set class info for \"%s\" preset").Format(group);
1080 return {};
1081}
1082
1084{
1085 wxCFStringRef cfname(wxFileNameFromPath(group));
1086 const auto &[data, _] = MakeBlob(cfname, true);
1087 if (!data)
1088 return false;
1089
1090 // Nothing to do if we don't have any data
1091 if (const auto length = CFDataGetLength(data.get())) {
1092 auto error =
1093 SaveBlobToConfig(group, {}, CFDataGetBytePtr(data.get()), length);
1094 if (!error.empty())
1095 return false;
1096 }
1097 return true;
1098}
1099
1101{
1102 mInitialization.reset();
1104 // Float64 mSampleRate;
1106
1107 // UInt32 mFormatID;
1108 kAudioFormatLinearPCM,
1109
1110 // UInt32 mFormatFlags;
1111 (kAudioFormatFlagsNativeFloatPacked |
1112 kAudioFormatFlagIsNonInterleaved),
1113
1114 // UInt32 mBytesPerPacket;
1115 sizeof(float),
1116
1117 // UInt32 mFramesPerPacket;
1118 1,
1119
1120 // UInt32 mBytesPerFrame;
1121 sizeof(float),
1122
1123 // UInt32 mChannelsPerFrame;
1124 0,
1125
1126 // UInt32 mBitsPerChannel;
1127 sizeof(float) * 8,
1128 };
1129
1130 const struct Info{
1131 unsigned nChannels;
1132 AudioUnitScope scope;
1133 const char *const msg; // used only in log messages
1134 } infos[]{
1135 { 1, kAudioUnitScope_Global, "global" },
1136 { mAudioIns, kAudioUnitScope_Input, "input" },
1137 { mAudioOuts, kAudioUnitScope_Output, "output" },
1138 };
1139 for (const auto &[nChannels, scope, msg] : infos) {
1140 if (nChannels) {
1141 if (SetProperty(kAudioUnitProperty_SampleRate, mSampleRate, scope)) {
1142 wxLogError("%ls Didn't accept sample rate on %s\n",
1143 // Exposing internal name only in logging
1144 GetSymbol().Internal().wx_str(), msg);
1145 return false;
1146 }
1147 if (scope != kAudioUnitScope_Global) {
1148 streamFormat.mChannelsPerFrame = nChannels;
1149 if (SetProperty(kAudioUnitProperty_StreamFormat,
1150 streamFormat, scope)) {
1151 wxLogError("%ls didn't accept stream format on %s\n",
1152 // Exposing internal name only in logging
1153 GetSymbol().Internal().wx_str(), msg);
1154 return false;
1155 }
1156 }
1157 }
1158 }
1159
1160 if (AudioUnitInitialize(mUnit.get())) {
1161 wxLogError("Couldn't initialize audio unit\n");
1162 return false;
1163 }
1164
1165 mInitialization.reset(mUnit.get());
1166 return true;
1167}
1168
1169bool AudioUnitEffect::CopyParameters(AudioUnit srcUnit, AudioUnit dstUnit)
1170{
1171 // Retrieve the class state from the source AU
1172 CF_ptr<CFPropertyListRef> content;
1174 kAudioUnitProperty_ClassInfo, content))
1175 return false;
1176
1177 // Set the destination AUs state from the source AU's content
1178 if (AudioUnitUtils::SetProperty(dstUnit,
1179 kAudioUnitProperty_ClassInfo, content))
1180 return false;
1181
1182 // Notify interested parties
1183 Notify(dstUnit, kAUParameterListener_AnyParameter);
1184
1185 return true;
1186}
1187
1189{
1190 // Create the file
1191 wxFFile f(path, wxT("wb"));
1192 if (!f.IsOpened())
1193 return XO("Couldn't open \"%s\"").Format(path);
1194
1195 // First set the name of the preset
1196 wxCFStringRef cfname(wxFileName(path).GetName());
1197
1198 const auto &[data, message] = MakeBlob(cfname, false);
1199 if (!data || !message.empty())
1200 return message;
1201
1202 // Write XML data
1203 auto length = CFDataGetLength(data.get());
1204 if (f.Write(CFDataGetBytePtr(data.get()), length) != length || f.Error())
1205 return XO("Failed to write XML preset to \"%s\"").Format(path);
1206
1207 f.Close();
1208 return {};
1209}
1210
1211std::pair<CF_ptr<CFDataRef>, TranslatableString>
1212AudioUnitEffect::MakeBlob(const wxCFStringRef &cfname, bool binary) const
1213{
1214 CF_ptr<CFDataRef> data;
1215 TranslatableString message;
1216
1217 // Define the preset property and set it in the audio unit
1218 if (SetProperty(
1219 kAudioUnitProperty_PresentPreset, AudioUnitUtils::UserPreset{ cfname }))
1220 message = XO("Failed to set preset name");
1221
1222 // Now retrieve the preset content
1223 else if (CF_ptr<CFPropertyListRef> content;
1224 GetFixedSizeProperty(kAudioUnitProperty_ClassInfo, content))
1225 message = XO("Failed to retrieve preset content");
1226
1227 // And convert it to serialized XML data
1228 else if (data.reset(CFPropertyListCreateData(kCFAllocatorDefault,
1229 content.get(),
1230 (binary ? PRESET_FORMAT : kCFPropertyListXMLFormat_v1_0), 0,
1231 // TODO might retrieve more error information
1232 nullptr));
1233 !data)
1234 message = XO("Failed to convert property list to XML data");
1235
1236 // Nothing to do if we don't have any data
1237 else if (auto length = CFDataGetLength(data.get()); length == 0)
1238 // Caller might not treat this as error, becauase data is non-null
1239 message = XO("XML data is empty after conversion");
1240
1241 return { move(data), message };
1242}
1243
1245{
1246 // Open the preset
1247 wxFFile f(path, wxT("r"));
1248 if (!f.IsOpened())
1249 return XO("Couldn't open \"%s\"").Format(path);
1250
1251 // Load it into the buffer
1252 size_t len = f.Length();
1253 wxMemoryBuffer buf(len);
1254 if (f.Read(buf.GetData(), len) != len || f.Error())
1255 return XO("Unable to read the preset from \"%s\"").Format(path);
1256
1257 const auto error = InterpretBlob(path, buf);
1258 if (!error.empty())
1259 return error;
1260
1261 // Notify interested parties of change and propagate to slaves
1262 Notify(mUnit.get(), kAUParameterListener_AnyParameter);
1263
1264 return {};
1265}
1266
1267void AudioUnitEffect::Notify(AudioUnit unit, AudioUnitParameterID parm) const
1268{
1269 // Notify any interested parties
1270 AudioUnitParameter aup = {};
1271 aup.mAudioUnit = unit;
1272 aup.mParameterID = parm;
1273 aup.mScope = kAudioUnitScope_Global;
1274 aup.mElement = 0;
1275 AUParameterListenerNotify(NULL, NULL, &aup);
1276}
1277
1278OSStatus AudioUnitEffect::Render(AudioUnitRenderActionFlags *inActionFlags,
1279 const AudioTimeStamp *inTimeStamp,
1280 UInt32 inBusNumber,
1281 UInt32 inNumFrames,
1282 AudioBufferList *ioData)
1283{
1284 size_t i = 0;
1285 auto size =
1286 std::min<size_t>(ioData->mNumberBuffers, PackedArray::Count(mInputList));
1287 for (; i < size; ++i)
1288 ioData->mBuffers[i].mData = mInputList[i].mData;
1289 // Some defensive code here just in case SDK requests from us an unexpectedly
1290 // large number of buffers:
1291 for (; i < ioData->mNumberBuffers; ++i)
1292 ioData->mBuffers[i].mData = nullptr;
1293 return 0;
1294}
1295
1296// static
1297OSStatus AudioUnitEffect::RenderCallback(void *inRefCon,
1298 AudioUnitRenderActionFlags *inActionFlags,
1299 const AudioTimeStamp *inTimeStamp,
1300 UInt32 inBusNumber,
1301 UInt32 inNumFrames,
1302 AudioBufferList *ioData)
1303{
1304 return static_cast<AudioUnitEffect *>(inRefCon)->Render(inActionFlags,
1305 inTimeStamp, inBusNumber, inNumFrames, ioData);
1306}
1307
1308void AudioUnitEffect::EventListener(const AudioUnitEvent *inEvent,
1309 AudioUnitParameterValue inParameterValue)
1310{
1311 // Handle property changes
1312 if (inEvent->mEventType == kAudioUnitEvent_PropertyChange)
1313 {
1314 // Handle latency changes
1315 if (inEvent->mArgument.mProperty.mPropertyID == kAudioUnitProperty_Latency)
1316 {
1317 // Allow change to be used
1318 //mLatencyDone = false;
1319 }
1320
1321 return;
1322 }
1323
1324 // Only parameter changes at this point
1325
1326 if (mMaster)
1327 {
1328 // We're a slave, so just set the parameter
1329 AudioUnitSetParameter(mUnit.get(),
1330 inEvent->mArgument.mParameter.mParameterID,
1331 kAudioUnitScope_Global, 0, inParameterValue, 0);
1332 }
1333 else
1334 {
1335 // We're the master, so propagate
1336 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
1337 {
1338 mSlaves[i]->EventListener(inEvent, inParameterValue);
1339 }
1340 }
1341}
1342
1343// static
1344void AudioUnitEffect::EventListenerCallback(void *inCallbackRefCon,
1345 void *inObject,
1346 const AudioUnitEvent *inEvent,
1347 UInt64 inEventHostTime,
1348 AudioUnitParameterValue inParameterValue)
1349{
1350 static_cast<AudioUnitEffect *>(inCallbackRefCon)
1351 ->EventListener(inEvent, inParameterValue);
1352}
1353
1355{
1356 // Does AU have channel info
1358 if (GetVariableSizeProperty(kAudioUnitProperty_SupportedNumChannels, info)) {
1359 // None supplied. Apparently all FX type units can do any number of INs
1360 // and OUTs as long as they are the same number. In this case, we'll
1361 // just say stereo.
1362 //
1363 // We should probably check to make sure we're dealing with an FX type.
1364 mAudioIns = 2;
1365 mAudioOuts = 2;
1366 return;
1367 }
1368
1369 // This is where it gets weird...not sure what is the best
1370 // way to do this really. If we knew how many ins/outs we
1371 // really needed, we could make a better choice.
1372
1373 bool haven2m = false; // nothing -> mono
1374 bool haven2s = false; // nothing -> stereo
1375 bool havem2n = false; // mono -> nothing
1376 bool haves2n = false; // stereo -> nothing
1377 bool havem2m = false; // mono -> mono
1378 bool haves2s = false; // stereo -> stereo
1379 bool havem2s = false; // mono -> stereo
1380 bool haves2m = false; // stereo -> mono
1381
1382 mAudioIns = 2;
1383 mAudioOuts = 2;
1384
1385 // Look only for exact channel constraints
1386 for (auto &ci : info) {
1387 int ic = ci.inChannels;
1388 int oc = ci.outChannels;
1389
1390 if (ic < 0 && oc >= 0)
1391 ic = 2;
1392 else if (ic >= 0 && oc < 0)
1393 oc = 2;
1394 else if (ic < 0 && oc < 0) {
1395 ic = 2;
1396 oc = 2;
1397 }
1398
1399 if (ic == 2 && oc == 2)
1400 haves2s = true;
1401 else if (ic == 1 && oc == 1)
1402 havem2m = true;
1403 else if (ic == 1 && oc == 2)
1404 havem2s = true;
1405 else if (ic == 2 && oc == 1)
1406 haves2m = true;
1407 else if (ic == 0 && oc == 2)
1408 haven2s = true;
1409 else if (ic == 0 && oc == 1)
1410 haven2m = true;
1411 else if (ic == 1 && oc == 0)
1412 havem2n = true;
1413 else if (ic == 2 && oc == 0)
1414 haves2n = true;
1415 }
1416
1417 if (haves2s) {
1418 mAudioIns = 2;
1419 mAudioOuts = 2;
1420 }
1421 else if (havem2m) {
1422 mAudioIns = 1;
1423 mAudioOuts = 1;
1424 }
1425 else if (havem2s) {
1426 mAudioIns = 1;
1427 mAudioOuts = 2;
1428 }
1429 else if (haves2m) {
1430 mAudioIns = 2;
1431 mAudioOuts = 1;
1432 }
1433 else if (haven2m) {
1434 mAudioIns = 0;
1435 mAudioOuts = 1;
1436 }
1437 else if (haven2s) {
1438 mAudioIns = 0;
1439 mAudioOuts = 2;
1440 }
1441 else if (haves2n) {
1442 mAudioIns = 2;
1443 mAudioOuts = 0;
1444 }
1445 else if (havem2n) {
1446 mAudioIns = 1;
1447 mAudioOuts = 0;
1448 }
1449
1450 return;
1451}
1452
1454{
1455 UInt32 value = (bypass ? 1 : 0);
1456 return !SetProperty(kAudioUnitProperty_BypassEffect, value);
1457}
1458
1459#endif
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
@ Internal
Indicates internal failure from Audacity.
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
constexpr auto OptionsKey
constexpr auto UseLatencyKey
#define PRESET_KEY
#define PRESET_FORMAT
#define PRESET_USER_PATH
constexpr auto UITypeKey
#define AUDIOUNITEFFECTS_FAMILY
static const auto BasicValue
static const auto FullValue
static TransactionScope::Factory::Scope scope
const TranslatableString name
Definition: Distortion.cpp:82
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeNone
@ EffectTypeProcess
enum ChannelName * ChannelNames
wxString RegistryPath
Definition: Identifier.h:218
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:162
wxString FilePath
Definition: Project.h:20
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
for(int ii=0, nn=names.size();ii< nn;++ii)
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
static const auto fn
void Close()
void ForceRedraw()
An Effect class that handles a wide range of effects. ??Mac only??
bool CopyParameters(AudioUnit srcUnit, AudioUnit dstUnit)
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
sampleCount GetLatency() override
bool HasOptions() override
TranslatableString SaveBlobToConfig(const RegistryPath &group, const wxString &path, const void *blob, size_t len, bool allowEmpty=true) const
bool RealtimeProcessStart(EffectSettings &settings) override
AUControl * mpControl
static OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
bool CloseUI() override
TranslatableString InterpretBlob(const wxString &group, const wxMemoryBuffer &buf) const
Interpret the dump made before by MakeBlob.
bool SaveUserPreset(const RegistryPath &name, const EffectSettings &settings) const override
Save settings in the configuration file as a user-named preset.
bool IsDefault() const override
Whether the effect sorts "above the line" in the menus.
AudioUnitEffect(const PluginPath &path, const wxString &name, AudioComponent component, AudioUnitEffect *master=NULL)
int GetMidiOutCount() const override
Function that has not yet found a use.
AudioTimeStamp mTimeStamp
bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const override
Store settings as keys and values.
bool BypassEffect(bool bypass)
size_t GetBlockSize() const override
PluginPath GetPath() const override
bool RealtimeSuspend() override
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
EffectType GetType() const override
Type determines how it behaves.
OSStatus Render(AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
void ShowOptions() override
TranslatableString GetDescription() const override
AudioUnitEffect *const mMaster
bool SupportsRealtime() const override
Whether the effect supports realtime previewing (while audio is playing).
void ImportPresets(EffectSettings &settings) override
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
bool ProcessFinalize() override
bool ProcessInitialize(EffectSettings &settings, sampleCount totalLen, ChannelNames chanMap) override
size_t RealtimeProcess(int group, EffectSettings &settings, const float *const *inbuf, float *const *outbuf, size_t numSamples) override
int GetMidiInCount() const override
Function that has not yet found a use.
bool CanExportPresets() override
std::unique_ptr< EffectUIValidator > PopulateUI(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Adds controls to a panel that is given as the parent window of S
virtual ~AudioUnitEffect()
bool LoadPreset(const RegistryPath &group, EffectSettings &settings) const
bool ValidateUI(EffectSettings &) override
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
TranslatableString Export(const wxString &path) const
bool RealtimeAddProcessor(EffectSettings &settings, unsigned numChannels, float sampleRate) override
wxWindow * mParent
PackedArray::Ptr< AudioBufferList > mOutputList
std::pair< CF_ptr< CFDataRef >, TranslatableString > MakeBlob(const wxCFStringRef &cfname, bool binary) const
Obtain dump of the setting state of an AudioUnit instance.
EffectFamilySymbol GetFamily() const override
Report identifier and user-visible name of the effect protocol.
bool RealtimeFinalize(EffectSettings &settings) noexcept override
bool RealtimeProcessEnd(EffectSettings &settings) noexcept override
AudioUnitEffectArray mSlaves
bool LoadFactoryPreset(int id, EffectSettings &settings) const override
Change settings to the preset whose name is GetFactoryPresets()[id]
wxWeakRef< wxDialog > mDialog
bool SavePreset(const RegistryPath &group) const
TranslatableString Import(const wxString &path)
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
PackedArray::Ptr< AudioBufferList > mInputList
bool RealtimeResume() noexcept override
void Notify(AudioUnit unit, AudioUnitParameterID parm) const
const wxString mName
bool IsGraphicalUI() override
bool SupportsAutomation() const override
Whether the effect has any automatable controls.
bool LoadUserPreset(const RegistryPath &name, EffectSettings &settings) const override
Change settings to a user-named preset.
wxString GetVersion() const override
void SetSampleRate(double rate) override
const wxString mVendor
void ExportPresets(const EffectSettings &settings) const override
std::shared_ptr< EffectInstance > DoMakeInstance()
VendorSymbol GetVendor() const override
const PluginPath mPath
static void EventListenerCallback(void *inCallbackRefCon, void *inObject, const AudioUnitEvent *inEvent, UInt64 inEventHostTime, AudioUnitParameterValue inParameterValue)
bool RealtimeInitialize(EffectSettings &settings) override
AudioUnitCleanup< AUEventListenerRef, AUListenerDispose > mEventListenerRef
size_t SetBlockSize(size_t maxBlockSize) override
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
int ShowClientInterface(wxWindow &parent, wxDialog &dialog, bool forceModal) override
ComponentInterfaceSymbol GetSymbol() const override
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
void EventListener(const AudioUnitEvent *inEvent, AudioUnitParameterValue inParameterValue)
AudioUnitCleanup< AudioUnit, AudioUnitUninitialize > mInitialization
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
bool SetParameters(const wxString &parms)
TranslatableString GetName() const
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Performs effect computation.
Abstract base class used in importing a file.
AudioUnitParameterInfo info
static const char idBeg
bool Get(AudioUnit mUnit, AudioUnitParameterID parmID)
static const char idSep
static const char idEnd
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
Holds a msgid for the translation catalog; may also bind format arguments.
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
OSStatus GetFixedSizeProperty(AudioUnit unit, AudioUnitPropertyID inID, T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0)
OSStatus SetProperty(AudioUnit unit, AudioUnitPropertyID inID, const T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0)
size_t Count(const Ptr< Type, BaseDeleter > &p)
Find out how many elements were allocated with a Ptr.
Definition: PackedArray.h:105
bool SetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, const Value &value)
bool RemoveConfig(const EffectDefinitionInterface &ident, PluginSettings::ConfigurationType type, const RegistryPath &group, const RegistryPath &key)
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
Common base class for AudioUnitEffect and its Instance.
OSStatus GetFixedSizeProperty(AudioUnitPropertyID inID, T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
OSStatus GetVariableSizeProperty(AudioUnitPropertyID inID, PackedArray::Ptr< T > &pObject, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
AudioUnitCleanup< AudioUnit, AudioComponentInstanceDispose > mUnit
OSStatus SetProperty(AudioUnitPropertyID inID, const T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
const AudioComponent mComponent
Externalized state of a plug-in.
Smart pointer type that deallocates with Deleter.
Definition: PackedArray.h:91