Audacity  2.2.2
AudioUnitEffect.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  AudioUnitEffect.cpp
6 
7  Dominic Mazzoni
8  Leland Lucius
9 
10 *******************************************************************//*******************************************************************/
16 
17 #include "../../Audacity.h"
18 
19 #if USE_AUDIO_UNITS
20 
21 #include <wx/defs.h>
22 #include <wx/button.h>
23 #include <wx/control.h>
24 #include <wx/dir.h>
25 #include <wx/crt.h>
26 
27 #ifdef __WXMAC__
28 #include <wx/evtloop.h>
29 #endif
30 
31 #include <wx/filename.h>
32 #include <wx/frame.h>
33 #include <wx/listctrl.h>
34 #include <wx/sizer.h>
35 #include <wx/settings.h>
36 #include <wx/stattext.h>
37 #include <wx/textctrl.h>
38 #include <wx/tokenzr.h>
39 
40 #include "../../ShuttleGui.h"
41 #include "../../widgets/valnum.h"
42 #include "../../widgets/wxPanelWrapper.h"
43 
44 #include "AudioUnitEffect.h"
45 #include "../../Internat.h"
46 
47 struct CFReleaser
48  { void operator () (const void *p) const { if (p) CFRelease(p); } };
49 template <typename T>
50  using CFunique_ptr = std::unique_ptr<T, CFReleaser>;
51 
52 struct AudioUnitParameterInfoEx : AudioUnitParameterInfo
53 {
54  ~AudioUnitParameterInfoEx ()
55  {
56  if ((flags & kAudioUnitParameterFlag_HasCFNameString)
57  &&
58  (flags & kAudioUnitParameterFlag_CFNameRelease))
59  CFRelease( cfNameString );
60  }
61 };
62 
63 // ============================================================================
64 // Module registration entry point
65 //
66 // This is the symbol that Audacity looks for when the module is built as a
67 // dynamic library.
68 //
69 // When the module is builtin to Audacity, we use the same function, but it is
70 // declared static so as not to clash with other builtin modules.
71 // ============================================================================
72 DECLARE_MODULE_ENTRY(AudacityModule)
73 {
74  // Create and register the importer
75  // Trust the module manager not to leak this
76  return safenew AudioUnitEffectsModule(moduleManager, path);
77 }
78 
79 // ============================================================================
80 // Register this as a builtin module
81 // ============================================================================
82 DECLARE_BUILTIN_MODULE(AudioUnitEffectsBuiltin);
83 
85 //
86 // AudioUnitEffectsModule
87 //
89 
90 AudioUnitEffectsModule::AudioUnitEffectsModule(ModuleManagerInterface *moduleManager,
91  const wxString *path)
92 {
93  mModMan = moduleManager;
94  if (path)
95  {
96  mPath = *path;
97  }
98 }
99 
100 AudioUnitEffectsModule::~AudioUnitEffectsModule()
101 {
102  mPath.Clear();
103 }
104 
105 // ============================================================================
106 // IdentInterface implementation
107 // ============================================================================
108 
109 wxString AudioUnitEffectsModule::GetPath()
110 {
111  return mPath;
112 }
113 
114 IdentInterfaceSymbol AudioUnitEffectsModule::GetSymbol()
115 {
116  /* 18n-hint: Audio Unit is the name of an Apple audio software protocol */
117  return XO("Audio Unit Effects");
118 }
119 
120 IdentInterfaceSymbol AudioUnitEffectsModule::GetVendor()
121 {
122  return XO("The Audacity Team");
123 }
124 
125 wxString AudioUnitEffectsModule::GetVersion()
126 {
127  // This "may" be different if this were to be maintained as a separate DLL
128  return AUDIOUNITEFFECTS_VERSION;
129 }
130 
131 wxString AudioUnitEffectsModule::GetDescription()
132 {
133  return _("Provides Audio Unit Effects support to Audacity");
134 }
135 
136 // ============================================================================
137 // ModuleInterface implementation
138 // ============================================================================
139 
140 wxArrayString AudioUnitEffectsModule::FileExtensions()
141 {
142  static const wxString ext[] = { _T("au") };
143  static const wxArrayString result{ sizeof(ext)/sizeof(*ext), ext };
144  return result;
145 }
146 
147 bool AudioUnitEffectsModule::Initialize()
148 {
149  // Nothing to do here
150  return true;
151 }
152 
153 void AudioUnitEffectsModule::Terminate()
154 {
155  // Nothing to do here
156  return;
157 }
158 
159 bool AudioUnitEffectsModule::AutoRegisterPlugins(PluginManagerInterface & pm)
160 {
161  // Nothing to be done here
162  return true;
163 }
164 
165 wxArrayString AudioUnitEffectsModule::FindPluginPaths(PluginManagerInterface & pm)
166 {
167  wxArrayString effects;
168 
169  LoadAudioUnitsOfType(kAudioUnitType_Effect, effects);
170  LoadAudioUnitsOfType(kAudioUnitType_Generator, effects);
171  LoadAudioUnitsOfType(kAudioUnitType_MusicEffect, effects);
172  LoadAudioUnitsOfType(kAudioUnitType_Mixer, effects);
173  LoadAudioUnitsOfType(kAudioUnitType_Panner, effects);
174 
175  return effects;
176 }
177 
178 unsigned AudioUnitEffectsModule::DiscoverPluginsAtPath(
179  const wxString & path, wxString &errMsg,
180  const RegistrationCallback &callback)
181 {
182  errMsg.clear();
183  wxString name;
184  AudioComponent component = FindAudioUnit(path, name);
185  if (component == NULL)
186  {
187  errMsg = _("Could not find component");
188  return 0;
189  }
190 
191  AudioUnitEffect effect(path, name, component);
192  if (!effect.SetHost(NULL))
193  {
194  // TODO: Is it worth it to discriminate all the ways SetHost might
195  // return false?
196  errMsg = _("Could not initialize component");
197  return 0;
198  }
199 
200  if(callback)
201  callback(this, &effect);
202 
203  return 1;
204 }
205 
206 bool AudioUnitEffectsModule::IsPluginValid(
207  const wxString & path, bool bFast)
208 {
209  if( bFast )
210  return true;
211  wxString name;
212  return FindAudioUnit(path, name) != NULL;
213 }
214 
215 IdentInterface *AudioUnitEffectsModule::CreateInstance(const wxString & path)
216 {
217  // Acquires a resource for the application.
218  wxString name;
219  AudioComponent component = FindAudioUnit(path, name);
220  if (component == NULL)
221  {
222  return NULL;
223  }
224 
225  // Safety of this depends on complementary calls to DeleteInstance on the module manager side.
226  return safenew AudioUnitEffect(path, name, component);
227 }
228 
229 void AudioUnitEffectsModule::DeleteInstance(IdentInterface *instance)
230 {
231  std::unique_ptr < AudioUnitEffect > {
232  dynamic_cast<AudioUnitEffect *>(instance)
233  };
234 }
235 
236 // ============================================================================
237 // AudioUnitEffectsModule implementation
238 // ============================================================================
239 
240 void AudioUnitEffectsModule::LoadAudioUnitsOfType(OSType inAUType,
241  wxArrayString & effects)
242 {
243  AudioComponentDescription desc;
244  AudioComponent component;
245 
246  desc.componentType = inAUType;
247  desc.componentSubType = 0;
248  desc.componentManufacturer = 0;
249  desc.componentFlags = 0;
250  desc.componentFlagsMask = 0;
251 
252  component = AudioComponentFindNext(NULL, &desc);
253  while (component != NULL)
254  {
255  OSStatus result;
256  AudioComponentDescription found;
257 
258  result = AudioComponentGetDescription(component, &found);
259  if (result == noErr)
260  {
261  CFStringRef cfName{};
262  result = AudioComponentCopyName(component, &cfName);
263  CFunique_ptr<const __CFString> uName{ cfName };
264 
265  if (result == noErr)
266  {
267  wxString name = wxCFStringRef::AsString(cfName);
268 
269  effects.Add(wxString::Format(wxT("%-4.4s/%-4.4s/%-4.4s/%s"),
270  FromOSType(found.componentManufacturer),
271  FromOSType(found.componentType),
272  FromOSType(found.componentSubType),
273  name));
274  }
275  }
276 
277  component = AudioComponentFindNext(component, &desc);
278  }
279 }
280 
281 AudioComponent AudioUnitEffectsModule::FindAudioUnit(const wxString & path,
282  wxString & name)
283 {
284  wxStringTokenizer tokens(path, wxT("/"));
285 
286  AudioComponentDescription desc;
287 
288  desc.componentManufacturer = ToOSType(tokens.GetNextToken());
289  desc.componentType = ToOSType(tokens.GetNextToken());
290  desc.componentSubType = ToOSType(tokens.GetNextToken());
291  desc.componentFlags = 0;
292  desc.componentFlagsMask = 0;
293 
294  name = tokens.GetNextToken();
295 
296  return AudioComponentFindNext(NULL, &desc);
297 }
298 
299 wxString AudioUnitEffectsModule::FromOSType(OSType type)
300 {
301  OSType rev = (type & 0xff000000) >> 24 |
302  (type & 0x00ff0000) >> 8 |
303  (type & 0x0000ff00) << 8 |
304  (type & 0x000000ff) << 24;
305 
306  return wxString::FromUTF8((char *)&rev, 4);
307 }
308 
309 OSType AudioUnitEffectsModule::ToOSType(const wxString & type)
310 {
311  wxCharBuffer buf = type.ToUTF8();
312 
313  OSType rev = ((unsigned char)buf.data()[0]) << 24 |
314  ((unsigned char)buf.data()[1]) << 16 |
315  ((unsigned char)buf.data()[2]) << 8 |
316  ((unsigned char)buf.data()[3]);
317 
318  return rev;
319 }
320 
322 //
323 // AudioUnitEffectOptionsDialog
324 //
326 
327 class AudioUnitEffectOptionsDialog final : public wxDialogWrapper
328 {
329 public:
330  AudioUnitEffectOptionsDialog(wxWindow * parent, EffectHostInterface *host);
331  virtual ~AudioUnitEffectOptionsDialog();
332 
333  void PopulateOrExchange(ShuttleGui & S);
334 
335  void OnOk(wxCommandEvent & evt);
336 
337 private:
338  EffectHostInterface *mHost;
339 
340  bool mUseLatency;
341  wxString mUIType;
342 
343  wxArrayString mUITypes;
344 
345  DECLARE_EVENT_TABLE()
346 };
347 
348 BEGIN_EVENT_TABLE(AudioUnitEffectOptionsDialog, wxDialogWrapper)
349  EVT_BUTTON(wxID_OK, AudioUnitEffectOptionsDialog::OnOk)
351 
352 AudioUnitEffectOptionsDialog::AudioUnitEffectOptionsDialog(wxWindow * parent, EffectHostInterface *host)
353 : wxDialogWrapper(parent, wxID_ANY, wxString(_("Audio Unit Effect Options")))
354 {
355  mHost = host;
356 
357  mUITypes.Add(_("Full"));
358  mUITypes.Add(_("Generic"));
359  mUITypes.Add(_("Basic"));
360 
361  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
362  mHost->GetSharedConfig(wxT("Options"), wxT("UIType"), mUIType, wxT("Full"));
363 
364  mUIType = wxGetTranslation(mUIType);
365 
366  ShuttleGui S(this, eIsCreating);
367  PopulateOrExchange(S);
368 }
369 
370 AudioUnitEffectOptionsDialog::~AudioUnitEffectOptionsDialog()
371 {
372 }
373 
374 void AudioUnitEffectOptionsDialog::PopulateOrExchange(ShuttleGui & S)
375 {
376 
377  S.SetBorder(5);
378  S.StartHorizontalLay(wxEXPAND, 1);
379  {
380  S.StartVerticalLay(false);
381  {
382  S.StartStatic(_("Latency Compensation"));
383  {
384  S.AddVariableText(wxString() +
385  _("As part of their processing, some Audio Unit effects must delay returning ") +
386  _("audio to Audacity. When not compensating for this delay, you will ") +
387  _("notice that small silences have been inserted into the audio. ") +
388  _("Enabling this option will provide that compensation, but it may ") +
389  _("not work for all Audio Unit effects."))->Wrap(650);
390 
391  S.StartHorizontalLay(wxALIGN_LEFT);
392  {
393  S.TieCheckBox(_("Enable &compensation"),
394  mUseLatency);
395  }
396  S.EndHorizontalLay();
397  }
398  S.EndStatic();
399 
400  S.StartStatic(_("User Interface"));
401  {
402  S.AddVariableText(wxString() +
403  _("Select \"Full\" to use the graphical interface if supplied by the Audio Unit.") +
404  _(" Select \"Generic\" to use the system supplied generic interface.") +
405  _(" Select \"Basic\" for a basic text-only interface. ") +
406  _(" Reopen the effect for this to take effect."))->Wrap(650);
407 
408  S.StartHorizontalLay(wxALIGN_LEFT);
409  {
410  S.TieChoice(_("Select &interface"),
411  mUIType,
412  &mUITypes);
413  }
414  S.EndHorizontalLay();
415  }
416  S.EndStatic();
417  }
418  S.EndVerticalLay();
419  }
420  S.EndHorizontalLay();
421 
422  S.AddStandardButtons();
423 
424  Layout();
425  Fit();
426  Center();
427 }
428 
429 void AudioUnitEffectOptionsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
430 {
431  if (!Validate())
432  {
433  return;
434  }
435 
437  PopulateOrExchange(S);
438 
439  if (mUIType == _("Full"))
440  {
441  mUIType = wxT("Full");
442  }
443  else if (mUIType == _("Generic"))
444  {
445  mUIType = wxT("Generic");
446  }
447  else if (mUIType == _("Basic"))
448  {
449  mUIType = wxT("Basic");
450  }
451 
452  mHost->SetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency);
453  mHost->SetSharedConfig(wxT("Options"), wxT("UIType"), mUIType);
454 
455  EndModal(wxID_OK);
456 }
457 
459 //
460 // AudioUnitEffectExportDialog
461 //
463 
464 #define PRESET_LOCAL_PATH wxT("/Library/Audio/Presets")
465 #define PRESET_USER_PATH wxT("~/Library/Audio/Presets")
466 
467 class AudioUnitEffectExportDialog final : public wxDialogWrapper
468 {
469 public:
470  AudioUnitEffectExportDialog(wxWindow * parent, AudioUnitEffect *effect);
471  virtual ~AudioUnitEffectExportDialog();
472 
473  void PopulateOrExchange(ShuttleGui & S);
474 
475  void OnOk(wxCommandEvent & evt);
476 
477 private:
478  wxWindow *mParent;
479  AudioUnitEffect *mEffect;
480 
481  wxListCtrl *mList;
482 
483  DECLARE_EVENT_TABLE()
484 };
485 
486 BEGIN_EVENT_TABLE(AudioUnitEffectExportDialog, wxDialogWrapper)
487  EVT_BUTTON(wxID_OK, AudioUnitEffectExportDialog::OnOk)
489 
490 AudioUnitEffectExportDialog::AudioUnitEffectExportDialog(wxWindow * parent, AudioUnitEffect *effect)
491 : wxDialogWrapper(parent, wxID_ANY, wxString(_("Export Audio Unit Presets")))
492 {
493  mEffect = effect;
494 
495  ShuttleGui S(this, eIsCreating);
496  PopulateOrExchange(S);
497 }
498 
499 AudioUnitEffectExportDialog::~AudioUnitEffectExportDialog()
500 {
501 }
502 
503 void AudioUnitEffectExportDialog::PopulateOrExchange(ShuttleGui & S)
504 {
505  S.SetBorder(5);
506  S.StartHorizontalLay(wxEXPAND, 1);
507  {
508  S.StartVerticalLay(true);
509  {
510  S.StartStatic(_("Presets (may select multiple)"));
511  {
512  S.SetStyle(wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
513  wxLC_NO_SORT_HEADER);
514  mList = S.AddListControlReportMode();
515  mList->InsertColumn(0, _("Preset"), wxLIST_FORMAT_LEFT);
516  }
517  S.EndStatic();
518  }
519  S.EndVerticalLay();
520  }
521  S.EndHorizontalLay();
522 
523  S.AddStandardButtons();
524 
525  wxArrayString presets;
526 
527  mEffect->mHost->GetPrivateConfigSubgroups(mEffect->mHost->GetUserPresetsGroup(wxEmptyString), presets);
528 
529  presets.Sort();
530 
531  for (size_t i = 0, cnt = presets.GetCount(); i < cnt; i++)
532  {
533  mList->InsertItem(i, presets[i]);
534  }
535 
536  mList->SetColumnWidth(0, wxLIST_AUTOSIZE);
537 
538  // Set the list size...with a little extra for good measure
539  wxSize sz = mList->GetBestSize();
540  sz.x += 5;
541  sz.y += 5;
542  mList->SetMinSize(sz);
543 
544  Layout();
545  Fit();
546  Center();
547 }
548 
549 void AudioUnitEffectExportDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
550 {
551  // Save active settings
552  wxString settingsName(wxT("Export Save"));
553  mEffect->SaveParameters(settingsName);
554 
555  // Look for selected presets
556  long sel = mList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
557  while (sel >= 0)
558  {
559  wxString name = mList->GetItemText(sel);
560 
561  // Make the preset current
562  mEffect->LoadParameters(mEffect->mHost->GetUserPresetsGroup(name));
563 
564  // Make sure the user preset directory exists
565  wxString path;
566  path.Printf(wxT("%s/%s/%s/%s.aupreset"),
567  PRESET_USER_PATH,
568  mEffect->mVendor,
569  mEffect->mName,
570  name);
571  wxFileName fn(path);
572  fn.Normalize();
573  fn.Mkdir(0755, wxPATH_MKDIR_FULL);
574  path = fn.GetFullPath();
575 
576  // First set the name of the preset
577  wxCFStringRef cfname(name);
578 
579  AUPreset preset;
580  preset.presetNumber = -1; // indicates user preset
581  preset.presetName = cfname;
582 
583  AudioUnitSetProperty(mEffect->mUnit,
584  kAudioUnitProperty_PresentPreset,
585  kAudioUnitScope_Global,
586  0,
587  &preset,
588  sizeof(preset));
589 
590  // Now retrieve the preset content
591  CFPropertyListRef content;
592  UInt32 size = sizeof(content);
593  AudioUnitGetProperty(mEffect->mUnit,
594  kAudioUnitProperty_ClassInfo,
595  kAudioUnitScope_Global,
596  0,
597  &content,
598  &size);
599 
600  // And convert it to XML
601  CFunique_ptr<const __CFData> xml {
602  CFPropertyListCreateXMLData(kCFAllocatorDefault, content)
603  };
604  if (xml)
605  {
606  // Create the CFURL for the path
607  CFunique_ptr<const __CFURL> url {
608  CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
609  wxCFStringRef(path),
610  kCFURLPOSIXPathStyle,
611  false)
612  };
613  if (url)
614  {
615  SInt32 error;
616  Boolean res = CFURLWriteDataAndPropertiesToResource(url.get(),
617  xml.get(),
618  NULL,
619  &error);
620  }
621  }
622 
623  // And continue to the next selected preset
624  sel = mList->GetNextItem(sel, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
625  }
626 
627  // Restore active settings
628  mEffect->LoadParameters(settingsName);
629  mEffect->mHost->RemovePrivateConfigSubgroup(settingsName);
630 
631  EndModal(wxID_OK);
632 }
633 
635 //
636 // AudioUnitEffectImportDialog
637 //
639 
640 class AudioUnitEffectImportDialog final : public wxDialogWrapper
641 {
642 public:
643  AudioUnitEffectImportDialog(wxWindow * parent, AudioUnitEffect *effect);
644  virtual ~AudioUnitEffectImportDialog();
645 
646  void PopulateOrExchange(ShuttleGui & S);
647 
648  void OnOk(wxCommandEvent & evt);
649 
650 private:
651  wxWindow *mParent;
652  AudioUnitEffect *mEffect;
653 
654  wxListCtrl *mList;
655 
656  DECLARE_EVENT_TABLE()
657 };
658 
659 BEGIN_EVENT_TABLE(AudioUnitEffectImportDialog, wxDialogWrapper)
660  EVT_BUTTON(wxID_OK, AudioUnitEffectImportDialog::OnOk)
662 
663 AudioUnitEffectImportDialog::AudioUnitEffectImportDialog(wxWindow * parent, AudioUnitEffect *effect)
664 : wxDialogWrapper(parent, wxID_ANY, wxString(_("Import Audio Unit Presets")))
665 {
666  mEffect = effect;
667 
668  ShuttleGui S(this, eIsCreating);
669  PopulateOrExchange(S);
670 }
671 
672 AudioUnitEffectImportDialog::~AudioUnitEffectImportDialog()
673 {
674 }
675 
676 void AudioUnitEffectImportDialog::PopulateOrExchange(ShuttleGui & S)
677 {
678  S.SetBorder(5);
679  S.StartHorizontalLay(wxEXPAND, 1);
680  {
681  S.StartVerticalLay(true);
682  {
683  S.StartStatic(_("Presets (may select multiple)"));
684  {
685  S.SetStyle(wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
686  wxLC_NO_SORT_HEADER);
687  mList = S.AddListControlReportMode();
688  mList->InsertColumn(0, _("Preset"), wxLIST_FORMAT_LEFT);
689  mList->InsertColumn(1, _("Location"), wxLIST_FORMAT_LEFT);
690  }
691  S.EndStatic();
692  }
693  S.EndVerticalLay();
694  }
695  S.EndHorizontalLay();
696 
697  S.AddStandardButtons();
698 
699  wxArrayString presets;
700 
701  // Make sure the user preset directory exists
702  wxString path;
703  path.Printf(wxT("%s/%s/%s"),
704  PRESET_LOCAL_PATH,
705  mEffect->mVendor,
706  mEffect->mName);
707  wxFileName fn(path);
708  fn.Normalize();
709 
710  // Get all presets in the local domain for this effect
711  wxDir::GetAllFiles(fn.GetFullPath(), &presets, wxT("*.aupreset"));
712 
713  path.Printf(wxT("%s/%s/%s"),
714  PRESET_USER_PATH,
715  mEffect->mVendor,
716  mEffect->mName);
717  fn = path;
718  fn.Normalize();
719 
720  // Get all presets in the user domain for this effect
721  wxDir::GetAllFiles(fn.GetFullPath(), &presets, wxT("*.aupreset"));
722 
723  presets.Sort();
724 
725  for (size_t i = 0, cnt = presets.GetCount(); i < cnt; i++)
726  {
727  fn = presets[i];
728  mList->InsertItem(i, fn.GetName());
729  mList->SetItem(i, 1, fn.GetPath());
730  }
731 
732  mList->SetColumnWidth(0, wxLIST_AUTOSIZE);
733  mList->SetColumnWidth(1, wxLIST_AUTOSIZE);
734 
735  // Set the list size...with a little extra for good measure
736  wxSize sz = mList->GetBestSize();
737  sz.x += 5;
738  sz.y += 5;
739  mList->SetMinSize(sz);
740 
741  Layout();
742  Fit();
743  Center();
744 }
745 
746 void AudioUnitEffectImportDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
747 {
748  // Save active settings
749  wxString settingsName(wxT("Import Save"));
750  mEffect->SaveParameters(settingsName);
751 
752  // Look for selected presets
753  long sel = -1;
754  while ((sel = mList->GetNextItem(sel, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) >= 0)
755  {
756  wxListItem item;
757  item.SetId(sel);
758  item.SetColumn(1);
759  item.SetMask(wxLIST_MASK_TEXT);
760  mList->GetItem(item);
761 
762  wxString path;
763  path.Printf(wxT("%s/%s.aupreset"),
764  item.GetText(),
765  mList->GetItemText(sel));
766 
767  // Create the CFURL for the path
768  CFunique_ptr<const __CFURL> url {
769  CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
770  wxCFStringRef(path),
771  kCFURLPOSIXPathStyle,
772  false)
773  };
774 
775  if (!url)
776  {
777  continue;
778  }
779 
780  CFDataRef xml{};
781  SInt32 error;
782  Boolean res = CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
783  url.get(),
784  &xml,
785  NULL,
786  NULL,
787  &error);
788  CFunique_ptr<const __CFData> uxml { xml };
789 
790  if (!res)
791  {
792  continue;
793  }
794 
795  CFunique_ptr<char> content {
796  (char*)CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
797  xml,
798  kCFPropertyListImmutable,
799  NULL)
800  };
801 
802  if (!content)
803  {
804  continue;
805  }
806 
807  OSStatus result = AudioUnitSetProperty(mEffect->mUnit,
808  kAudioUnitProperty_ClassInfo,
809  kAudioUnitScope_Global,
810  0,
811  &content,
812  sizeof(content));
813 
814  mEffect->SaveUserPreset(mEffect->mHost->GetUserPresetsGroup(mList->GetItemText(sel)));
815  }
816 
817  // Restore active settings
818  mEffect->LoadParameters(settingsName);
819  mEffect->mHost->RemovePrivateConfigSubgroup(settingsName);
820 
821  EndModal(wxID_OK);
822 }
823 
825 //
826 // AudioUnitEffect
827 //
829 
830 AudioUnitEffect::AudioUnitEffect(const wxString & path,
831  const wxString & name,
832  AudioComponent component,
833  AudioUnitEffect *master)
834 {
835  mPath = path;
836  mName = name.AfterFirst(wxT(':')).Trim(true).Trim(false);
837  mVendor = name.BeforeFirst(wxT(':')).Trim(true).Trim(false);
838  mComponent = component;
839  mMaster = master;
840 
841  mUnit = NULL;
842 
843  mBlockSize = 0.0;
844  mInteractive = false;
845  mIsGraphical = false;
846 
847  mUIHost = NULL;
848  mDialog = NULL;
849  mParent = NULL;
850 
851  mUnitInitialized = false;
852 
853  mEventListenerRef = NULL;
854 }
855 
856 AudioUnitEffect::~AudioUnitEffect()
857 {
858  if (mUnitInitialized)
859  {
860  AudioUnitUninitialize(mUnit);
861  }
862 
863  if (mEventListenerRef)
864  {
865  AUListenerDispose(mEventListenerRef);
866  }
867 
868  if (mUnit)
869  {
870  AudioComponentInstanceDispose(mUnit);
871  }
872 }
873 
874 // ============================================================================
875 // IdentInterface implementation
876 // ============================================================================
877 
878 wxString AudioUnitEffect::GetPath()
879 {
880  return mPath;
881 }
882 
883 IdentInterfaceSymbol AudioUnitEffect::GetSymbol()
884 {
885  return mName;
886 }
887 
888 IdentInterfaceSymbol AudioUnitEffect::GetVendor()
889 {
890  return { mVendor };
891 }
892 
893 wxString AudioUnitEffect::GetVersion()
894 {
895  UInt32 version;
896 
897  OSStatus result = AudioComponentGetVersion(mComponent, &version);
898 
899  return wxString::Format(wxT("%d.%d.%d"),
900  (version >> 16) & 0xffff,
901  (version >> 8) & 0xff,
902  version & 0xff);
903 }
904 
905 wxString AudioUnitEffect::GetDescription()
906 {
907  /* i18n-hint: Can mean "not available," "not applicable," "no answer" */
908  return _("n/a");
909 }
910 
911 // ============================================================================
912 // EffectIdentInterface implementation
913 // ============================================================================
914 
915 EffectType AudioUnitEffect::GetType()
916 {
917  if (mAudioIns == 0 && mAudioOuts == 0)
918  {
919  return EffectTypeNone;
920  }
921 
922  if (mAudioIns == 0)
923  {
924  return EffectTypeGenerate;
925  }
926 
927  if (mAudioOuts == 0)
928  {
929  return EffectTypeAnalyze;
930  }
931 
932  return EffectTypeProcess;
933 }
934 
935 IdentInterfaceSymbol AudioUnitEffect::GetFamilyId()
936 {
937  return AUDIOUNITEFFECTS_FAMILY;
938 }
939 
940 bool AudioUnitEffect::IsInteractive()
941 {
942  return mInteractive;
943 }
944 
945 bool AudioUnitEffect::IsDefault()
946 {
947  return false;
948 }
949 
950 bool AudioUnitEffect::IsLegacy()
951 {
952  return false;
953 }
954 
955 bool AudioUnitEffect::SupportsRealtime()
956 {
957  return GetType() == EffectTypeProcess;
958 }
959 
960 bool AudioUnitEffect::SupportsAutomation()
961 {
962  OSStatus result;
963  UInt32 dataSize;
964  Boolean isWritable;
965 
966  result = AudioUnitGetPropertyInfo(mUnit,
967  kAudioUnitProperty_ParameterList,
968  kAudioUnitScope_Global,
969  0,
970  &dataSize,
971  &isWritable);
972  if (result != noErr)
973  {
974  return false;
975  }
976 
977  UInt32 cnt = dataSize / sizeof(AudioUnitParameterID);
979 
980  result = AudioUnitGetProperty(mUnit,
981  kAudioUnitProperty_ParameterList,
982  kAudioUnitScope_Global,
983  0,
984  array.get(),
985  &dataSize);
986  if (result != noErr)
987  {
988  return false;
989  }
990 
991  for (int i = 0; i < cnt; i++)
992  {
993  AudioUnitParameterInfoEx info;
994  dataSize = sizeof(info);
995  result = AudioUnitGetProperty(mUnit,
996  kAudioUnitProperty_ParameterInfo,
997  kAudioUnitScope_Global,
998  array[i],
999  &info,
1000  &dataSize);
1001  if (result != noErr)
1002  {
1003  return false;
1004  }
1005 
1006  if (info.flags & kAudioUnitParameterFlag_IsWritable)
1007  {
1008  // All we need is one
1009  return true;
1010  }
1011  }
1012 
1013  return false;
1014 }
1015 
1016 // ============================================================================
1017 // EffectClientInterface Implementation
1018 // ============================================================================
1019 
1020 bool AudioUnitEffect::SetHost(EffectHostInterface *host)
1021 {
1022  OSStatus result;
1023 
1024  mHost = host;
1025 
1026  mSampleRate = 44100;
1027  result = AudioComponentInstanceNew(mComponent, &mUnit);
1028  if (!mUnit)
1029  {
1030  return false;
1031  }
1032 
1033  GetChannelCounts();
1034 
1035  SetRateAndChannels();
1036 
1037  // Retrieve the desired number of frames per slice
1038  UInt32 dataSize = sizeof(mBlockSize);
1039  mBlockSize = 512;
1040  AudioUnitGetProperty(mUnit,
1041  kAudioUnitProperty_MaximumFramesPerSlice,
1042  kAudioUnitScope_Global,
1043  0,
1044  &mBlockSize,
1045  &dataSize);
1046 
1047  // mHost will be null during registration
1048  if (mHost)
1049  {
1050  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
1051  mHost->GetSharedConfig(wxT("Options"), wxT("UIType"), mUIType, wxT("Full"));
1052 
1053  mUIType = wxGetTranslation(mUIType);
1054 
1055  bool haveDefaults;
1056  mHost->GetPrivateConfig(mHost->GetFactoryDefaultsGroup(), wxT("Initialized"), haveDefaults, false);
1057  if (!haveDefaults)
1058  {
1059  SaveParameters(mHost->GetFactoryDefaultsGroup());
1060  mHost->SetPrivateConfig(mHost->GetFactoryDefaultsGroup(), wxT("Initialized"), true);
1061  }
1062 
1063  LoadParameters(mHost->GetCurrentSettingsGroup());
1064  }
1065 
1066  if (!mMaster)
1067  {
1068  result = AUEventListenerCreate(AudioUnitEffect::EventListenerCallback,
1069  this,
1070  (CFRunLoopRef)GetCFRunLoopFromEventLoop(GetCurrentEventLoop()),
1071  kCFRunLoopDefaultMode,
1072  0.0,
1073  0.0,
1074  &mEventListenerRef);
1075  if (result != noErr)
1076  {
1077  return false;
1078  }
1079 
1080  AudioUnitEvent event;
1081 
1082  event.mEventType = kAudioUnitEvent_ParameterValueChange;
1083  event.mArgument.mParameter.mAudioUnit = mUnit;
1084  event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
1085  event.mArgument.mParameter.mElement = 0;
1086 
1087  UInt32 dataSize;
1088  Boolean isWritable;
1089 
1090  // Retrieve the list of properties
1091  result = AudioUnitGetPropertyInfo(mUnit,
1092  kAudioUnitProperty_ParameterList,
1093  kAudioUnitScope_Global,
1094  0,
1095  &dataSize,
1096  &isWritable);
1097  if (result != noErr)
1098  {
1099  return false;
1100  }
1101 
1102  // And get them
1103  UInt32 cnt = dataSize / sizeof(AudioUnitParameterID);
1104  ArrayOf<AudioUnitParameterID> array {cnt};
1105 
1106  result = AudioUnitGetProperty(mUnit,
1107  kAudioUnitProperty_ParameterList,
1108  kAudioUnitScope_Global,
1109  0,
1110  array.get(),
1111  &dataSize);
1112  if (result != noErr)
1113  {
1114  return false;
1115  }
1116 
1117  // Register them as something we're interested in
1118  for (int i = 0; i < cnt; i++)
1119  {
1120  event.mArgument.mParameter.mParameterID = array[i];
1121  result = AUEventListenerAddEventType(mEventListenerRef,
1122  this,
1123  &event);
1124  if (result != noErr)
1125  {
1126  return false;
1127  }
1128  }
1129 
1130  event.mEventType = kAudioUnitEvent_PropertyChange;
1131  event.mArgument.mProperty.mAudioUnit = mUnit;
1132  event.mArgument.mProperty.mPropertyID = kAudioUnitProperty_Latency;
1133  event.mArgument.mProperty.mScope = kAudioUnitScope_Global;
1134  event.mArgument.mProperty.mElement = 0;
1135 
1136  result = AUEventListenerAddEventType(mEventListenerRef,
1137  this,
1138  &event);
1139  if (result != noErr)
1140  {
1141  return false;
1142  }
1143 
1144  AudioUnitCocoaViewInfo cocoaViewInfo;
1145  dataSize = sizeof(AudioUnitCocoaViewInfo);
1146 
1147  // Check for a Cocoa UI
1148  result = AudioUnitGetProperty(mUnit,
1149  kAudioUnitProperty_CocoaUI,
1150  kAudioUnitScope_Global,
1151  0,
1152  &cocoaViewInfo,
1153  &dataSize);
1154 
1155  bool hasCocoa = result == noErr;
1156 
1157  // Check for a Carbon UI
1158  AudioComponentDescription compDesc;
1159  dataSize = sizeof(compDesc);
1160  result = AudioUnitGetProperty(mUnit,
1161  kAudioUnitProperty_GetUIComponentList,
1162  kAudioUnitScope_Global,
1163  0,
1164  &compDesc,
1165  &dataSize);
1166  bool hasCarbon = result == noErr;
1167 
1168  mInteractive = (cnt > 0) || hasCocoa || hasCarbon;
1169  }
1170 
1171  return true;
1172 }
1173 
1174 unsigned AudioUnitEffect::GetAudioInCount()
1175 {
1176  return mAudioIns;
1177 }
1178 
1179 unsigned AudioUnitEffect::GetAudioOutCount()
1180 {
1181  return mAudioOuts;
1182 }
1183 
1184 int AudioUnitEffect::GetMidiInCount()
1185 {
1186  return 0;
1187 }
1188 
1189 int AudioUnitEffect::GetMidiOutCount()
1190 {
1191  return 0;
1192 }
1193 
1194 void AudioUnitEffect::SetSampleRate(double rate)
1195 {
1196  mSampleRate = rate;
1197 }
1198 
1199 size_t AudioUnitEffect::SetBlockSize(size_t maxBlockSize)
1200 {
1201  return mBlockSize;
1202 }
1203 
1204 sampleCount AudioUnitEffect::GetLatency()
1205 {
1206  // Retrieve the latency (can be updated via an event)
1207  if (mUseLatency && !mLatencyDone)
1208  {
1209  mLatencyDone = true;
1210 
1211  Float64 latency = 0.0;
1212  UInt32 dataSize = sizeof(latency);
1213  AudioUnitGetProperty(mUnit,
1214  kAudioUnitProperty_Latency,
1215  kAudioUnitScope_Global,
1216  0,
1217  &latency,
1218  &dataSize);
1219 
1220  return sampleCount( latency * mSampleRate );
1221  }
1222 
1223  return 0;
1224 }
1225 
1226 size_t AudioUnitEffect::GetTailSize()
1227 {
1228  // Retrieve the tail time
1229  Float64 tailTime = 0.0;
1230  UInt32 dataSize = sizeof(tailTime);
1231  AudioUnitGetProperty(mUnit,
1232  kAudioUnitProperty_TailTime,
1233  kAudioUnitScope_Global,
1234  0,
1235  &tailTime,
1236  &dataSize);
1237 
1238  return tailTime * mSampleRate;
1239 }
1240 
1241 bool AudioUnitEffect::IsReady()
1242 {
1243  return mReady;
1244 }
1245 
1246 bool AudioUnitEffect::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
1247 {
1248  OSStatus result;
1249 
1250  mInputList.reinit( mAudioIns );
1251  mInputList[0].mNumberBuffers = mAudioIns;
1252 
1253  mOutputList.reinit( mAudioOuts );
1254  mOutputList[0].mNumberBuffers = mAudioOuts;
1255 
1256  memset(&mTimeStamp, 0, sizeof(AudioTimeStamp));
1257  mTimeStamp.mSampleTime = 0; // This is a double-precision number that should
1258  // accumulate the number of frames processed so far
1259  mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
1260 
1261  if (!SetRateAndChannels())
1262  {
1263  return false;
1264  }
1265 
1266  AURenderCallbackStruct callbackStruct;
1267  callbackStruct.inputProc = RenderCallback;
1268  callbackStruct.inputProcRefCon = this;
1269  result = AudioUnitSetProperty(mUnit,
1270  kAudioUnitProperty_SetRenderCallback,
1271  kAudioUnitScope_Input,
1272  0,
1273  &callbackStruct,
1274  sizeof(AURenderCallbackStruct));
1275  if (result != noErr)
1276  {
1277  wxPrintf("Setting input render callback failed.\n");
1278  return false;
1279  }
1280 
1281  result = AudioUnitReset(mUnit, kAudioUnitScope_Global, 0);
1282  if (result != noErr)
1283  {
1284  return false;
1285  }
1286 
1287  mLatencyDone = false;
1288 
1289  mReady = true;
1290 
1291  return true;
1292 }
1293 
1294 bool AudioUnitEffect::ProcessFinalize()
1295 {
1296  mReady = false;
1297 
1298  mOutputList.reset();
1299  mInputList.reset();
1300 
1301  return true;
1302 }
1303 
1304 size_t AudioUnitEffect::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
1305 {
1306  for (size_t i = 0; i < mAudioIns; i++)
1307  {
1308  mInputList[0].mBuffers[i].mNumberChannels = 1;
1309  mInputList[0].mBuffers[i].mData = inBlock[i];
1310  mInputList[0].mBuffers[i].mDataByteSize = sizeof(float) * blockLen;
1311  }
1312 
1313  for (size_t i = 0; i < mAudioOuts; i++)
1314  {
1315  mOutputList[0].mBuffers[i].mNumberChannels = 1;
1316  mOutputList[0].mBuffers[i].mData = outBlock[i];
1317  mOutputList[0].mBuffers[i].mDataByteSize = sizeof(float) * blockLen;
1318  }
1319 
1320  AudioUnitRenderActionFlags flags = 0;
1321  OSStatus result;
1322 
1323  result = AudioUnitRender(mUnit,
1324  &flags,
1325  &mTimeStamp,
1326  0,
1327  blockLen,
1328  mOutputList.get());
1329  if (result != noErr)
1330  {
1331  wxPrintf("Render failed: %d %4.4s\n", (int)result, (char *)&result);
1332  return 0;
1333  }
1334 
1335  mTimeStamp.mSampleTime += blockLen;
1336 
1337  return blockLen;
1338 }
1339 
1340 bool AudioUnitEffect::RealtimeInitialize()
1341 {
1342  mMasterIn.reinit(mAudioIns, mBlockSize, true);
1343  mMasterOut.reinit( mAudioOuts, mBlockSize );
1344  return ProcessInitialize(0);
1345 }
1346 
1347 bool AudioUnitEffect::RealtimeAddProcessor(unsigned numChannels, float sampleRate)
1348 {
1349  auto slave = std::make_unique<AudioUnitEffect>(mPath, mName, mComponent, this);
1350  if (!slave->SetHost(NULL))
1351  return false;
1352 
1353  slave->SetBlockSize(mBlockSize);
1354  slave->SetChannelCount(numChannels);
1355  slave->SetSampleRate(sampleRate);
1356 
1357  if (!CopyParameters(mUnit, slave->mUnit))
1358  return false;
1359 
1360  auto pSlave = slave.get();
1361  mSlaves.push_back(std::move(slave));
1362 
1363  return pSlave->ProcessInitialize(0);
1364 }
1365 
1366 bool AudioUnitEffect::RealtimeFinalize()
1367 {
1368  for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
1369  mSlaves[i]->ProcessFinalize();
1370  mSlaves.clear();
1371 
1372  mMasterIn.reset();
1373  mMasterOut.reset();
1374 
1375  return ProcessFinalize();
1376 }
1377 
1378 bool AudioUnitEffect::RealtimeSuspend()
1379 {
1380  return true;
1381 }
1382 
1383 bool AudioUnitEffect::RealtimeResume()
1384 {
1385  OSStatus result;
1386 
1387  result = AudioUnitReset(mUnit, kAudioUnitScope_Global, 0);
1388  if (result != noErr)
1389  {
1390  return false;
1391  }
1392 
1393  return true;
1394 }
1395 
1396 bool AudioUnitEffect::RealtimeProcessStart()
1397 {
1398  for (size_t i = 0; i < mAudioIns; i++)
1399  memset(mMasterIn[i].get(), 0, mBlockSize * sizeof(float));
1400 
1401  mNumSamples = 0;
1402 
1403  return true;
1404 }
1405 
1406 size_t AudioUnitEffect::RealtimeProcess(int group,
1407  float **inbuf,
1408  float **outbuf,
1409  size_t numSamples)
1410 {
1411  wxASSERT(numSamples <= mBlockSize);
1412 
1413  for (size_t c = 0; c < mAudioIns; c++)
1414  {
1415  for (decltype(numSamples) s = 0; s < numSamples; s++)
1416  {
1417  mMasterIn[c][s] += inbuf[c][s];
1418  }
1419  }
1420  mNumSamples = wxMax(numSamples, mNumSamples);
1421 
1422  return mSlaves[group]->ProcessBlock(inbuf, outbuf, numSamples);
1423 }
1424 
1425 bool AudioUnitEffect::RealtimeProcessEnd()
1426 {
1427  ProcessBlock(
1428  reinterpret_cast<float**>(mMasterIn.get()),
1429  reinterpret_cast<float**>(mMasterOut.get()),
1430  mNumSamples);
1431 
1432  return true;
1433 }
1434 
1435 bool AudioUnitEffect::ShowInterface(wxWindow *parent, bool forceModal)
1436 {
1437  if (mDialog)
1438  {
1439  if( mDialog->Close(true) )
1440  mDialog = nullptr;
1441  return false;
1442  }
1443 
1444  // mDialog is null
1445  auto cleanup = valueRestorer( mDialog );
1446 
1447  mDialog = mHost->CreateUI(parent, this);
1448  if (!mDialog)
1449  {
1450  return false;
1451  }
1452 
1453  if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal)
1454  {
1455  mDialog->Show();
1456  cleanup.release();
1457 
1458  return false;
1459  }
1460 
1461  bool res = mDialog->ShowModal() != 0;
1462 
1463  return res;
1464 }
1465 
1466 bool AudioUnitEffect::GetAutomationParameters(CommandParameters & parms)
1467 {
1468  OSStatus result;
1469  UInt32 dataSize;
1470  Boolean isWritable;
1471 
1472  result = AudioUnitGetPropertyInfo(mUnit,
1473  kAudioUnitProperty_ParameterList,
1474  kAudioUnitScope_Global,
1475  0,
1476  &dataSize,
1477  &isWritable);
1478  if (result != noErr)
1479  {
1480  return false;
1481  }
1482 
1483  UInt32 cnt = dataSize / sizeof(AudioUnitParameterID);
1484  ArrayOf<AudioUnitParameterID> array {cnt};
1485 
1486  result = AudioUnitGetProperty(mUnit,
1487  kAudioUnitProperty_ParameterList,
1488  kAudioUnitScope_Global,
1489  0,
1490  array.get(),
1491  &dataSize);
1492  if (result != noErr)
1493  {
1494  return false;
1495  }
1496 
1497  for (int i = 0; i < cnt; i++)
1498  {
1499  AudioUnitParameterInfoEx info;
1500  dataSize = sizeof(info);
1501  result = AudioUnitGetProperty(mUnit,
1502  kAudioUnitProperty_ParameterInfo,
1503  kAudioUnitScope_Global,
1504  array[i],
1505  &info,
1506  &dataSize);
1507  if (result != noErr)
1508  {
1509  return false;
1510  }
1511 
1512  wxString name;
1513  if (info.flags & kAudioUnitParameterFlag_HasCFNameString)
1514  {
1515  name = wxCFStringRef::AsString(info.cfNameString);
1516  }
1517 
1518  if (name.IsEmpty())
1519  {
1520  continue;
1521  }
1522 
1523  AudioUnitParameterValue value;
1524  result = AudioUnitGetParameter(mUnit,
1525  array[i],
1526  kAudioUnitScope_Global,
1527  0,
1528  &value);
1529  if (result != noErr)
1530  {
1531  return false;
1532  }
1533  parms.Write(name, value);
1534  }
1535 
1536  return true;
1537 }
1538 
1539 bool AudioUnitEffect::SetAutomationParameters(CommandParameters & parms)
1540 {
1541  OSStatus result;
1542  UInt32 dataSize;
1543  Boolean isWritable;
1544 
1545  result = AudioUnitGetPropertyInfo(mUnit,
1546  kAudioUnitProperty_ParameterList,
1547  kAudioUnitScope_Global,
1548  0,
1549  &dataSize,
1550  &isWritable);
1551  if (result != noErr)
1552  {
1553  return false;
1554  }
1555 
1556  UInt32 cnt = dataSize / sizeof(AudioUnitParameterID);
1557  ArrayOf<AudioUnitParameterID> array {cnt};
1558 
1559  result = AudioUnitGetProperty(mUnit,
1560  kAudioUnitProperty_ParameterList,
1561  kAudioUnitScope_Global,
1562  0,
1563  array.get(),
1564  &dataSize);
1565  if (result != noErr)
1566  {
1567  return false;
1568  }
1569 
1570  for (int i = 0; i < cnt; i++)
1571  {
1572  AudioUnitParameterInfoEx info;
1573  dataSize = sizeof(info);
1574  result = AudioUnitGetProperty(mUnit,
1575  kAudioUnitProperty_ParameterInfo,
1576  kAudioUnitScope_Global,
1577  array[i],
1578  &info,
1579  &dataSize);
1580  if (result != noErr)
1581  {
1582  return false;
1583  }
1584 
1585  wxString name;
1586  if (info.flags & kAudioUnitParameterFlag_HasCFNameString)
1587  {
1588  name = wxCFStringRef::AsString(info.cfNameString);
1589  }
1590 
1591  if (name.IsEmpty())
1592  {
1593  continue;
1594  }
1595 
1596 
1597  double d = 0.0;
1598  if (!parms.Read(name, &d))
1599  {
1600  return false;
1601  }
1602 
1603  AudioUnitParameterValue value = d;
1604  result = AudioUnitSetParameter(mUnit,
1605  array[i],
1606  kAudioUnitScope_Global,
1607  0,
1608  value,
1609  0);
1610  if (result != noErr)
1611  {
1612  return false;
1613  }
1614  }
1615 
1616  AudioUnitParameter aup;
1617  aup.mAudioUnit = mUnit;
1618  aup.mParameterID = kAUParameterListener_AnyParameter;
1619  aup.mScope = kAudioUnitScope_Global;
1620  aup.mElement = 0;
1621  AUParameterListenerNotify(NULL, NULL, &aup);
1622 
1623  return true;
1624 }
1625 
1626 bool AudioUnitEffect::LoadUserPreset(const wxString & name)
1627 {
1628  return LoadParameters(name);
1629 }
1630 
1631 bool AudioUnitEffect::SaveUserPreset(const wxString & name)
1632 {
1633  return SaveParameters(name);
1634 }
1635 
1636 bool AudioUnitEffect::LoadFactoryPreset(int id)
1637 {
1638  OSStatus result;
1639 
1640  // Retrieve the list of factory presets
1641  CFArrayRef array{};
1642  UInt32 dataSize = sizeof(CFArrayRef);
1643  result = AudioUnitGetProperty(mUnit,
1644  kAudioUnitProperty_FactoryPresets,
1645  kAudioUnitScope_Global,
1646  0,
1647  &array,
1648  &dataSize);
1649  CFunique_ptr < const __CFArray > uarray { array };
1650  if (result != noErr)
1651  {
1652  return false;
1653  }
1654 
1655  if (id < 0 || id >= CFArrayGetCount(array))
1656  {
1657  return false;
1658  }
1659 
1660  AUPreset *preset = (AUPreset *) CFArrayGetValueAtIndex(array, id);
1661 
1662  result = AudioUnitSetProperty(mUnit,
1663  kAudioUnitProperty_PresentPreset,
1664  kAudioUnitScope_Global,
1665  0,
1666  preset,
1667  sizeof(AUPreset));
1668  if (result == noErr)
1669  {
1670  AudioUnitParameter aup;
1671  aup.mAudioUnit = mUnit;
1672  aup.mParameterID = kAUParameterListener_AnyParameter;
1673  aup.mScope = kAudioUnitScope_Global;
1674  aup.mElement = 0;
1675  AUParameterListenerNotify(NULL, NULL, &aup);
1676  }
1677 
1678  return result == noErr;
1679 }
1680 
1681 bool AudioUnitEffect::LoadFactoryDefaults()
1682 {
1683  return LoadParameters(mHost->GetFactoryDefaultsGroup());
1684 }
1685 
1686 wxArrayString AudioUnitEffect::GetFactoryPresets()
1687 {
1688  OSStatus result;
1689  wxArrayString presets;
1690 
1691  // Retrieve the list of factory presets
1692  CFArrayRef array{};
1693  UInt32 dataSize = sizeof(CFArrayRef);
1694  result = AudioUnitGetProperty(mUnit,
1695  kAudioUnitProperty_FactoryPresets,
1696  kAudioUnitScope_Global,
1697  0,
1698  &array,
1699  &dataSize);
1700  CFunique_ptr< const __CFArray > uarray { array };
1701  if (result == noErr)
1702  {
1703  for (CFIndex i = 0, cnt = CFArrayGetCount(array); i < cnt; i++)
1704  {
1705  AUPreset *preset = (AUPreset *) CFArrayGetValueAtIndex(array, i);
1706  presets.Add(wxCFStringRef::AsString(preset->presetName));
1707  }
1708  }
1709 
1710  return presets;
1711 }
1712 
1713 // ============================================================================
1714 // EffectUIClientInterface Implementation
1715 // ============================================================================
1716 
1717 void AudioUnitEffect::SetHostUI(EffectUIHostInterface *host)
1718 {
1719  mUIHost = host;
1720 }
1721 
1722 bool AudioUnitEffect::PopulateUI(wxWindow *parent)
1723 {
1724  // OSStatus result;
1725 
1726  mDialog = static_cast<wxDialog *>(wxGetTopLevelParent(parent));
1727  mParent = parent;
1728 
1729  wxPanel *container;
1730  {
1731  auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
1732 
1733  wxASSERT(mParent); // To justify safenew
1734  container = safenew wxPanelWrapper(mParent, wxID_ANY);
1735  mainSizer->Add(container, 1, wxEXPAND);
1736 
1737  mParent->SetSizer(mainSizer.release());
1738  }
1739 
1740  if (mUIType == wxT("Plain"))
1741  {
1742  if (!CreatePlain(mParent))
1743  {
1744  return false;
1745  }
1746  }
1747  else
1748  {
1749  auto pControl = Destroy_ptr<AUControl>( safenew AUControl );
1750  if (!pControl)
1751  {
1752  return false;
1753  }
1754 
1755  if (!pControl->Create(container, mComponent, mUnit, mUIType == wxT("Full")))
1756  {
1757  return false;
1758  }
1759 
1760  {
1761  auto innerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
1762 
1763  innerSizer->Add((mpControl = pControl.release()), 1, wxEXPAND);
1764  container->SetSizer(innerSizer.release());
1765  }
1766 
1767  mParent->SetMinSize(wxDefaultSize);
1768 
1769 #ifdef __WXMAC__
1770 #ifdef __WX_EVTLOOP_BUSY_WAITING__
1771  wxEventLoop::SetBusyWaiting(true);
1772 #endif
1773 #endif
1774  }
1775 
1776  mParent->PushEventHandler(this);
1777 
1778  return true;
1779 }
1780 
1781 bool AudioUnitEffect::IsGraphicalUI()
1782 {
1783  return mUIType != wxT("Plain");
1784 }
1785 
1786 bool AudioUnitEffect::ValidateUI()
1787 {
1788 #if 0
1789  if (!mParent->Validate())
1790  {
1791  return false;
1792  }
1793 
1794  if (GetType() == EffectTypeGenerate)
1795  {
1796  mHost->SetDuration(mDuration->GetValue());
1797  }
1798 #endif
1799  return true;
1800 }
1801 
1802 bool AudioUnitEffect::CreatePlain(wxWindow *parent)
1803 {
1804  return false;
1805 }
1806 
1807 bool AudioUnitEffect::HideUI()
1808 {
1809 #if 0
1810  if (GetType() == EffectTypeAnalyze || mNumOutputControls > 0)
1811  {
1812  return false;
1813  }
1814 #endif
1815  return true;
1816 }
1817 
1818 bool AudioUnitEffect::CloseUI()
1819 {
1820 #ifdef __WXMAC__
1821 #ifdef __WX_EVTLOOP_BUSY_WAITING__
1822  wxEventLoop::SetBusyWaiting(false);
1823 #endif
1824  if (mpControl)
1825  mpControl->Close(), mpControl = nullptr;
1826 #endif
1827 
1828  mParent->RemoveEventHandler(this);
1829 
1830  mUIHost = NULL;
1831  mParent = NULL;
1832  mDialog = NULL;
1833 
1834  return true;
1835 }
1836 
1837 bool AudioUnitEffect::CanExportPresets()
1838 {
1839  return true;
1840 }
1841 
1842 void AudioUnitEffect::ExportPresets()
1843 {
1844  AudioUnitEffectExportDialog dlg(mDialog, this);
1845  dlg.ShowModal();
1846 }
1847 
1848 void AudioUnitEffect::ImportPresets()
1849 {
1850  AudioUnitEffectImportDialog dlg(mDialog, this);
1851  dlg.ShowModal();
1852 }
1853 
1854 bool AudioUnitEffect::HasOptions()
1855 {
1856  return true;
1857 }
1858 
1859 void AudioUnitEffect::ShowOptions()
1860 {
1861  AudioUnitEffectOptionsDialog dlg(mParent, mHost);
1862  if (dlg.ShowModal())
1863  {
1864  // Reinitialize configuration settings
1865  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
1866  mHost->GetSharedConfig(wxT("Options"), wxT("UIType"), mUIType, wxT("Full"));
1867 
1868  mUIType = wxGetTranslation(mUIType);
1869  }
1870 }
1871 
1872 // ============================================================================
1873 // AudioUnitEffect Implementation
1874 // ============================================================================
1875 
1876 bool AudioUnitEffect::LoadParameters(const wxString & group)
1877 {
1878  wxString parms;
1879  if (!mHost->GetPrivateConfig(group, wxT("Parameters"), parms, wxEmptyString))
1880  {
1881  return false;
1882  }
1883 
1884  CommandParameters eap;
1885  if (!eap.SetParameters(parms))
1886  {
1887  return false;
1888  }
1889 
1890  return SetAutomationParameters(eap);
1891 }
1892 
1893 bool AudioUnitEffect::SaveParameters(const wxString & group)
1894 {
1895  CommandParameters eap;
1896  if (!GetAutomationParameters(eap))
1897  {
1898  return false;
1899  }
1900 
1901  wxString parms;
1902  if (!eap.GetParameters(parms))
1903  {
1904  return false;
1905  }
1906 
1907  return mHost->SetPrivateConfig(group, wxT("Parameters"), parms);
1908 }
1909 
1910 bool AudioUnitEffect::SetRateAndChannels()
1911 {
1912  OSStatus result;
1913 
1914  if (mUnitInitialized)
1915  {
1916  AudioUnitUninitialize(mUnit);
1917 
1918  mUnitInitialized = false;
1919  }
1920 
1921  AudioStreamBasicDescription streamFormat {
1922  // Float64 mSampleRate;
1923  mSampleRate,
1924 
1925  // UInt32 mFormatID;
1926  kAudioFormatLinearPCM,
1927 
1928  // UInt32 mFormatFlags;
1929  (kAudioFormatFlagsNativeFloatPacked |
1930  kAudioFormatFlagIsNonInterleaved),
1931 
1932  // UInt32 mBytesPerPacket;
1933  sizeof(float),
1934 
1935  // UInt32 mFramesPerPacket;
1936  1,
1937 
1938  // UInt32 mBytesPerFrame;
1939  sizeof(float),
1940 
1941  // UInt32 mChannelsPerFrame;
1942  mAudioIns,
1943 
1944  // UInt32 mBitsPerChannel;
1945  sizeof(float) * 8,
1946 
1947  // UInt32 mReserved;
1948  0
1949  };
1950 
1951  result = AudioUnitSetProperty(mUnit,
1952  kAudioUnitProperty_SampleRate,
1953  kAudioUnitScope_Global,
1954  0,
1955  &mSampleRate,
1956  sizeof(Float64));
1957  if (result != noErr)
1958  {
1959  wxPrintf("%ls Didn't accept sample rate on global\n",
1960  // Exposing internal name only in debug printf
1961  GetSymbol().Internal().wx_str());
1962  return false;
1963  }
1964 
1965  if (mAudioIns > 0)
1966  {
1967  result = AudioUnitSetProperty(mUnit,
1968  kAudioUnitProperty_SampleRate,
1969  kAudioUnitScope_Input,
1970  0,
1971  &mSampleRate,
1972  sizeof(Float64));
1973  if (result != noErr)
1974  {
1975  wxPrintf("%ls Didn't accept sample rate on input\n",
1976  // Exposing internal name only in debug printf
1977  GetSymbol().Internal().wx_str());
1978  return false;
1979  }
1980 
1981  result = AudioUnitSetProperty(mUnit,
1982  kAudioUnitProperty_StreamFormat,
1983  kAudioUnitScope_Input,
1984  0,
1985  &streamFormat,
1986  sizeof(AudioStreamBasicDescription));
1987  if (result != noErr)
1988  {
1989  wxPrintf("%ls didn't accept stream format on input\n",
1990  // Exposing internal name only in debug printf
1991  GetSymbol().Internal().wx_str());
1992  return false;
1993  }
1994  }
1995 
1996  if (mAudioOuts > 0)
1997  {
1998  result = AudioUnitSetProperty(mUnit,
1999  kAudioUnitProperty_SampleRate,
2000  kAudioUnitScope_Output,
2001  0,
2002  &mSampleRate,
2003  sizeof(Float64));
2004  if (result != noErr)
2005  {
2006  wxPrintf("%ls Didn't accept sample rate on output\n",
2007  // Exposing internal name only in debug printf
2008  GetSymbol().Internal().wx_str());
2009  return false;
2010  }
2011 
2012  streamFormat.mChannelsPerFrame = mAudioOuts;
2013  result = AudioUnitSetProperty(mUnit,
2014  kAudioUnitProperty_StreamFormat,
2015  kAudioUnitScope_Output,
2016  0,
2017  &streamFormat,
2018  sizeof(AudioStreamBasicDescription));
2019 
2020  if (result != noErr)
2021  {
2022  wxPrintf("%ls didn't accept stream format on output\n",
2023  // Exposing internal name only in debug printf
2024  GetSymbol().Internal().wx_str());
2025  return false;
2026  }
2027  }
2028 
2029  result = AudioUnitInitialize(mUnit);
2030  if (result != noErr)
2031  {
2032  wxPrintf("Couldn't initialize audio unit\n");
2033  return false;
2034  }
2035 
2036  mUnitInitialized = true;
2037 
2038  return true;
2039 }
2040 
2041 bool AudioUnitEffect::CopyParameters(AudioUnit srcUnit, AudioUnit dstUnit)
2042 {
2043  OSStatus result;
2044  Float32 parameterValue;
2045  UInt32 size;
2046 
2047  // Get number of parameters by passing NULL in the data field and
2048  // getting back the size of the parameter list
2049 
2050  size = 0;
2051  result = AudioUnitGetProperty(srcUnit,
2052  kAudioUnitProperty_ParameterList,
2053  kAudioUnitScope_Global,
2054  0,
2055  NULL,
2056  &size);
2057  if (result != 0)
2058  {
2059  wxPrintf("Couldn't get number of parameters\n");
2060  return false;
2061  }
2062 
2063  // Now get the list of all parameter IDs
2064 
2065  auto numParameters = size / sizeof(AudioUnitParameterID);
2066  ArrayOf<AudioUnitParameterID> parameters{ numParameters };
2067  result = AudioUnitGetProperty(srcUnit,
2068  kAudioUnitProperty_ParameterList,
2069  kAudioUnitScope_Global,
2070  0,
2071  parameters.get(),
2072  &size);
2073  if (result != 0)
2074  {
2075  wxPrintf("Couldn't get parameter list\n");
2076  return false;
2077  }
2078 
2079  // Copy the parameters from the main unit to the unit specific to
2080  // this track
2081 
2082  for (unsigned i = 0; i < numParameters; i++)
2083  {
2084  result = AudioUnitGetParameter(srcUnit,
2085  parameters[i],
2086  kAudioUnitScope_Global,
2087  0,
2088  &parameterValue);
2089  if (result != 0)
2090  {
2091  wxPrintf("Couldn't get parameter %d: ID=%d\n", i, (int)parameters[i]);
2092  continue;
2093  }
2094 
2095  result = AudioUnitSetParameter(dstUnit,
2096  parameters[i],
2097  kAudioUnitScope_Global,
2098  0,
2099  parameterValue,
2100  0);
2101  if (result != 0)
2102  {
2103  wxPrintf("Couldn't set parameter %d: ID=%d\n", i, (int)parameters[i]);
2104  }
2105  }
2106 
2107  return true;
2108 }
2109 
2110 unsigned AudioUnitEffect::GetChannelCount()
2111 {
2112  return mNumChannels;
2113 }
2114 
2115 void AudioUnitEffect::SetChannelCount(unsigned numChannels)
2116 {
2117  mNumChannels = numChannels;
2118 }
2119 
2120 OSStatus AudioUnitEffect::Render(AudioUnitRenderActionFlags *inActionFlags,
2121  const AudioTimeStamp *inTimeStamp,
2122  UInt32 inBusNumber,
2123  UInt32 inNumFrames,
2124  AudioBufferList *ioData)
2125 {
2126  for (int i = 0; i < ioData->mNumberBuffers; i++)
2127  ioData->mBuffers[i].mData = mInputList[0].mBuffers[i].mData;
2128 
2129  return 0;
2130 }
2131 
2132 // static
2133 OSStatus AudioUnitEffect::RenderCallback(void *inRefCon,
2134  AudioUnitRenderActionFlags *inActionFlags,
2135  const AudioTimeStamp *inTimeStamp,
2136  UInt32 inBusNumber,
2137  UInt32 inNumFrames,
2138  AudioBufferList *ioData)
2139 {
2140  return ((AudioUnitEffect *) inRefCon)->Render(inActionFlags,
2141  inTimeStamp,
2142  inBusNumber,
2143  inNumFrames,
2144  ioData);
2145 }
2146 
2147 void AudioUnitEffect::EventListener(const AudioUnitEvent *inEvent,
2148  AudioUnitParameterValue inParameterValue)
2149 {
2150  // Handle property changes
2151  if (inEvent->mEventType == kAudioUnitEvent_PropertyChange)
2152  {
2153  // We're only registered for Latency changes
2154  if (inEvent->mArgument.mProperty.mPropertyID == kAudioUnitProperty_Latency)
2155  {
2156  // Allow change to be used
2157  //mLatencyDone = false;
2158  }
2159 
2160  return;
2161  }
2162 
2163  // Only parameter changes at this point
2164 
2165  if (mMaster)
2166  {
2167  // We're a slave, so just set the parameter
2168  AudioUnitSetParameter(mUnit,
2169  inEvent->mArgument.mParameter.mParameterID,
2170  kAudioUnitScope_Global,
2171  0,
2172  inParameterValue,
2173  0);
2174  }
2175  else
2176  {
2177  // We're the master, so propogate
2178  for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
2179  mSlaves[i]->EventListener(inEvent, inParameterValue);
2180  }
2181 }
2182 
2183 // static
2184 void AudioUnitEffect::EventListenerCallback(void *inCallbackRefCon,
2185  void *inObject,
2186  const AudioUnitEvent *inEvent,
2187  UInt64 inEventHostTime,
2188  AudioUnitParameterValue inParameterValue)
2189 {
2190  ((AudioUnitEffect *) inCallbackRefCon)->EventListener(inEvent,
2191  inParameterValue);
2192 }
2193 
2194 void AudioUnitEffect::GetChannelCounts()
2195 {
2196  Boolean isWritable = 0;
2197  UInt32 dataSize = 0;
2198  OSStatus result;
2199 
2200  // Does AU have channel info
2201  result = AudioUnitGetPropertyInfo(mUnit,
2202  kAudioUnitProperty_SupportedNumChannels,
2203  kAudioUnitScope_Global,
2204  0,
2205  &dataSize,
2206  &isWritable);
2207  if (result)
2208  {
2209  // None supplied. Apparently all FX type units can do any number of INs
2210  // and OUTs as long as they are the same number. In this case, we'll
2211  // just say stereo.
2212  //
2213  // We should probably check to make sure we're dealing with an FX type.
2214  mAudioIns = 2;
2215  mAudioOuts = 2;
2216  return;
2217  }
2218 
2219  ArrayOf<char> buffer{ dataSize };
2220  auto info = (AUChannelInfo *) buffer.get();
2221 
2222  // Retrieve the channel info
2223  result = AudioUnitGetProperty(mUnit,
2224  kAudioUnitProperty_SupportedNumChannels,
2225  kAudioUnitScope_Global,
2226  0,
2227  info,
2228  &dataSize);
2229  if (result)
2230  {
2231  // Oh well, not much we can do out this case
2232  mAudioIns = 2;
2233  mAudioOuts = 2;
2234 
2235  return;
2236  }
2237 
2238  // This is where it gets weird...not sure what is the best
2239  // way to do this really. If we knew how many ins/outs we
2240  // really needed, we could make a better choice.
2241 
2242  bool haven2m = false; // nothing -> mono
2243  bool haven2s = false; // nothing -> stereo
2244  bool havem2n = false; // mono -> nothing
2245  bool haves2n = false; // stereo -> nothing
2246  bool havem2m = false; // mono -> mono
2247  bool haves2s = false; // stereo -> stereo
2248  bool havem2s = false; // mono -> stereo
2249  bool haves2m = false; // stereo -> mono
2250 
2251  mAudioIns = 2;
2252  mAudioOuts = 2;
2253 
2254  // Look only for exact channel constraints
2255  for (int i = 0; i < dataSize / sizeof(AUChannelInfo); i++)
2256  {
2257  AUChannelInfo *ci = &info[i];
2258 
2259  int ic = ci->inChannels;
2260  int oc = ci->outChannels;
2261 
2262  if (ic < 0 && oc >= 0)
2263  {
2264  ic = 2;
2265  }
2266  else if (ic >= 0 && oc < 0)
2267  {
2268  oc = 2;
2269  }
2270  else if (ic < 0 && oc < 0)
2271  {
2272  ic = 2;
2273  oc = 2;
2274  }
2275 
2276  if (ic == 2 && oc == 2)
2277  {
2278  haves2s = true;
2279  }
2280  else if (ic == 1 && oc == 1)
2281  {
2282  havem2m = true;
2283  }
2284  else if (ic == 1 && oc == 2)
2285  {
2286  havem2s = true;
2287  }
2288  else if (ic == 2 && oc == 1)
2289  {
2290  haves2m = true;
2291  }
2292  else if (ic == 0 && oc == 2)
2293  {
2294  haven2s = true;
2295  }
2296  else if (ic == 0 && oc == 1)
2297  {
2298  haven2m = true;
2299  }
2300  else if (ic == 1 && oc == 0)
2301  {
2302  havem2n = true;
2303  }
2304  else if (ic == 2 && oc == 0)
2305  {
2306  haves2n = true;
2307  }
2308  }
2309 
2310  if (haves2s)
2311  {
2312  mAudioIns = 2;
2313  mAudioOuts = 2;
2314  }
2315  else if (havem2m)
2316  {
2317  mAudioIns = 1;
2318  mAudioOuts = 1;
2319  }
2320  else if (havem2s)
2321  {
2322  mAudioIns = 1;
2323  mAudioOuts = 2;
2324  }
2325  else if (haves2m)
2326  {
2327  mAudioIns = 2;
2328  mAudioOuts = 1;
2329  }
2330  else if (haven2m)
2331  {
2332  mAudioIns = 0;
2333  mAudioOuts = 1;
2334  }
2335  else if (haven2s)
2336  {
2337  mAudioIns = 0;
2338  mAudioOuts = 2;
2339  }
2340  else if (haves2n)
2341  {
2342  mAudioIns = 2;
2343  mAudioOuts = 0;
2344  }
2345  else if (havem2n)
2346  {
2347  mAudioIns = 1;
2348  mAudioOuts = 0;
2349  }
2350 
2351  return;
2352 }
2353 
2354 #endif
wxChoice * TieChoice(const wxString &Prompt, WrappedType &WrappedRef, const wxArrayString *pChoices)
#define DECLARE_BUILTIN_MODULE(name)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
const wxChar * desc
Definition: ExportPCM.cpp:58
Base class for many of the effects in Audacity.
Definition: Effect.h:62
#define XO(s)
Definition: Internat.h:33
Main class to control the export function.
#define safenew
Definition: Audacity.h:230
void EndHorizontalLay()
void EndVerticalLay()
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
wxListCtrl * AddListControlReportMode()
Definition: ShuttleGui.cpp:689
#define DECLARE_MODULE_ENTRY(name)
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the Shuttle cla...
void SetStyle(int Style)
Definition: ShuttleGui.h:287
bool GetParameters(wxString &parms)
IdentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
enum ChannelName * ChannelNames
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
bool SetParameters(const wxString &parms)
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
ValueRestorer< T > valueRestorer(T &var)
Definition: MemoryX.h:494
EffectHostInterface is a decorator of a EffectUIClientInterface. It adds virtual (abstract) functions...
EffectType
wxCheckBox * TieCheckBox(const wxString &Prompt, WrappedType &WrappedRef)
const wxChar * name
Definition: Distortion.cpp:94
Memory.h template class for making an array of float, bool, etc.
Definition: MemoryX.h:86
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:414
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:763
An Effect class that handles a wide range of effects. ??Mac only??
std::unique_ptr< T, Destroyer< T >> Destroy_ptr
Definition: MemoryX.h:433
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
END_EVENT_TABLE()
void SetBorder(int Border)
Definition: ShuttleGui.h:286
IdentInterface provides name / vendor / version functions to identify plugins. It is what makes a cla...
a wxControl with Cocoa/Carbon support
Definition: AUControl.h:37
EffectUIHostInterface has nothing in it. It is provided so that an Effect can call SetHostUI passing ...
void StartVerticalLay(int iProp=1)