Audacity  2.3.1
VSTEffect.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  VSTEffect.cpp
6 
7  Dominic Mazzoni
8 
9  This class implements a VST Plug-in effect. The plug-in must be
10  loaded in a platform-specific way and passed into the constructor,
11  but from here this class handles the interfacing.
12 
13 ********************************************************************//********************************************************************/
19 
20 //#define VST_DEBUG
21 //#define DEBUG_VST
22 
23 // *******************************************************************
24 // WARNING: This is NOT 64-bit safe
25 // *******************************************************************
26 
27 #include "../../Audacity.h"
28 
29 #if 0
30 #if defined(BUILDING_AUDACITY)
31 #include "../../Audacity.h"
32 #include "../../PlatformCompatibility.h"
33 
34 // Make the main function private
35 #define MODULEMAIN_SCOPE static
36 #else
37 #define MODULEMAIN_SCOPE
38 #define USE_VST 1
39 #endif
40 #endif
41 
42 #if USE_VST
43 
44 #include <limits.h>
45 #include <stdio.h>
46 
47 #include <wx/dynlib.h>
48 #include <wx/app.h>
49 #include <wx/defs.h>
50 #include <wx/buffer.h>
51 #include <wx/busyinfo.h>
52 #include <wx/button.h>
53 #include <wx/combobox.h>
54 #include <wx/dcclient.h>
55 #include <wx/file.h>
56 #include <wx/filename.h>
57 #include <wx/frame.h>
58 #include <wx/imaglist.h>
59 #include <wx/listctrl.h>
60 #include <wx/log.h>
61 #include <wx/module.h>
62 #include <wx/process.h>
63 #include <wx/progdlg.h>
64 #include <wx/recguard.h>
65 #include <wx/sizer.h>
66 #include <wx/slider.h>
67 #include <wx/scrolwin.h>
68 #include <wx/sstream.h>
69 #include <wx/statbox.h>
70 #include <wx/stattext.h>
71 #include <wx/timer.h>
72 #include <wx/tokenzr.h>
73 #include <wx/utils.h>
74 
75 #if defined(__WXMSW__)
76 #include <shlwapi.h>
77 #pragma comment(lib, "shlwapi")
78 #else
79 #include <dlfcn.h>
80 #endif
81 
82 // TODO: Unfortunately we have some dependencies on Audacity provided
83 // dialogs, widgets and other stuff. This will need to be cleaned up.
84 
85 #include "../../FileNames.h"
86 #include "../../Internat.h"
87 #include "../../PlatformCompatibility.h"
88 #include "../../ShuttleGui.h"
89 #include "../../effects/Effect.h"
90 #include "../../widgets/NumericTextCtrl.h"
91 #include "../../widgets/wxPanelWrapper.h"
92 #include "../../widgets/valnum.h"
93 #include "../../widgets/ErrorDialog.h"
94 #include "../../xml/XMLFileReader.h"
95 #include "../../xml/XMLWriter.h"
96 
97 #if wxUSE_ACCESSIBILITY
98 #include "../../widgets/WindowAccessible.h"
99 #endif
100 
102 
103 #include "VSTEffect.h"
104 #include "../../MemoryX.h"
105 #include <cstring>
106 
107 static float reinterpretAsFloat(uint32_t x)
108 {
109  static_assert(sizeof(float) == sizeof(uint32_t), "Cannot reinterpret uint32_t to float since sizes are different.");
110  float f;
111  std::memcpy(&f, &x, sizeof(float));
112  return f;
113 }
114 
115 static uint32_t reinterpretAsUint32(float f)
116 {
117  static_assert(sizeof(float) == sizeof(uint32_t), "Cannot reinterpret float to uint32_t since sizes are different.");
118 
119  uint32_t x;
120  std::memcpy(&x, &f, sizeof(uint32_t));
121  return x;
122 }
123 
124 // NOTE: To debug the subprocess, use wxLogDebug and, on Windows, Debugview
125 // from TechNet (Sysinternals).
126 
127 // ============================================================================
128 //
129 // Module registration entry point
130 //
131 // This is the symbol that Audacity looks for when the module is built as a
132 // dynamic library.
133 //
134 // When the module is builtin to Audacity, we use the same function, but it is
135 // declared static so as not to clash with other builtin modules.
136 //
137 // ============================================================================
138 DECLARE_MODULE_ENTRY(AudacityModule)
139 {
140  // Create our effects module and register
141  // Trust the module manager not to leak this
142  return safenew VSTEffectsModule(moduleManager, path);
143 }
144 
145 // ============================================================================
146 //
147 // Register this as a builtin module
148 //
149 // We also take advantage of the fact that wxModules are initialized before
150 // the wxApp::OnInit() method is called. We check to see if Audacity was
151 // executed to scan a VST effect in a different process.
152 //
153 // ============================================================================
154 DECLARE_BUILTIN_MODULE(VSTBuiltin);
155 
156 
162 class VSTSubEntry final : public wxModule
163 {
164 public:
165  bool OnInit()
166  {
167  // Have we been started to check a plugin?
168  if (wxTheApp && wxTheApp->argc == 3 && wxStrcmp(wxTheApp->argv[1], VSTCMDKEY) == 0)
169  {
170  // NOTE: This can really hide failures, which is what we want for those pesky
171  // VSTs that are bad or that our support isn't currect. But, it can also
172  // hide Audacity failures in the subprocess, so if you're having an unruley
173  // VST or odd Audacity failures, comment it out and you might get more info.
174  //wxHandleFatalExceptions();
175  VSTEffectsModule::Check(wxTheApp->argv[2]);
176 
177  // Returning false causes default processing to display a message box, but we don't
178  // want that so disable logging.
179  wxLog::EnableLogging(false);
180 
181  return false;
182  }
183 
184  return true;
185  };
186 
187  void OnExit() {};
188 
189  DECLARE_DYNAMIC_CLASS(VSTSubEntry)
190 };
192 
193 //----------------------------------------------------------------------------
194 // VSTSubProcess
195 //----------------------------------------------------------------------------
196 #define OUTPUTKEY wxT("<VSTLOADCHK>-")
198 {
210 };
211 
212 
218 class VSTSubProcess final : public wxProcess,
220 {
221 public:
223  {
224  Redirect();
225  }
226 
227  // EffectClientInterface implementation
228 
229  wxString GetPath() override
230  {
231  return mPath;
232  }
233 
235  {
236  return mName;
237  }
238 
240  {
241  return { mVendor };
242  }
243 
244  wxString GetVersion() override
245  {
246  return mVersion;
247  }
248 
249  wxString GetDescription() override
250  {
251  return mDescription;
252  }
253 
255  {
256  return VSTPLUGINTYPE;
257  }
258 
259  EffectType GetType() override
260  {
261  return mType;
262  }
263 
264  bool IsInteractive() override
265  {
266  return mInteractive;
267  }
268 
269  bool IsDefault() override
270  {
271  return false;
272  }
273 
274  bool IsLegacy() override
275  {
276  return false;
277  }
278 
279  bool SupportsRealtime() override
280  {
281  return mType == EffectTypeProcess;
282  }
283 
284  bool SupportsAutomation() override
285  {
286  return mAutomatable;
287  }
288 
289 public:
290  wxString mPath;
291  wxString mName;
292  wxString mVendor;
293  wxString mVersion;
294  wxString mDescription;
298 };
299 
300 // ============================================================================
301 //
302 // VSTEffectsModule
303 //
304 // ============================================================================
306  const wxString *path)
307 {
308  mModMan = moduleManager;
309  if (path)
310  {
311  mPath = *path;
312  }
313 }
314 
316 {
317  mPath = wxEmptyString;
318 }
319 
320 // ============================================================================
321 // ComponentInterface implementation
322 // ============================================================================
323 
325 {
326  return mPath;
327 }
328 
330 {
331  return XO("VST Effects");
332 }
333 
335 {
336  return XO("The Audacity Team");
337 }
338 
340 {
341  // This "may" be different if this were to be maintained as a separate DLL
343 }
344 
346 {
347  return _("Adds the ability to use VST effects in Audacity.");
348 }
349 
350 // ============================================================================
351 // ModuleInterface implementation
352 // ============================================================================
353 
355 {
356  // Nothing to do here
357  return true;
358 }
359 
361 {
362  // Nothing to do here
363  return;
364 }
365 
367 {
368  static const wxString ext[] = { _T("vst") };
369  static const wxArrayString result{ sizeof(ext)/sizeof(*ext), ext };
370  return result;
371 }
372 
374 {
375  // Not yet ready for VST drag-and-drop...
376  // return FileNames::PlugInDir();
377 
378  return {};
379 }
380 
382 {
383  // We don't auto-register
384  return true;
385 }
386 
388 {
389  wxArrayString pathList;
390  wxArrayString files;
391 
392  // Check for the VST_PATH environment variable
393  wxString vstpath = wxString::FromUTF8(getenv("VST_PATH"));
394  if (!vstpath.empty())
395  {
396  wxStringTokenizer tok(vstpath);
397  while (tok.HasMoreTokens())
398  {
399  pathList.Add(tok.GetNextToken());
400  }
401  }
402 
403 #if defined(__WXMAC__)
404 #define VSTPATH wxT("/Library/Audio/Plug-Ins/VST")
405 
406  // Look in ~/Library/Audio/Plug-Ins/VST and /Library/Audio/Plug-Ins/VST
407  pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + VSTPATH);
408  pathList.Add(VSTPATH);
409 
410  // Recursively search all paths for Info.plist files. This will identify all
411  // bundles.
412  pm.FindFilesInPathList(wxT("Info.plist"), pathList, files, true);
413 
414  // Remove the 'Contents/Info.plist' portion of the names
415  for (size_t i = 0; i < files.GetCount(); i++)
416  {
417  files[i] = wxPathOnly(wxPathOnly(files[i]));
418  if (!files[i].EndsWith(wxT(".vst")))
419  {
420  files.RemoveAt(i--);
421  }
422  }
423 
424 #elif defined(__WXMSW__)
425 
426  TCHAR dpath[MAX_PATH];
427  TCHAR tpath[MAX_PATH];
428  DWORD len;
429 
430  // Try HKEY_CURRENT_USER registry key first
431  len = WXSIZEOF(tpath);
432  if (SHRegGetUSValue(wxT("Software\\VST"),
433  wxT("VSTPluginsPath"),
434  NULL,
435  tpath,
436  &len,
437  FALSE,
438  NULL,
439  0) == ERROR_SUCCESS)
440  {
441  tpath[len] = 0;
442  dpath[0] = 0;
443  ExpandEnvironmentStrings(tpath, dpath, WXSIZEOF(dpath));
444  pathList.Add(dpath);
445  }
446 
447  // Then try HKEY_LOCAL_MACHINE registry key
448  len = WXSIZEOF(tpath);
449  if (SHRegGetUSValue(wxT("Software\\VST"),
450  wxT("VSTPluginsPath"),
451  NULL,
452  tpath,
453  &len,
454  TRUE,
455  NULL,
456  0) == ERROR_SUCCESS)
457  {
458  tpath[len] = 0;
459  dpath[0] = 0;
460  ExpandEnvironmentStrings(tpath, dpath, WXSIZEOF(dpath));
461  pathList.Add(dpath);
462  }
463 
464  // Add the default path last
465  dpath[0] = 0;
466  ExpandEnvironmentStrings(wxT("%ProgramFiles%\\Steinberg\\VSTPlugins"),
467  dpath,
468  WXSIZEOF(dpath));
469  pathList.Add(dpath);
470 
471  // Recursively scan for all DLLs
472  pm.FindFilesInPathList(wxT("*.dll"), pathList, files, true);
473 
474 #else
475 
476  // Nothing specified in the VST_PATH environment variable...provide defaults
477  if (vstpath.IsEmpty())
478  {
479  // We add this "non-default" one
480  pathList.Add(wxT(LIBDIR) wxT("/vst"));
481 
482  // These are the defaults used by other hosts
483  pathList.Add(wxT("/usr/lib/vst"));
484  pathList.Add(wxT("/usr/local/lib/vst"));
485  pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".vst"));
486  }
487 
488  // Recursively scan for all shared objects
489  pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
490 
491 #endif
492 
493  return files;
494 }
495 
497  const wxString & path, wxString &errMsg,
498  const RegistrationCallback &callback)
499 {
500  bool error = false;
501  unsigned nFound = 0;
502  errMsg.clear();
503  // TODO: Fix this for external usage
504  const wxString &cmdpath = PlatformCompatibility::GetExecutablePath();
505 
506  wxString effectIDs = wxT("0;");
507  wxStringTokenizer effectTzr(effectIDs, wxT(";"));
508 
509  Maybe<wxProgressDialog> progress{};
510  size_t idCnt = 0;
511  size_t idNdx = 0;
512 
513  bool cont = true;
514 
515  while (effectTzr.HasMoreTokens() && cont)
516  {
517  wxString effectID = effectTzr.GetNextToken();
518 
519  wxString cmd;
520  cmd.Printf(wxT("\"%s\" %s \"%s;%s\""), cmdpath, VSTCMDKEY, path, effectID);
521 
522  VSTSubProcess proc;
523  try
524  {
525  int flags = wxEXEC_SYNC | wxEXEC_NODISABLE;
526 #if defined(__WXMSW__)
527  flags += wxEXEC_NOHIDE;
528 #endif
529  wxExecute(cmd, flags, &proc);
530  }
531  catch (...)
532  {
533  wxLogMessage(_("VST plugin registration failed for %s\n"), path);
534  error = true;
535  }
536 
537  wxString output;
538  wxStringOutputStream ss(&output);
539  proc.GetInputStream()->Read(ss);
540 
541  int keycount = 0;
542  bool haveBegin = false;
543  wxStringTokenizer tzr(output, wxT("\n"));
544  while (tzr.HasMoreTokens())
545  {
546  wxString line = tzr.GetNextToken();
547 
548  // Our output may follow any output the plugin may have written.
549  if (!line.StartsWith(OUTPUTKEY))
550  {
551  continue;
552  }
553 
554  long key;
555  if (!line.Mid(wxStrlen(OUTPUTKEY)).BeforeFirst(wxT('=')).ToLong(&key))
556  {
557  continue;
558  }
559  wxString val = line.AfterFirst(wxT('=')).BeforeFirst(wxT('\r'));
560 
561  switch (key)
562  {
563  case kKeySubIDs:
564  effectIDs = val;
565  effectTzr.Reinit(effectIDs);
566  idCnt = effectTzr.CountTokens();
567  if (idCnt > 3)
568  {
569  progress.create( _("Scanning Shell VST"),
570  wxString::Format(_("Registering %d of %d: %-64.64s"), 0, idCnt,
571  proc.GetSymbol().Translation()),
572  static_cast<int>(idCnt),
573  nullptr,
574  wxPD_APP_MODAL |
575  wxPD_AUTO_HIDE |
576  wxPD_CAN_ABORT |
577  wxPD_ELAPSED_TIME |
578  wxPD_ESTIMATED_TIME |
579  wxPD_REMAINING_TIME );
580  progress->Show();
581  }
582  break;
583 
584  case kKeyBegin:
585  haveBegin = true;
586  keycount++;
587  break;
588 
589  case kKeyName:
590  proc.mName = val;
591  keycount++;
592  break;
593 
594  case kKeyPath:
595  proc.mPath = val;
596  keycount++;
597  break;
598 
599  case kKeyVendor:
600  proc.mVendor = val;
601  keycount++;
602  break;
603 
604  case kKeyVersion:
605  proc.mVersion = val;
606  keycount++;
607  break;
608 
609  case kKeyDescription:
610  proc.mDescription = val;
611  keycount++;
612  break;
613 
614  case kKeyEffectType:
615  long type;
616  val.ToLong(&type);
617  proc.mType = (EffectType) type;
618  keycount++;
619  break;
620 
621  case kKeyInteractive:
622  proc.mInteractive = val.IsSameAs(wxT("1"));
623  keycount++;
624  break;
625 
626  case kKeyAutomatable:
627  proc.mAutomatable = val.IsSameAs(wxT("1"));
628  keycount++;
629  break;
630 
631  case kKeyEnd:
632  {
633  if (!haveBegin || ++keycount != kKeyEnd)
634  {
635  keycount = 0;
636  haveBegin = false;
637  continue;
638  }
639 
640  bool skip = false;
641  if (progress)
642  {
643  idNdx++;
644  cont = progress->Update(idNdx,
645  wxString::Format(_("Registering %d of %d: %-64.64s"), idNdx, idCnt,
646  proc.GetSymbol().Translation() ));
647  }
648 
649  if (!skip && cont)
650  {
651  if (callback)
652  callback( this, &proc );
653  ++nFound;
654  }
655  }
656  break;
657 
658  default:
659  keycount = 0;
660  haveBegin = false;
661  break;
662  }
663  }
664  }
665 
666  if (error)
667  errMsg = _("Could not load the library");
668 
669  return nFound;
670 }
671 
672 bool VSTEffectsModule::IsPluginValid(const wxString & path, bool bFast)
673 {
674  if( bFast )
675  return true;
676  wxString realPath = path.BeforeFirst(wxT(';'));
677  return wxFileName::FileExists(realPath) || wxFileName::DirExists(realPath);
678 }
679 
681 {
682  // Acquires a resource for the application.
683  // For us, the ID is simply the path to the effect
684  // Safety of this depends on complementary calls to DeleteInstance on the module manager side.
685  return safenew VSTEffect(path);
686 }
687 
689 {
690  std::unique_ptr < VSTEffect > {
691  dynamic_cast<VSTEffect *>(instance)
692  };
693 }
694 
695 // ============================================================================
696 // ModuleEffectInterface implementation
697 // ============================================================================
698 
699 // ============================================================================
700 // VSTEffectsModule implementation
701 // ============================================================================
702 
703 // static
704 //
705 // Called from reinvokation of Audacity or DLL to check in a separate process
706 void VSTEffectsModule::Check(const wxChar *path)
707 {
708  VSTEffect effect(path);
709  if (effect.SetHost(NULL))
710  {
711  auto effectIDs = effect.GetEffectIDs();
712  wxString out;
713 
714  if (effectIDs.size() > 0)
715  {
716  wxString subids;
717 
718  for (size_t i = 0, cnt = effectIDs.size(); i < cnt; i++)
719  {
720  subids += wxString::Format(wxT("%d;"), effectIDs[i]);
721  }
722 
723  out = wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeySubIDs, subids.RemoveLast());
724  }
725  else
726  {
727  out += wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeyBegin, wxEmptyString);
728  out += wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeyPath, effect.GetPath());
729  out += wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeyName, effect.GetSymbol().Internal());
730  out += wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeyVendor,
731  effect.GetVendor().Internal());
732  out += wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeyVersion, effect.GetVersion());
733  out += wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeyDescription, effect.GetDescription());
734  out += wxString::Format(wxT("%s%d=%d\n"), OUTPUTKEY, kKeyEffectType, effect.GetType());
735  out += wxString::Format(wxT("%s%d=%d\n"), OUTPUTKEY, kKeyInteractive, effect.IsInteractive());
736  out += wxString::Format(wxT("%s%d=%d\n"), OUTPUTKEY, kKeyAutomatable, effect.SupportsAutomation());
737  out += wxString::Format(wxT("%s%d=%s\n"), OUTPUTKEY, kKeyEnd, wxEmptyString);
738  }
739 
740  // We want to output info in one chunk to prevent output
741  // from the effect intermixing with the info
742  const wxCharBuffer buf = out.ToUTF8();
743  fwrite(buf, 1, strlen(buf), stdout);
744  fflush(stdout);
745  }
746 }
747 
749 //
750 // Dialog for configuring latency, buffer size and graphics mode for a
751 // VST effect.
752 //
755 {
756 public:
757  VSTEffectOptionsDialog(wxWindow * parent, EffectHostInterface *host);
758  virtual ~VSTEffectOptionsDialog();
759 
760  void PopulateOrExchange(ShuttleGui & S);
761 
762  void OnOk(wxCommandEvent & evt);
763 
764 private:
768  bool mUseGUI;
769 
770  DECLARE_EVENT_TABLE()
771 };
772 
773 BEGIN_EVENT_TABLE(VSTEffectOptionsDialog, wxDialogWrapper)
774  EVT_BUTTON(wxID_OK, VSTEffectOptionsDialog::OnOk)
776 
778 : wxDialogWrapper(parent, wxID_ANY, wxString(_("VST Effect Options")))
779 {
780  mHost = host;
781 
782  mHost->GetSharedConfig(wxT("Options"), wxT("BufferSize"), mBufferSize, 8192);
783  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
784  mHost->GetSharedConfig(wxT("Options"), wxT("UseGUI"), mUseGUI, true);
785 
786  ShuttleGui S(this, eIsCreating);
787  PopulateOrExchange(S);
788 }
789 
791 {
792 }
793 
795 {
796  S.SetBorder(5);
797  S.StartHorizontalLay(wxEXPAND, 1);
798  {
799  S.StartVerticalLay(false);
800  {
801  S.StartStatic(_("Buffer Size"));
802  {
803  IntegerValidator<int> vld(&mBufferSize);
804  vld.SetRange(8, 1048576 * 1);
805 
806  S.AddVariableText(wxString() +
807  _("The buffer size controls the number of samples sent to the effect ") +
808  _("on each iteration. Smaller values will cause slower processing and ") +
809  _("some effects require 8192 samples or less to work properly. However ") +
810  _("most effects can accept large buffers and using them will greatly ") +
811  _("reduce processing time."))->Wrap(650);
812 
813  S.StartHorizontalLay(wxALIGN_LEFT);
814  {
815  wxTextCtrl *t;
816  t = S.TieNumericTextBox(_("&Buffer Size (8 to 1048576 samples):"),
817  mBufferSize,
818  12);
819  t->SetMinSize(wxSize(100, -1));
820  t->SetValidator(vld);
821  }
822  S.EndHorizontalLay();
823  }
824  S.EndStatic();
825 
826  S.StartStatic(_("Latency Compensation"));
827  {
828  S.AddVariableText(wxString() +
829  _("As part of their processing, some VST effects must delay returning ") +
830  _("audio to Audacity. When not compensating for this delay, you will ") +
831  _("notice that small silences have been inserted into the audio. ") +
832  _("Enabling this option will provide that compensation, but it may ") +
833  _("not work for all VST effects."))->Wrap(650);
834 
835  S.StartHorizontalLay(wxALIGN_LEFT);
836  {
837  S.TieCheckBox(_("Enable &compensation"),
838  mUseLatency);
839  }
840  S.EndHorizontalLay();
841  }
842  S.EndStatic();
843 
844  S.StartStatic(_("Graphical Mode"));
845  {
846  S.AddVariableText(wxString() +
847  _("Most VST effects have a graphical interface for setting parameter values.") +
848  _(" A basic text-only method is also available. ") +
849  _(" Reopen the effect for this to take effect."))->Wrap(650);
850  S.TieCheckBox(_("Enable &graphical interface"),
851  mUseGUI);
852  }
853  S.EndStatic();
854  }
855  S.EndVerticalLay();
856  }
857  S.EndHorizontalLay();
858 
859  S.AddStandardButtons();
860 
861  Layout();
862  Fit();
863  Center();
864 }
865 
866 void VSTEffectOptionsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
867 {
868  if (!Validate())
869  {
870  return;
871  }
872 
874  PopulateOrExchange(S);
875 
876  mHost->SetSharedConfig(wxT("Options"), wxT("BufferSize"), mBufferSize);
877  mHost->SetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency);
878  mHost->SetSharedConfig(wxT("Options"), wxT("UseGUI"), mUseGUI);
879 
880  EndModal(wxID_OK);
881 }
882 
890 class VSTEffectTimer final : public wxTimer
891 {
892 public:
894  : wxTimer(),
895  mEffect(effect)
896  {
897  }
898 
900  {
901  }
902 
903  void Notify()
904  {
905  mEffect->OnTimer();
906  }
907 
908 private:
910 };
911 
913 //
914 // VSTEffect
915 //
917 enum
918 {
919  ID_Duration = 20000,
920  ID_Sliders = 21000,
921 };
922 
923 DEFINE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW);
924 DEFINE_LOCAL_EVENT_TYPE(EVT_UPDATEDISPLAY);
925 
926 BEGIN_EVENT_TABLE(VSTEffect, wxEvtHandler)
927  EVT_COMMAND_RANGE(ID_Sliders, ID_Sliders + 999, wxEVT_COMMAND_SLIDER_UPDATED, VSTEffect::OnSlider)
928 
929  // Events from the audioMaster callback
930  EVT_COMMAND(wxID_ANY, EVT_SIZEWINDOW, VSTEffect::OnSizeWindow)
932 
933 // Needed to support shell plugins...sucks, but whatcha gonna do???
934 intptr_t VSTEffect::mCurrentEffectID;
935 
936 typedef AEffect *(*vstPluginMain)(audioMasterCallback audioMaster);
937 
938 intptr_t VSTEffect::AudioMaster(AEffect * effect,
939  int32_t opcode,
940  int32_t index,
941  intptr_t value,
942  void * ptr,
943  float opt)
944 {
945  VSTEffect *vst = (effect ? (VSTEffect *) effect->ptr2 : NULL);
946 
947  // Handles operations during initialization...before VSTEffect has had a
948  // chance to set its instance pointer.
949  switch (opcode)
950  {
951  case audioMasterVersion:
952  return (intptr_t) 2400;
953 
955  return mCurrentEffectID;
956 
958  strcpy((char *) ptr, "Audacity Team"); // Do not translate, max 64 + 1 for null terminator
959  return 1;
960 
962  strcpy((char *) ptr, "Audacity"); // Do not translate, max 64 + 1 for null terminator
963  return 1;
964 
966  return (intptr_t) (AUDACITY_VERSION << 24 |
967  AUDACITY_RELEASE << 16 |
968  AUDACITY_REVISION << 8 |
970 
971  // Some (older) effects depend on an effIdle call when requested. An
972  // example is the Antress Modern plugins which uses the call to update
973  // the editors display when the program (preset) changes.
974  case audioMasterNeedIdle:
975  if (vst)
976  {
977  vst->NeedIdle();
978  return 1;
979  }
980  return 0;
981 
982  // We would normally get this if the effect editor is dipslayed and something "major"
983  // has changed (like a program change) instead of multiple automation calls.
984  // Since we don't do anything with the parameters while the editor is displayed,
985  // there's no need for us to do anything.
987  if (vst)
988  {
989  vst->UpdateDisplay();
990  return 1;
991  }
992  return 0;
993 
994  // Return the current time info.
995  case audioMasterGetTime:
996  if (vst)
997  {
998  return (intptr_t) vst->GetTimeInfo();
999  }
1000  return 0;
1001 
1002  // Inputs, outputs, or initial delay has changed...all we care about is initial delay.
1003  case audioMasterIOChanged:
1004  if (vst)
1005  {
1006  vst->SetBufferDelay(effect->initialDelay);
1007  return 1;
1008  }
1009  return 0;
1010 
1012  if (vst)
1013  {
1014  return (intptr_t) vst->GetSampleRate();
1015  }
1016  return 0;
1017 
1018  case audioMasterIdle:
1019  wxYieldIfNeeded();
1020  return 1;
1021 
1023  if (vst)
1024  {
1025  return vst->GetProcessLevel();
1026  }
1027  return 0;
1028 
1030  return kVstLangEnglish;
1031 
1032  // We always replace, never accumulate
1034  return 1;
1035 
1036  // Resize the window to accommodate the effect size
1037  case audioMasterSizeWindow:
1038  if (vst)
1039  {
1040  vst->SizeWindow(index, value);
1041  }
1042  return 1;
1043 
1044  case audioMasterCanDo:
1045  {
1046  char *s = (char *) ptr;
1047  if (strcmp(s, "acceptIOChanges") == 0 ||
1048  strcmp(s, "sendVstTimeInfo") == 0 ||
1049  strcmp(s, "startStopProcess") == 0 ||
1050  strcmp(s, "shellCategory") == 0 ||
1051  strcmp(s, "sizeWindow") == 0)
1052  {
1053  return 1;
1054  }
1055 
1056 #if defined(VST_DEBUG)
1057 #if defined(__WXMSW__)
1058  wxLogDebug(wxT("VST canDo: %s"), wxString::FromAscii((char *)ptr));
1059 #else
1060  wxPrintf(wxT("VST canDo: %s\n"), wxString::FromAscii((char *)ptr));
1061 #endif
1062 #endif
1063 
1064  return 0;
1065  }
1066 
1067  case audioMasterBeginEdit:
1068  case audioMasterEndEdit:
1069  return 0;
1070 
1071  case audioMasterAutomate:
1072  if (vst)
1073  {
1074  vst->Automate(index, opt);
1075  }
1076  return 0;
1077 
1078  // We're always connected (sort of)
1080 
1081  // We don't do MIDI yet
1082  case audioMasterWantMidi:
1084 
1085  // Don't need to see any messages about these
1086  return 0;
1087  }
1088 
1089 #if defined(VST_DEBUG)
1090 #if defined(__WXMSW__)
1091  wxLogDebug(wxT("vst: %p opcode: %d index: %d value: %p ptr: %p opt: %f user: %p"),
1092  effect, (int) opcode, (int) index, (void *) value, ptr, opt, vst);
1093 #else
1094  wxPrintf(wxT("vst: %p opcode: %d index: %d value: %p ptr: %p opt: %f user: %p\n"),
1095  effect, (int) opcode, (int) index, (void *) value, ptr, opt, vst);
1096 #endif
1097 #endif
1098 
1099  return 0;
1100 }
1101 
1102 #if !defined(__WXMSW__)
1104 {
1105  if (p)
1106  dlclose(p);
1107 }
1108 #endif
1109 
1110 #if defined(__WXMAC__)
1111 void VSTEffect::BundleDeleter::operator() (void* p) const
1112 {
1113  if (p)
1114  CFRelease(static_cast<CFBundleRef>(p));
1115 }
1116 
1117 void VSTEffect::ResourceHandle::reset()
1118 {
1119  if (mpHandle)
1120  CFBundleCloseBundleResourceMap(mpHandle, mNum);
1121  mpHandle = nullptr;
1122  mNum = 0;
1123 }
1124 #endif
1125 
1126 VSTEffect::VSTEffect(const wxString & path, VSTEffect *master)
1127 : mPath(path),
1128  mMaster(master)
1129 {
1130  mHost = NULL;
1131  mModule = NULL;
1132  mAEffect = NULL;
1133  mDialog = NULL;
1134 
1135  mTimer = std::make_unique<VSTEffectTimer>(this);
1136  mTimerGuard = 0;
1137 
1138  mInteractive = false;
1139  mAudioIns = 0;
1140  mAudioOuts = 0;
1141  mMidiIns = 0;
1142  mMidiOuts = 0;
1143  mSampleRate = 44100;
1144  mBlockSize = mUserBlockSize = 8192;
1145  mBufferDelay = 0;
1146  mProcessLevel = 1; // in GUI thread
1147  mHasPower = false;
1148  mWantsIdle = false;
1149  mWantsEditIdle = false;
1150  mUseLatency = true;
1151  mReady = false;
1152 
1153  memset(&mTimeInfo, 0, sizeof(mTimeInfo));
1154  mTimeInfo.samplePos = 0.0;
1155  mTimeInfo.sampleRate = 44100.0; // this is a bogus value, but it's only for the display
1156  mTimeInfo.nanoSeconds = wxGetUTCTimeMillis().ToDouble();
1157  mTimeInfo.tempo = 120.0;
1161 
1162  // UI
1163 
1164  mGui = false;
1165  mContainer = NULL;
1166 
1167  // If we're a slave then go ahead a load immediately
1168  if (mMaster)
1169  {
1170  Load();
1171  }
1172 }
1173 
1175 {
1176  if (mDialog)
1177  {
1178  mDialog->Close();
1179  }
1180 
1181  Unload();
1182 }
1183 
1184 // ============================================================================
1185 // ComponentInterface Implementation
1186 // ============================================================================
1187 
1189 {
1190  return mPath;
1191 }
1192 
1194 {
1195  return mName;
1196 }
1197 
1199 {
1200  return { mVendor };
1201 }
1202 
1204 {
1205  wxString version;
1206 
1207  bool skipping = true;
1208  for (int i = 0, s = 0; i < 4; i++, s += 8)
1209  {
1210  int dig = (mVersion >> s) & 0xff;
1211  if (dig != 0 || !skipping)
1212  {
1213  version += !skipping ? wxT(".") : wxT("");
1214  version += wxString::Format(wxT("%d"), dig);
1215  skipping = false;
1216  }
1217  }
1218 
1219  return version;
1220 }
1221 
1223 {
1224  // VST does have a product string opcode and some effects return a short
1225  // description, but most do not or they just return the name again. So,
1226  // try to provide some sort of useful information.
1227  return wxString::Format( _("Audio In: %d, Audio Out: %d"),
1229 }
1230 
1231 // ============================================================================
1232 // EffectDefinitionInterface Implementation
1233 // ============================================================================
1234 
1236 {
1237  if (mAudioIns == 0 && mAudioOuts == 0 && mMidiIns == 0 && mMidiOuts == 0)
1238  {
1239  return EffectTypeTool;
1240  }
1241 
1242  if (mAudioIns == 0 && mMidiIns == 0)
1243  {
1244  return EffectTypeGenerate;
1245  }
1246 
1247  if (mAudioOuts == 0 && mMidiOuts == 0)
1248  {
1249  return EffectTypeAnalyze;
1250  }
1251 
1252  return EffectTypeProcess;
1253 }
1254 
1255 
1257 {
1258  return VSTPLUGINTYPE;
1259 }
1260 
1262 {
1263  return mInteractive;
1264 }
1265 
1267 {
1268  return false;
1269 }
1270 
1272 {
1273  return false;
1274 }
1275 
1277 {
1278  return GetType() == EffectTypeProcess;
1279 }
1280 
1282 {
1283  return mAutomatable;
1284 }
1285 
1286 // ============================================================================
1287 // EffectClientInterface Implementation
1288 // ============================================================================
1289 
1291 {
1292  mHost = host;
1293 
1294  if (!mAEffect)
1295  {
1296  Load();
1297  }
1298 
1299  if (!mAEffect)
1300  {
1301  return false;
1302  }
1303 
1304  // If we have a master then there's no need to load settings since the master will feed
1305  // us everything we need.
1306  if (mMaster)
1307  {
1308  return true;
1309  }
1310 
1311  if (mHost)
1312  {
1313  int userBlockSize;
1314  mHost->GetSharedConfig(wxT("Options"), wxT("BufferSize"), userBlockSize, 8192);
1315  mUserBlockSize = std::max( 1, userBlockSize );
1316  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
1317 
1319 
1320  bool haveDefaults;
1321  mHost->GetPrivateConfig(mHost->GetFactoryDefaultsGroup(), wxT("Initialized"), haveDefaults, false);
1322  if (!haveDefaults)
1323  {
1325  mHost->SetPrivateConfig(mHost->GetFactoryDefaultsGroup(), wxT("Initialized"), true);
1326  }
1327 
1329  }
1330 
1331  return true;
1332 }
1333 
1335 {
1336  return mAudioIns;
1337 }
1338 
1340 {
1341  return mAudioOuts;
1342 }
1343 
1345 {
1346  return mMidiIns;
1347 }
1348 
1350 {
1351  return mMidiOuts;
1352 }
1353 
1354 size_t VSTEffect::SetBlockSize(size_t maxBlockSize)
1355 {
1356  mBlockSize = std::min( maxBlockSize, mUserBlockSize );
1357  return mBlockSize;
1358 }
1359 
1360 void VSTEffect::SetSampleRate(double rate)
1361 {
1362  mSampleRate = (float) rate;
1363 }
1364 
1366 {
1367  if (mUseLatency)
1368  {
1369  // ??? Threading issue ???
1370  auto delay = mBufferDelay;
1371  mBufferDelay = 0;
1372  return delay;
1373  }
1374 
1375  return 0;
1376 }
1377 
1379 {
1380  return 0;
1381 }
1382 
1384 {
1385  return mReady;
1386 }
1387 
1388 bool VSTEffect::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
1389 {
1390  // Initialize time info
1391  memset(&mTimeInfo, 0, sizeof(mTimeInfo));
1393  mTimeInfo.nanoSeconds = wxGetUTCTimeMillis().ToDouble();
1394  mTimeInfo.tempo = 120.0;
1398 
1399  // Set processing parameters...power must be off for this
1401  callDispatcher(effSetBlockSize, 0, mBlockSize, NULL, 0.0);
1402 
1403  // Turn on the power
1404  PowerOn();
1405 
1406  // Set the initial buffer delay
1408 
1409  mReady = true;
1410 
1411  return true;
1412 }
1413 
1415 {
1416  mReady = false;
1417 
1418  PowerOff();
1419 
1420  return true;
1421 }
1422 
1423 size_t VSTEffect::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
1424 {
1425  // Only call the effect if there's something to do...some do not like zero-length block
1426  if (blockLen)
1427  {
1428  // Go let the plugin moleste the samples
1429  callProcessReplacing(inBlock, outBlock, blockLen);
1430 
1431  // And track the position
1432  mTimeInfo.samplePos += ((double) blockLen / mTimeInfo.sampleRate);
1433  }
1434 
1435  return blockLen;
1436 }
1437 
1439 {
1440  return mNumChannels;
1441 }
1442 
1443 void VSTEffect::SetChannelCount(unsigned numChannels)
1444 {
1445  mNumChannels = numChannels;
1446 }
1447 
1449 {
1452 
1453  return ProcessInitialize(0, NULL);
1454 }
1455 
1456 bool VSTEffect::RealtimeAddProcessor(unsigned numChannels, float sampleRate)
1457 {
1458  mSlaves.push_back(std::make_unique<VSTEffect>(mPath, this));
1459  VSTEffect *const slave = mSlaves.back().get();
1460 
1461  slave->SetBlockSize(mBlockSize);
1462  slave->SetChannelCount(numChannels);
1463  slave->SetSampleRate(sampleRate);
1464 
1465  int clen = 0;
1467  {
1468  void *chunk = NULL;
1469 
1470  clen = (int) callDispatcher(effGetChunk, 1, 0, &chunk, 0.0); // get master's chunk, for the program only
1471  if (clen != 0)
1472  {
1473  slave->callSetChunk(true, clen, chunk); // copy state to slave, for the program only
1474  }
1475  }
1476 
1477  if (clen == 0)
1478  {
1479  callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
1480 
1481  for (int i = 0; i < mAEffect->numParams; i++)
1482  {
1483  slave->callSetParameter(i, callGetParameter(i));
1484  }
1485 
1486  callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
1487  }
1488 
1489  return slave->ProcessInitialize(0, NULL);
1490 }
1491 
1493 {
1494  for (const auto &slave : mSlaves)
1495  slave->ProcessFinalize();
1496  mSlaves.clear();
1497 
1498  mMasterIn.reset();
1499 
1500  mMasterOut.reset();
1501 
1502  return ProcessFinalize();
1503 }
1504 
1506 {
1507  PowerOff();
1508 
1509  for (const auto &slave : mSlaves)
1510  slave->PowerOff();
1511 
1512  return true;
1513 }
1514 
1516 {
1517  PowerOn();
1518 
1519  for (const auto &slave : mSlaves)
1520  slave->PowerOn();
1521 
1522  return true;
1523 }
1524 
1526 {
1527  for (unsigned int i = 0; i < mAudioIns; i++)
1528  memset(mMasterIn[i].get(), 0, mBlockSize * sizeof(float));
1529 
1530  mNumSamples = 0;
1531 
1532  return true;
1533 }
1534 
1535 size_t VSTEffect::RealtimeProcess(int group, float **inbuf, float **outbuf, size_t numSamples)
1536 {
1537  wxASSERT(numSamples <= mBlockSize);
1538 
1539  for (unsigned int c = 0; c < mAudioIns; c++)
1540  {
1541  for (decltype(numSamples) s = 0; s < numSamples; s++)
1542  {
1543  mMasterIn[c][s] += inbuf[c][s];
1544  }
1545  }
1546  mNumSamples = std::max(numSamples, mNumSamples);
1547 
1548  return mSlaves[group]->ProcessBlock(inbuf, outbuf, numSamples);
1549 }
1550 
1552 {
1553  // These casts to float** should be safe...
1554  ProcessBlock(
1555  reinterpret_cast <float**> (mMasterIn.get()),
1556  reinterpret_cast <float**> (mMasterOut.get()),
1557  mNumSamples);
1558 
1559  return true;
1560 }
1561 
1588 bool VSTEffect::ShowInterface(wxWindow *parent, bool forceModal)
1589 {
1590  if (mDialog)
1591  {
1592  if ( mDialog->Close(true) )
1593  mDialog = nullptr;
1594  return false;
1595  }
1596 
1597  // mDialog is null
1598  auto cleanup = valueRestorer( mDialog );
1599 
1600  // mProcessLevel = 1; // in GUI thread
1601 
1602  // Set some defaults since some VSTs need them...these will be reset when
1603  // normal or realtime processing begins
1604  if (!IsReady())
1605  {
1606  mSampleRate = 44100;
1607  mBlockSize = 8192;
1608  ProcessInitialize(0, NULL);
1609  }
1610 
1611  mDialog = mHost->CreateUI(parent, this);
1612  if (!mDialog)
1613  {
1614  return false;
1615  }
1616  mDialog->CentreOnParent();
1617 
1618  if (SupportsRealtime() && !forceModal)
1619  {
1620  mDialog->Show();
1621  cleanup.release();
1622 
1623  return false;
1624  }
1625 
1626  bool res = mDialog->ShowModal() != 0;
1627 
1628  return res;
1629 }
1630 
1632 {
1633  for (int i = 0; i < mAEffect->numParams; i++)
1634  {
1635  wxString name = GetString(effGetParamName, i);
1636  if (name.IsEmpty())
1637  {
1638  name.Printf(wxT("parm_%d"), i);
1639  }
1640 
1641  float value = callGetParameter(i);
1642  if (!parms.Write(name, value))
1643  {
1644  return false;
1645  }
1646  }
1647 
1648  return true;
1649 }
1650 
1652 {
1653  callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
1654  for (int i = 0; i < mAEffect->numParams; i++)
1655  {
1656  wxString name = GetString(effGetParamName, i);
1657  if (name.IsEmpty())
1658  {
1659  name.Printf(wxT("parm_%d"), i);
1660  }
1661 
1662  double d = 0.0;
1663  if (!parms.Read(name, &d))
1664  {
1665  return false;
1666  }
1667 
1668  if (d >= -1.0 && d <= 1.0)
1669  {
1670  callSetParameter(i, d);
1671  for (const auto &slave : mSlaves)
1672  slave->callSetParameter(i, d);
1673  }
1674  }
1675  callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
1676 
1677  return true;
1678 }
1679 
1680 
1681 bool VSTEffect::LoadUserPreset(const wxString & name)
1682 {
1683  if (!LoadParameters(name))
1684  {
1685  return false;
1686  }
1687 
1689 
1690  return true;
1691 }
1692 
1693 bool VSTEffect::SaveUserPreset(const wxString & name)
1694 {
1695  return SaveParameters(name);
1696 }
1697 
1699 {
1700  wxArrayString progs;
1701 
1702  // Some plugins, like Guitar Rig 5, only report 128 programs while they have hundreds. While
1703  // I was able to come up with a hack in the Guitar Rig case to gather all of the program names
1704  // it would not let me set a program outside of the first 128.
1705  if (mVstVersion >= 2)
1706  {
1707  for (int i = 0; i < mAEffect->numPrograms; i++)
1708  {
1709  progs.Add(GetString(effGetProgramNameIndexed, i));
1710  }
1711  }
1712 
1713  return progs;
1714 }
1715 
1717 {
1718  callSetProgram(id);
1719 
1721 
1722  return true;
1723 }
1724 
1726 {
1728  {
1729  return false;
1730  }
1731 
1733 
1734  return true;
1735 }
1736 
1737 // ============================================================================
1738 // EffectUIClientInterface implementation
1739 // ============================================================================
1740 
1742 {
1743  mUIHost = host;
1744 }
1745 
1746 bool VSTEffect::PopulateUI(wxWindow *parent)
1747 {
1748  mDialog = static_cast<wxDialog *>(wxGetTopLevelParent(parent));
1749  mParent = parent;
1750 
1751  mParent->PushEventHandler(this);
1752 
1753  // Determine if the VST editor is supposed to be used or not
1754  mHost->GetSharedConfig(wxT("Options"),
1755  wxT("UseGUI"),
1756  mGui,
1757  true);
1758  mGui = mAEffect->flags & effFlagsHasEditor ? mGui : false;
1759 
1760  // Must use the GUI editor if parameters aren't provided
1761  if (mAEffect->numParams == 0)
1762  {
1763  mGui = true;
1764  }
1765 
1766  // Build the appropriate dialog type
1767  if (mGui)
1768  {
1769  BuildFancy();
1770  }
1771  else
1772  {
1773  BuildPlain();
1774  }
1775 
1776  return true;
1777 }
1778 
1780 {
1781  return mGui;
1782 }
1783 
1785 {
1786  if (!mParent->Validate() || !mParent->TransferDataFromWindow())
1787  {
1788  return false;
1789  }
1790 
1791  if (GetType() == EffectTypeGenerate)
1792  {
1794  }
1795 
1796  return true;
1797 }
1798 
1800 {
1801  return true;
1802 }
1803 
1805 {
1806 #ifdef __WXMAC__
1807 #ifdef __WX_EVTLOOP_BUSY_WAITING__
1808  wxEventLoop::SetBusyWaiting(false);
1809 #endif
1810  mControl->Close();
1811 #endif
1812 
1813  mParent->RemoveEventHandler(this);
1814 
1815  PowerOff();
1816 
1817  NeedEditIdle(false);
1818 
1819  RemoveHandler();
1820 
1821  mNames.reset();
1822  mSliders.reset();
1823  mDisplays.reset();
1824  mLabels.reset();
1825 
1826  mUIHost = NULL;
1827  mParent = NULL;
1828  mDialog = NULL;
1829 
1830  return true;
1831 }
1832 
1834 {
1835  return true;
1836 }
1837 
1838 // Throws exceptions rather than reporting errors.
1840 {
1841  wxString path;
1842 
1843  // Ask the user for the real name
1844  //
1845  // Passing a valid parent will cause some effects dialogs to malfunction
1846  // upon returning from the FileNames::SelectFile().
1848  _("Save VST Preset As:"),
1850  wxEmptyString,
1851  wxT("xml"),
1852  wxT("Standard VST bank file (*.fxb)|*.fxb|Standard VST program file (*.fxp)|*.fxp|Audacity VST preset file (*.xml)|*.xml"),
1853  wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
1854  NULL);
1855 
1856  // User canceled...
1857  if (path.IsEmpty())
1858  {
1859  return;
1860  }
1861 
1862  wxFileName fn(path);
1863  wxString ext = fn.GetExt();
1864  if (ext.CmpNoCase(wxT("fxb")) == 0)
1865  {
1866  SaveFXB(fn);
1867  }
1868  else if (ext.CmpNoCase(wxT("fxp")) == 0)
1869  {
1870  SaveFXP(fn);
1871  }
1872  else if (ext.CmpNoCase(wxT("xml")) == 0)
1873  {
1874  // may throw
1875  SaveXML(fn);
1876  }
1877  else
1878  {
1879  // This shouldn't happen, but complain anyway
1880  AudacityMessageBox(_("Unrecognized file extension."),
1881  _("Error Saving VST Presets"),
1882  wxOK | wxCENTRE,
1883  mParent);
1884 
1885  return;
1886  }
1887 }
1888 
1889 //
1890 // Load an "fxb", "fxp" or Audacuty "xml" file
1891 //
1892 // Based on work by Sven Giermann
1893 //
1895 {
1896  wxString path;
1897 
1898  // Ask the user for the real name
1900  _("Load VST Preset:"),
1902  wxEmptyString,
1903  wxT("xml"),
1904  wxT("VST preset files (*.fxb; *.fxp; *.xml)|*.fxb;*.fxp;*.xml"),
1905  wxFD_OPEN | wxRESIZE_BORDER,
1906  mParent);
1907 
1908  // User canceled...
1909  if (path.IsEmpty())
1910  {
1911  return;
1912  }
1913 
1914  wxFileName fn(path);
1915  wxString ext = fn.GetExt();
1916  bool success = false;
1917  if (ext.CmpNoCase(wxT("fxb")) == 0)
1918  {
1919  success = LoadFXB(fn);
1920  }
1921  else if (ext.CmpNoCase(wxT("fxp")) == 0)
1922  {
1923  success = LoadFXP(fn);
1924  }
1925  else if (ext.CmpNoCase(wxT("xml")) == 0)
1926  {
1927  success = LoadXML(fn);
1928  }
1929  else
1930  {
1931  // This shouldn't happen, but complain anyway
1932  AudacityMessageBox(_("Unrecognized file extension."),
1933  _("Error Loading VST Presets"),
1934  wxOK | wxCENTRE,
1935  mParent);
1936 
1937  return;
1938  }
1939 
1940  if (!success)
1941  {
1942  AudacityMessageBox(_("Unable to load presets file."),
1943  _("Error Loading VST Presets"),
1944  wxOK | wxCENTRE,
1945  mParent);
1946 
1947  return;
1948  }
1949 
1951 
1952  return;
1953 }
1954 
1956 {
1957  return true;
1958 }
1959 
1961 {
1963  if (dlg.ShowModal())
1964  {
1965  // Reinitialize configuration settings
1966  int userBlockSize;
1967  mHost->GetSharedConfig(wxT("Options"), wxT("BufferSize"), userBlockSize, 8192);
1968  mUserBlockSize = std::max( 1, userBlockSize );
1969  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
1970  }
1971 }
1972 
1973 // ============================================================================
1974 // VSTEffect implementation
1975 // ============================================================================
1976 
1978 {
1979  vstPluginMain pluginMain;
1980  bool success = false;
1981 
1982  long effectID = 0;
1983  wxString realPath = mPath.BeforeFirst(wxT(';'));
1984  mPath.AfterFirst(wxT(';')).ToLong(&effectID);
1985  mCurrentEffectID = (intptr_t) effectID;
1986 
1987  mModule = NULL;
1988  mAEffect = NULL;
1989 
1990 #if defined(__WXMAC__)
1991  // Start clean
1992  mBundleRef.reset();
1993 
1994  mResource = ResourceHandle{};
1995 
1996  // Convert the path to a CFSTring
1997  wxCFStringRef path(realPath);
1998 
1999  // Convert the path to a URL
2000  CFURLRef urlRef =
2001  CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
2002  path,
2003  kCFURLPOSIXPathStyle,
2004  true);
2005  if (urlRef == NULL)
2006  {
2007  return false;
2008  }
2009 
2010  // Create the bundle using the URL
2011  BundleHandle bundleRef{ CFBundleCreate(kCFAllocatorDefault, urlRef) };
2012 
2013  // Done with the URL
2014  CFRelease(urlRef);
2015 
2016  // Bail if the bundle wasn't created
2017  if (!bundleRef)
2018  {
2019  return false;
2020  }
2021 
2022  // Retrieve a reference to the executable
2023  CFURLRef exeRef = CFBundleCopyExecutableURL(bundleRef.get());
2024  if (!exeRef)
2025  return false;
2026 
2027  // Convert back to path
2028  UInt8 exePath[PLATFORM_MAX_PATH];
2029  Boolean good = CFURLGetFileSystemRepresentation(exeRef, true, exePath, sizeof(exePath));
2030 
2031  // Done with the executable reference
2032  CFRelease(exeRef);
2033 
2034  // Bail if we couldn't resolve the executable path
2035  if (good == FALSE)
2036  return false;
2037 
2038  // Attempt to open it
2039  mModule.reset((char*)dlopen((char *) exePath, RTLD_NOW | RTLD_LOCAL));
2040  if (!mModule)
2041  return false;
2042 
2043  // Try to locate the NEW plugin entry point
2044  pluginMain = (vstPluginMain) dlsym(mModule.get(), "VSTPluginMain");
2045 
2046  // If not found, try finding the old entry point
2047  if (pluginMain == NULL)
2048  {
2049  pluginMain = (vstPluginMain) dlsym(mModule.get(), "main_macho");
2050  }
2051 
2052  // Must not be a VST plugin
2053  if (pluginMain == NULL)
2054  {
2055  mModule.reset();
2056  return false;
2057  }
2058 
2059  // Need to keep the bundle reference around so we can map the
2060  // resources.
2061  mBundleRef = std::move(bundleRef);
2062 
2063  // Open the resource map ... some plugins (like GRM Tools) need this.
2064  mResource = ResourceHandle{
2065  mBundleRef.get(), CFBundleOpenBundleResourceMap(mBundleRef.get())
2066  };
2067 
2068 #elif defined(__WXMSW__)
2069 
2070  {
2071  wxLogNull nolog;
2072 
2073  // Try to load the library
2074  auto lib = std::make_unique<wxDynamicLibrary>(realPath);
2075  if (!lib)
2076  return false;
2077 
2078  // Bail if it wasn't successful
2079  if (!lib->IsLoaded())
2080  return false;
2081 
2082  // Try to find the entry point, while suppressing error messages
2083  pluginMain = (vstPluginMain) lib->GetSymbol(wxT("VSTPluginMain"));
2084  if (pluginMain == NULL)
2085  {
2086  pluginMain = (vstPluginMain) lib->GetSymbol(wxT("main"));
2087  if (pluginMain == NULL)
2088  return false;
2089  }
2090 
2091  // Save the library reference
2092  mModule = std::move(lib);
2093  }
2094 
2095 #else
2096 
2097  // Attempt to load it
2098  //
2099  // Spent a few days trying to figure out why some VSTs where running okay and
2100  // others were hit or miss. The cause was that we export all of Audacity's
2101  // symbols and some of the loaded libraries were picking up Audacity's and
2102  // not their own.
2103  //
2104  // So far, I've only seen this issue on Linux, but we might just be getting
2105  // lucky on the Mac and Windows. The sooner we stop exporting everything
2106  // the better.
2107  //
2108  // To get around the problem, I just added the RTLD_DEEPBIND flag to the load
2109  // and that "basically" puts Audacity last when the loader needs to resolve
2110  // symbols.
2111  //
2112  // Once we define a proper external API, the flags can be removed.
2113 #ifndef RTLD_DEEPBIND
2114 #define RTLD_DEEPBIND 0
2115 #endif
2116  ModuleHandle lib {
2117  (char*) dlopen((const char *)wxString(realPath).ToUTF8(),
2118  RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND)
2119  };
2120  if (!lib)
2121  {
2122  return false;
2123  }
2124 
2125  // Try to find the entry point, while suppressing error messages
2126  pluginMain = (vstPluginMain) dlsym(lib.get(), "VSTPluginMain");
2127  if (pluginMain == NULL)
2128  {
2129  pluginMain = (vstPluginMain) dlsym(lib.get(), "main");
2130  if (pluginMain == NULL)
2131  return false;
2132  }
2133 
2134  // Save the library reference
2135  mModule = std::move(lib);
2136 
2137 #endif
2138 
2139  // Initialize the plugin
2140  try
2141  {
2142  mAEffect = pluginMain(VSTEffect::AudioMaster);
2143  }
2144  catch (...)
2145  {
2146  wxLogMessage(_("VST plugin initialization failed\n"));
2147  mAEffect = NULL;
2148  }
2149 
2150  // Was it successful?
2151  if (mAEffect)
2152  {
2153  // Save a reference to ourselves
2154  //
2155  // Note: Some hosts use "user" and some use "ptr2/resvd2". It might
2156  // be worthwhile to check if user is NULL before using it and
2157  // then falling back to "ptr2/resvd2".
2158  mAEffect->ptr2 = this;
2159 
2160  // Give the plugin an initial sample rate and blocksize
2161  callDispatcher(effSetSampleRate, 0, 0, NULL, 48000.0);
2162  callDispatcher(effSetBlockSize, 0, 512, NULL, 0);
2163 
2164  // Ask the plugin to identify itself...might be needed for older plugins
2165  callDispatcher(effIdentify, 0, 0, NULL, 0);
2166 
2167  // Open the plugin
2168  callDispatcher(effOpen, 0, 0, NULL, 0.0);
2169 
2170  // Get the VST version the plugin understands
2171  mVstVersion = callDispatcher(effGetVstVersion, 0, 0, NULL, 0);
2172 
2173  // Set it again in case plugin ignored it before the effOpen
2174  callDispatcher(effSetSampleRate, 0, 0, NULL, 48000.0);
2175  callDispatcher(effSetBlockSize, 0, 512, NULL, 0);
2176 
2177  // Ensure that it looks like a plugin and can deal with ProcessReplacing
2178  // calls. Also exclude synths for now.
2179  if (mAEffect->magic == kEffectMagic &&
2180  !(mAEffect->flags & effFlagsIsSynth) &&
2182  {
2183  if (mVstVersion >= 2)
2184  {
2186  if (mName.length() == 0)
2187  {
2189  }
2190  }
2191  if (mName.length() == 0)
2192  {
2193  mName = wxFileName{realPath}.GetName();
2194  }
2195 
2196  if (mVstVersion >= 2)
2197  {
2199  mVersion = wxINT32_SWAP_ON_LE(callDispatcher(effGetVendorVersion, 0, 0, NULL, 0));
2200  }
2201  if (mVersion == 0)
2202  {
2203  mVersion = wxINT32_SWAP_ON_LE(mAEffect->version);
2204  }
2205 
2207  {
2208  mInteractive = true;
2209  }
2210 
2213 
2214  mMidiIns = 0;
2215  mMidiOuts = 0;
2216 
2217  // Check to see if parameters can be automated. This isn't a gaurantee
2218  // since it could be that the effect simply doesn't support the opcode.
2219  mAutomatable = false;
2220  for (int i = 0; i < mAEffect->numParams; i++)
2221  {
2222  if (callDispatcher(effCanBeAutomated, 0, i, NULL, 0.0))
2223  {
2224  mAutomatable = true;
2225  break;
2226  }
2227  }
2228 
2229  // Make sure we start out with a valid program selection
2230  // I've found one plugin (SoundHack +morphfilter) that will
2231  // crash Audacity when saving the initial default parameters
2232  // with this.
2233  callSetProgram(0);
2234 
2235  // Pretty confident that we're good to go
2236  success = true;
2237  }
2238  }
2239 
2240  if (!success)
2241  {
2242  Unload();
2243  }
2244 
2245  return success;
2246 }
2247 
2249 {
2250  if (mDialog)
2251  {
2252  CloseUI();
2253  }
2254 
2255  if (mAEffect)
2256  {
2257  // Turn the power off
2258  PowerOff();
2259 
2260  // Finally, close the plugin
2261  callDispatcher(effClose, 0, 0, NULL, 0.0);
2262  mAEffect = NULL;
2263  }
2264 
2265  if (mModule)
2266  {
2267 #if defined(__WXMAC__)
2268  mResource.reset();
2269  mBundleRef.reset();
2270 #endif
2271 
2272  mModule.reset();
2273  mAEffect = NULL;
2274  }
2275 }
2276 
2277 std::vector<int> VSTEffect::GetEffectIDs()
2278 {
2279  std::vector<int> effectIDs;
2280 
2281  // Are we a shell?
2283  {
2284  char name[64];
2285  int effectID;
2286 
2287  effectID = (int) callDispatcher(effShellGetNextPlugin, 0, 0, &name, 0);
2288  while (effectID)
2289  {
2290  effectIDs.push_back(effectID);
2291  effectID = (int) callDispatcher(effShellGetNextPlugin, 0, 0, &name, 0);
2292  }
2293  }
2294 
2295  return effectIDs;
2296 }
2297 
2298 bool VSTEffect::LoadParameters(const wxString & group)
2299 {
2300  wxString value;
2301 
2303  mHost->GetPrivateConfig(group, wxT("UniqueID"), info.pluginUniqueID, info.pluginUniqueID);
2304  mHost->GetPrivateConfig(group, wxT("Version"), info.pluginVersion, info.pluginVersion);
2305  mHost->GetPrivateConfig(group, wxT("Elements"), info.numElements, info.numElements);
2306 
2307  if ((info.pluginUniqueID != mAEffect->uniqueID) ||
2308  (info.pluginVersion != mAEffect->version) ||
2309  (info.numElements != mAEffect->numParams))
2310  {
2311  return false;
2312  }
2313 
2314  if (mHost->GetPrivateConfig(group, wxT("Chunk"), value, wxEmptyString))
2315  {
2316  ArrayOf<char> buf{ value.length() / 4 * 3 };
2317 
2318  int len = VSTEffect::b64decode(value, buf.get());
2319  if (len)
2320  {
2321  callSetChunk(true, len, buf.get(), &info);
2322  }
2323 
2324  return true;
2325  }
2326 
2327  wxString parms;
2328  if (!mHost->GetPrivateConfig(group, wxT("Parameters"), parms, wxEmptyString))
2329  {
2330  return false;
2331  }
2332 
2333  CommandParameters eap;
2334  if (!eap.SetParameters(parms))
2335  {
2336  return false;
2337  }
2338 
2339  return SetAutomationParameters(eap);
2340 }
2341 
2342 bool VSTEffect::SaveParameters(const wxString & group)
2343 {
2344  mHost->SetPrivateConfig(group, wxT("UniqueID"), mAEffect->uniqueID);
2345  mHost->SetPrivateConfig(group, wxT("Version"), mAEffect->version);
2346  mHost->SetPrivateConfig(group, wxT("Elements"), mAEffect->numParams);
2347 
2349  {
2350  void *chunk = NULL;
2351  int clen = (int) callDispatcher(effGetChunk, 1, 0, &chunk, 0.0);
2352  if (clen <= 0)
2353  {
2354  return false;
2355  }
2356 
2357  mHost->SetPrivateConfig(group, wxT("Chunk"), VSTEffect::b64encode(chunk, clen));
2358  return true;
2359  }
2360 
2361  CommandParameters eap;
2362  if (!GetAutomationParameters(eap))
2363  {
2364  return false;
2365  }
2366 
2367  wxString parms;
2368  if (!eap.GetParameters(parms))
2369  {
2370  return false;
2371  }
2372 
2373  return mHost->SetPrivateConfig(group, wxT("Parameters"), parms);
2374 }
2375 
2377 {
2378  wxRecursionGuard guard(mTimerGuard);
2379 
2380  // Ignore it if we're recursing
2381  if (guard.IsInside())
2382  {
2383  return;
2384  }
2385 
2386  if (mVstVersion >= 2 && mWantsIdle)
2387  {
2388  int ret = callDispatcher(effIdle, 0, 0, NULL, 0.0);
2389  if (!ret)
2390  {
2391  mWantsIdle = false;
2392  }
2393  }
2394 
2395  if (mWantsEditIdle)
2396  {
2397  callDispatcher(effEditIdle, 0, 0, NULL, 0.0);
2398  }
2399 }
2400 
2402 {
2403  mWantsIdle = true;
2404  mTimer->Start(100);
2405 }
2406 
2407 void VSTEffect::NeedEditIdle(bool state)
2408 {
2409  mWantsEditIdle = state;
2410  mTimer->Start(100);
2411 }
2412 
2414 {
2415  mTimeInfo.nanoSeconds = wxGetUTCTimeMillis().ToDouble();
2416  return &mTimeInfo;
2417 }
2418 
2420 {
2421  return mTimeInfo.sampleRate;
2422 }
2423 
2425 {
2426  return mProcessLevel;
2427 }
2428 
2430 {
2431  if (!mHasPower)
2432  {
2433  // Turn the power on
2434  callDispatcher(effMainsChanged, 0, 1, NULL, 0.0);
2435 
2436  // Tell the effect we're going to start processing
2437  if (mVstVersion >= 2)
2438  {
2439  callDispatcher(effStartProcess, 0, 0, NULL, 0.0);
2440  }
2441 
2442  // Set state
2443  mHasPower = true;
2444  }
2445 }
2446 
2448 {
2449  if (mHasPower)
2450  {
2451  // Tell the effect we're going to stop processing
2452  if (mVstVersion >= 2)
2453  {
2454  callDispatcher(effStopProcess, 0, 0, NULL, 0.0);
2455  }
2456 
2457  // Turn the power off
2458  callDispatcher(effMainsChanged, 0, 0, NULL, 0.0);
2459 
2460  // Set state
2461  mHasPower = false;
2462  }
2463 }
2464 
2465 void VSTEffect::SizeWindow(int w, int h)
2466 {
2467  // Queue the event to make the resizes smoother
2468  if (mParent)
2469  {
2470  wxCommandEvent sw(EVT_SIZEWINDOW);
2471  sw.SetInt(w);
2472  sw.SetExtraLong(h);
2473  mParent->GetEventHandler()->AddPendingEvent(sw);
2474  }
2475 
2476  return;
2477 }
2478 
2480 {
2481 #if 0
2482  // Tell the dialog to refresh effect information
2483  if (mParent)
2484  {
2485  wxCommandEvent ud(EVT_UPDATEDISPLAY);
2486  mParent->GetEventHandler()->AddPendingEvent(ud);
2487  }
2488 #endif
2489  return;
2490 }
2491 
2492 void VSTEffect::Automate(int index, float value)
2493 {
2494  // Just ignore it if we're a slave
2495  if (mMaster)
2496  {
2497  return;
2498  }
2499 
2500  for (const auto &slave : mSlaves)
2501  slave->callSetParameter(index, value);
2502 
2503  return;
2504 }
2505 
2506 void VSTEffect::SetBufferDelay(int samples)
2507 {
2508  // We do not support negative delay
2509  if (samples >= 0 && mUseLatency)
2510  {
2511  mBufferDelay = samples;
2512  }
2513 
2514  return;
2515 }
2516 
2517 int VSTEffect::GetString(wxString & outstr, int opcode, int index)
2518 {
2519  char buf[256];
2520 
2521  memset(buf, 0, sizeof(buf));
2522 
2523  callDispatcher(opcode, index, 0, buf, 0.0);
2524 
2525  outstr = wxString::FromUTF8(buf);
2526 
2527  return 0;
2528 }
2529 
2530 wxString VSTEffect::GetString(int opcode, int index)
2531 {
2532  wxString str;
2533 
2534  GetString(str, opcode, index);
2535 
2536  return str;
2537 }
2538 
2539 void VSTEffect::SetString(int opcode, const wxString & str, int index)
2540 {
2541  char buf[256];
2542  strcpy(buf, str.Left(255).ToUTF8());
2543 
2544  callDispatcher(opcode, index, 0, buf, 0.0);
2545 }
2546 
2547 intptr_t VSTEffect::callDispatcher(int opcode,
2548  int index, intptr_t value, void *ptr, float opt)
2549 {
2550  // Needed since we might be in the dispatcher when the timer pops
2551  wxCRIT_SECT_LOCKER(locker, mDispatcherLock);
2552  return mAEffect->dispatcher(mAEffect, opcode, index, value, ptr, opt);
2553 }
2554 
2556  float **outputs, int sampleframes)
2557 {
2558  mAEffect->processReplacing(mAEffect, inputs, outputs, sampleframes);
2559 }
2560 
2562 {
2563  return mAEffect->getParameter(mAEffect, index);
2564 }
2565 
2566 void VSTEffect::callSetParameter(int index, float value)
2567 {
2568  if (mVstVersion == 0 || callDispatcher(effCanBeAutomated, 0, index, NULL, 0.0))
2569  {
2570  mAEffect->setParameter(mAEffect, index, value);
2571 
2572  for (const auto &slave : mSlaves)
2573  slave->callSetParameter(index, value);
2574  }
2575 }
2576 
2578 {
2579  callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
2580 
2581  callDispatcher(effSetProgram, 0, index, NULL, 0.0);
2582  for (const auto &slave : mSlaves)
2583  slave->callSetProgram(index);
2584 
2585  callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
2586 }
2587 
2588 void VSTEffect::callSetChunk(bool isPgm, int len, void *buf)
2589 {
2590  VstPatchChunkInfo info;
2591 
2592  memset(&info, 0, sizeof(info));
2593  info.version = 1;
2595  info.pluginVersion = mAEffect->version;
2596  info.numElements = isPgm ? mAEffect->numParams : mAEffect->numPrograms;
2597 
2598  callSetChunk(isPgm, len, buf, &info);
2599 }
2600 
2601 void VSTEffect::callSetChunk(bool isPgm, int len, void *buf, VstPatchChunkInfo *info)
2602 {
2603  if (isPgm)
2604  {
2605  // Ask the effect if this is an acceptable program
2606  if (callDispatcher(effBeginLoadProgram, 0, 0, info, 0.0) == -1)
2607  {
2608  return;
2609  }
2610  }
2611  else
2612  {
2613  // Ask the effect if this is an acceptable bank
2614  if (callDispatcher(effBeginLoadBank, 0, 0, info, 0.0) == -1)
2615  {
2616  return;
2617  }
2618  }
2619 
2620  callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
2621  callDispatcher(effSetChunk, isPgm ? 1 : 0, len, buf, 0.0);
2622  callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
2623 
2624  for (const auto &slave : mSlaves)
2625  slave->callSetChunk(isPgm, len, buf, info);
2626 }
2627 
2629 // Base64 en/decoding
2630 //
2631 // Original routines marked as public domain and found at:
2632 //
2633 // http://en.wikibooks.org/wiki/Algorithm_implementation/Miscellaneous/Base64
2634 //
2636 
2637 // Lookup table for encoding
2638 const static wxChar cset[] = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
2639 const static char padc = wxT('=');
2640 
2641 wxString VSTEffect::b64encode(const void *in, int len)
2642 {
2643  unsigned char *p = (unsigned char *) in;
2644  wxString out;
2645 
2646  unsigned long temp;
2647  for (int i = 0; i < len / 3; i++)
2648  {
2649  temp = (*p++) << 16; //Convert to big endian
2650  temp += (*p++) << 8;
2651  temp += (*p++);
2652  out += cset[(temp & 0x00FC0000) >> 18];
2653  out += cset[(temp & 0x0003F000) >> 12];
2654  out += cset[(temp & 0x00000FC0) >> 6];
2655  out += cset[(temp & 0x0000003F)];
2656  }
2657 
2658  switch (len % 3)
2659  {
2660  case 1:
2661  temp = (*p++) << 16; //Convert to big endian
2662  out += cset[(temp & 0x00FC0000) >> 18];
2663  out += cset[(temp & 0x0003F000) >> 12];
2664  out += padc;
2665  out += padc;
2666  break;
2667 
2668  case 2:
2669  temp = (*p++) << 16; //Convert to big endian
2670  temp += (*p++) << 8;
2671  out += cset[(temp & 0x00FC0000) >> 18];
2672  out += cset[(temp & 0x0003F000) >> 12];
2673  out += cset[(temp & 0x00000FC0) >> 6];
2674  out += padc;
2675  break;
2676  }
2677 
2678  return out;
2679 }
2680 
2681 int VSTEffect::b64decode(const wxString &in, void *out)
2682 {
2683  int len = in.length();
2684  unsigned char *p = (unsigned char *) out;
2685 
2686  if (len % 4) //Sanity check
2687  {
2688  return 0;
2689  }
2690 
2691  int padding = 0;
2692  if (len)
2693  {
2694  if (in[len - 1] == padc)
2695  {
2696  padding++;
2697  }
2698 
2699  if (in[len - 2] == padc)
2700  {
2701  padding++;
2702  }
2703  }
2704 
2705  //const char *a = in.mb_str();
2706  //Setup a vector to hold the result
2707  unsigned long temp = 0; //Holds decoded quanta
2708  int i = 0;
2709  while (i < len)
2710  {
2711  for (int quantumPosition = 0; quantumPosition < 4; quantumPosition++)
2712  {
2713  unsigned char c = in[i];
2714  temp <<= 6;
2715 
2716  if (c >= 0x41 && c <= 0x5A)
2717  {
2718  temp |= c - 0x41;
2719  }
2720  else if (c >= 0x61 && c <= 0x7A)
2721  {
2722  temp |= c - 0x47;
2723  }
2724  else if (c >= 0x30 && c <= 0x39)
2725  {
2726  temp |= c + 0x04;
2727  }
2728  else if (c == 0x2B)
2729  {
2730  temp |= 0x3E;
2731  }
2732  else if (c == 0x2F)
2733  {
2734  temp |= 0x3F;
2735  }
2736  else if (c == padc)
2737  {
2738  switch (len - i)
2739  {
2740  case 1: //One pad character
2741  *p++ = (temp >> 16) & 0x000000FF;
2742  *p++ = (temp >> 8) & 0x000000FF;
2743  return p - (unsigned char *) out;
2744  case 2: //Two pad characters
2745  *p++ = (temp >> 10) & 0x000000FF;
2746  return p - (unsigned char *) out;
2747  }
2748  }
2749  i++;
2750  }
2751  *p++ = (temp >> 16) & 0x000000FF;
2752  *p++ = (temp >> 8) & 0x000000FF;
2753  *p++ = temp & 0x000000FF;
2754  }
2755 
2756  return p - (unsigned char *) out;
2757 }
2758 
2760 {
2761 }
2762 
2763 static void OnSize(wxSizeEvent & evt)
2764 {
2765  evt.Skip();
2766 
2767  // Once the parent dialog reaches its final size as indicated by
2768  // a non-default minimum size, we set the maximum size to match.
2769  // This is a bit of a hack to prevent VSTs GUI windows from resizing
2770  // there's no real reason to allow it. But, there should be a better
2771  // way of handling it.
2772  wxWindow *w = (wxWindow *) evt.GetEventObject();
2773  wxSize sz = w->GetMinSize();
2774 
2775  if (sz != wxDefaultSize)
2776  {
2777  w->SetMaxSize(sz);
2778  }
2779 }
2780 
2782 {
2783  // Turn the power on...some effects need this when the editor is open
2784  PowerOn();
2785 
2786  auto control = Destroy_ptr<VSTControl>{ safenew VSTControl };
2787  if (!control)
2788  {
2789  return;
2790  }
2791 
2792  if (!control->Create(mParent, this))
2793  {
2794  return;
2795  }
2796 
2797  {
2798  auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
2799 
2800  mainSizer->Add((mControl = control.release()), 0, wxALIGN_CENTER);
2801 
2802  mParent->SetMinSize(wxDefaultSize);
2803  mParent->SetSizer(mainSizer.release());
2804  }
2805 
2806  NeedEditIdle(true);
2807 
2808  mDialog->Bind(wxEVT_SIZE, OnSize);
2809 
2810 #ifdef __WXMAC__
2811 #ifdef __WX_EVTLOOP_BUSY_WAITING__
2812  wxEventLoop::SetBusyWaiting(true);
2813 #endif
2814 #endif
2815 
2816  return;
2817 }
2818 
2820 {
2821  wxASSERT(mParent); // To justify safenew
2822  wxScrolledWindow *const scroller = safenew wxScrolledWindow(mParent,
2823  wxID_ANY,
2824  wxDefaultPosition,
2825  wxDefaultSize,
2826  wxVSCROLL | wxTAB_TRAVERSAL);
2827 
2828  {
2829  auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
2830 
2831  // Try to give the window a sensible default/minimum size
2832  scroller->SetMinSize(wxSize(wxMax(600, mParent->GetSize().GetWidth() * 2 / 3),
2833  mParent->GetSize().GetHeight() / 2));
2834  scroller->SetScrollRate(0, 20);
2835 
2836  // This fools NVDA into not saying "Panel" when the dialog gets focus
2837  scroller->SetName(wxT("\a"));
2838  scroller->SetLabel(wxT("\a"));
2839 
2840  mainSizer->Add(scroller, 1, wxEXPAND | wxALL, 5);
2841  mParent->SetSizer(mainSizer.release());
2842  }
2843 
2844  mNames.reinit(static_cast<size_t>(mAEffect->numParams));
2845  mSliders.reinit(static_cast<size_t>(mAEffect->numParams));
2846  mDisplays.reinit(static_cast<size_t>(mAEffect->numParams));
2847  mLabels.reinit(static_cast<size_t>(mAEffect->numParams));
2848 
2849  {
2850  auto paramSizer = std::make_unique<wxStaticBoxSizer>(wxVERTICAL, scroller, _("Effect Settings"));
2851 
2852  {
2853  auto gridSizer = std::make_unique<wxFlexGridSizer>(4, 0, 0);
2854  gridSizer->AddGrowableCol(1);
2855 
2856  // Add the duration control for generators
2857  if (GetType() == EffectTypeGenerate)
2858  {
2859  wxControl *item = safenew wxStaticText(scroller, 0, _("Duration:"));
2860  gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
2861  mDuration = safenew
2862  NumericTextCtrl(scroller, ID_Duration,
2865  mHost->GetDuration(),
2866  mSampleRate,
2868  .AutoPos(true));
2869  mDuration->SetName(_("Duration"));
2870  gridSizer->Add(mDuration, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
2871  gridSizer->Add(1, 1, 0);
2872  gridSizer->Add(1, 1, 0);
2873  }
2874 
2875  // Find the longest parameter name.
2876  int namew = 0;
2877  int w;
2878  int h;
2879  for (int i = 0; i < mAEffect->numParams; i++)
2880  {
2881  wxString text = GetString(effGetParamName, i);
2882 
2883  if (text.Right(1) != wxT(':'))
2884  {
2885  text += wxT(':');
2886  }
2887 
2888  scroller->GetTextExtent(text, &w, &h);
2889  if (w > namew)
2890  {
2891  namew = w;
2892  }
2893  }
2894 
2895  scroller->GetTextExtent(wxT("HHHHHHHH"), &w, &h);
2896 
2897  for (int i = 0; i < mAEffect->numParams; i++)
2898  {
2899  mNames[i] = safenew wxStaticText(scroller,
2900  wxID_ANY,
2901  wxEmptyString,
2902  wxDefaultPosition,
2903  wxSize(namew, -1),
2904  wxALIGN_RIGHT | wxST_NO_AUTORESIZE);
2905  gridSizer->Add(mNames[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
2906 
2907  mSliders[i] = safenew wxSlider(scroller,
2908  ID_Sliders + i,
2909  0,
2910  0,
2911  1000,
2912  wxDefaultPosition,
2913  wxSize(200, -1));
2914  gridSizer->Add(mSliders[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);
2915 #if wxUSE_ACCESSIBILITY
2916  // so that name can be set on a standard control
2917  mSliders[i]->SetAccessible(safenew WindowAccessible(mSliders[i]));
2918 #endif
2919 
2920  mDisplays[i] = safenew wxStaticText(scroller,
2921  wxID_ANY,
2922  wxEmptyString,
2923  wxDefaultPosition,
2924  wxSize(w, -1),
2925  wxALIGN_RIGHT | wxST_NO_AUTORESIZE);
2926  gridSizer->Add(mDisplays[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
2927 
2928  mLabels[i] = safenew wxStaticText(scroller,
2929  wxID_ANY,
2930  wxEmptyString,
2931  wxDefaultPosition,
2932  wxSize(w, -1),
2933  wxALIGN_LEFT | wxST_NO_AUTORESIZE);
2934  gridSizer->Add(mLabels[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5);
2935  }
2936 
2937  paramSizer->Add(gridSizer.release(), 1, wxEXPAND | wxALL, 5);
2938  }
2939  scroller->SetSizer(paramSizer.release());
2940  }
2941 
2943 
2944  mSliders[0]->SetFocus();
2945 }
2946 
2948 {
2949  if (!mNames)
2950  {
2951  return;
2952  }
2953 
2954  for (int i = 0; i < mAEffect->numParams; i++)
2955  {
2956  wxString text = GetString(effGetParamName, i);
2957 
2958  text = text.Trim(true).Trim(false);
2959 
2960  wxString name = text;
2961 
2962  if (text.Right(1) != wxT(':'))
2963  {
2964  text += wxT(':');
2965  }
2966  mNames[i]->SetLabel(text);
2967 
2968  // For some parameters types like on/off, setting the slider value has
2969  // a side effect that causes it to only move when the parameter changes
2970  // from off to on. However, this prevents changing the value using the
2971  // keyboard, so we skip the active slider if any.
2972  if (i != skip)
2973  {
2974  mSliders[i]->SetValue(callGetParameter(i) * 1000);
2975  }
2976  name = text;
2977 
2978  text = GetString(effGetParamDisplay, i);
2979  if (text.IsEmpty())
2980  {
2981  text.Printf(wxT("%.5g"),callGetParameter(i));
2982  }
2983  mDisplays[i]->SetLabel(wxString::Format(wxT("%8s"), text));
2984  name += wxT(' ') + text;
2985 
2986  text = GetString(effGetParamDisplay, i);
2987  if (!text.IsEmpty())
2988  {
2989  text.Printf(wxT("%-8s"), GetString(effGetParamLabel, i));
2990  mLabels[i]->SetLabel(wxString::Format(wxT("%8s"), text));
2991  name += wxT(' ') + text;
2992  }
2993 
2994  mSliders[i]->SetName(name);
2995  }
2996 }
2997 
2998 void VSTEffect::OnSizeWindow(wxCommandEvent & evt)
2999 {
3000  if (!mControl)
3001  {
3002  return;
3003  }
3004 
3005  mControl->SetMinSize(wxSize(evt.GetInt(), (int) evt.GetExtraLong()));
3006  mControl->SetSize(wxSize(evt.GetInt(), (int) evt.GetExtraLong()));
3007 
3008  // DO NOT CHANGE THE ORDER OF THESE
3009  //
3010  // Guitar Rig (and possibly others) Cocoa VSTs can resize too large
3011  // if the bounds are unlimited.
3012  mDialog->SetMinSize(wxDefaultSize);
3013  mDialog->SetMaxSize(wxDefaultSize);
3014  mDialog->Layout();
3015  mDialog->SetMinSize(mDialog->GetBestSize());
3016  mDialog->SetMaxSize(mDialog->GetBestSize());
3017  mDialog->Fit();
3018 }
3019 
3020 void VSTEffect::OnSlider(wxCommandEvent & evt)
3021 {
3022  wxSlider *s = (wxSlider *) evt.GetEventObject();
3023  int i = s->GetId() - ID_Sliders;
3024 
3025  callSetParameter(i, s->GetValue() / 1000.0);
3026 
3027  RefreshParameters(i);
3028 }
3029 
3030 bool VSTEffect::LoadFXB(const wxFileName & fn)
3031 {
3032  bool ret = false;
3033 
3034  // Try to open the file...will be closed automatically when method returns
3035  wxFFile f(fn.GetFullPath(), wxT("rb"));
3036  if (!f.IsOpened())
3037  {
3038  return false;
3039  }
3040 
3041  // Allocate memory for the contents
3042  ArrayOf<unsigned char> data{ size_t(f.Length()) };
3043  if (!data)
3044  {
3045  AudacityMessageBox(_("Unable to allocate memory when loading presets file."),
3046  _("Error Loading VST Presets"),
3047  wxOK | wxCENTRE,
3048  mParent);
3049  return false;
3050  }
3051  unsigned char *bptr = data.get();
3052 
3053  do
3054  {
3055  // Read in the whole file
3056  ssize_t len = f.Read((void *) bptr, f.Length());
3057  if (f.Error())
3058  {
3059  AudacityMessageBox(_("Unable to read presets file."),
3060  _("Error Loading VST Presets"),
3061  wxOK | wxCENTRE,
3062  mParent);
3063  break;
3064  }
3065 
3066  // Most references to the data are via an "int" array
3067  int32_t *iptr = (int32_t *) bptr;
3068 
3069  // Verify that we have at least enough for the header
3070  if (len < 156)
3071  {
3072  break;
3073  }
3074 
3075  // Verify that we probably have an FX file
3076  if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K'))
3077  {
3078  break;
3079  }
3080 
3081  // Ignore the size...sometimes it's there, other times it's zero
3082 
3083  // Get the version and verify
3084  int version = wxINT32_SWAP_ON_LE(iptr[3]);
3085  if (version != 1 && version != 2)
3086  {
3087  break;
3088  }
3089 
3090  VstPatchChunkInfo info =
3091  {
3092  1,
3093  wxINT32_SWAP_ON_LE(iptr[4]),
3094  wxINT32_SWAP_ON_LE(iptr[5]),
3095  wxINT32_SWAP_ON_LE(iptr[6]),
3096  ""
3097  };
3098 
3099  // Ensure this program looks to belong to the current plugin
3100  if ((info.pluginUniqueID != mAEffect->uniqueID) &&
3101  (info.pluginVersion != mAEffect->version) &&
3102  (info.numElements != mAEffect->numPrograms))
3103  {
3104  break;
3105  }
3106 
3107  // Get the number of programs
3108  int numProgs = info.numElements;
3109 
3110  // Get the current program index
3111  int curProg = 0;
3112  if (version >= 2)
3113  {
3114  curProg = wxINT32_SWAP_ON_LE(iptr[7]);
3115  if (curProg < 0 || curProg >= numProgs)
3116  {
3117  break;
3118  }
3119  }
3120 
3121  // Is it a bank of programs?
3122  if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'B', 'k'))
3123  {
3124  // Drop the header
3125  bptr += 156;
3126  len -= 156;
3127 
3128  unsigned char *tempPtr = bptr;
3129  ssize_t tempLen = len;
3130 
3131  // Validate all of the programs
3132  for (int i = 0; i < numProgs; i++)
3133  {
3134  if (!LoadFXProgram(&tempPtr, tempLen, i, true))
3135  {
3136  break;
3137  }
3138  }
3139 
3140  // Ask the effect if this is an acceptable bank
3141  if (callDispatcher(effBeginLoadBank, 0, 0, &info, 0.0) == -1)
3142  {
3143  return false;
3144  }
3145 
3146  // Start loading the individual programs
3147  for (int i = 0; i < numProgs; i++)
3148  {
3149  ret = LoadFXProgram(&bptr, len, i, false);
3150  }
3151  }
3152  // Or maybe a bank chunk?
3153  else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'B', 'C', 'h'))
3154  {
3155  // Can't load programs chunks if the plugin doesn't support it
3157  {
3158  break;
3159  }
3160 
3161  // Verify that we have enough to grab the chunk size
3162  if (len < 160)
3163  {
3164  break;
3165  }
3166 
3167  // Get the chunk size
3168  int size = wxINT32_SWAP_ON_LE(iptr[39]);
3169 
3170  // We finally know the full length of the program
3171  int proglen = 160 + size;
3172 
3173  // Verify that we have enough for the entire program
3174  if (len < proglen)
3175  {
3176  break;
3177  }
3178 
3179  // Set the entire bank in one shot
3180  callSetChunk(false, size, &iptr[40], &info);
3181 
3182  // Success
3183  ret = true;
3184  }
3185  // Unrecognizable type
3186  else
3187  {
3188  break;
3189  }
3190 
3191  // Set the active program
3192  if (ret && version >= 2)
3193  {
3194  callSetProgram(curProg);
3195  }
3196  } while (false);
3197 
3198  return ret;
3199 }
3200 
3201 bool VSTEffect::LoadFXP(const wxFileName & fn)
3202 {
3203  bool ret = false;
3204 
3205  // Try to open the file...will be closed automatically when method returns
3206  wxFFile f(fn.GetFullPath(), wxT("rb"));
3207  if (!f.IsOpened())
3208  {
3209  return false;
3210  }
3211 
3212  // Allocate memory for the contents
3213  ArrayOf<unsigned char> data{ size_t(f.Length()) };
3214  if (!data)
3215  {
3216  AudacityMessageBox(_("Unable to allocate memory when loading presets file."),
3217  _("Error Loading VST Presets"),
3218  wxOK | wxCENTRE,
3219  mParent);
3220  return false;
3221  }
3222  unsigned char *bptr = data.get();
3223 
3224  do
3225  {
3226  // Read in the whole file
3227  ssize_t len = f.Read((void *) bptr, f.Length());
3228  if (f.Error())
3229  {
3230  AudacityMessageBox(_("Unable to read presets file."),
3231  _("Error Loading VST Presets"),
3232  wxOK | wxCENTRE,
3233  mParent);
3234  break;
3235  }
3236 
3237  // Get (or default) currently selected program
3238  int i = 0; //mProgram->GetCurrentSelection();
3239  if (i < 0)
3240  {
3241  i = 0; // default to first program
3242  }
3243 
3244  // Go verify and set the program
3245  ret = LoadFXProgram(&bptr, len, i, false);
3246  } while (false);
3247 
3248  return ret;
3249 }
3250 
3251 bool VSTEffect::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bool dryrun)
3252 {
3253  // Most references to the data are via an "int" array
3254  int32_t *iptr = (int32_t *) *bptr;
3255 
3256  // Verify that we have at least enough for a program without parameters
3257  if (len < 28)
3258  {
3259  return false;
3260  }
3261 
3262  // Verify that we probably have an FX file
3263  if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K'))
3264  {
3265  return false;
3266  }
3267 
3268  // Ignore the size...sometimes it's there, other times it's zero
3269 
3270  // Get the version and verify
3271 #if defined(IS_THIS_AN_FXP_ARTIFICAL_LIMITATION)
3272  int version = wxINT32_SWAP_ON_LE(iptr[3]);
3273  if (version != 1)
3274  {
3275  return false;
3276  }
3277 #endif
3278 
3279  VstPatchChunkInfo info =
3280  {
3281  1,
3282  wxINT32_SWAP_ON_LE(iptr[4]),
3283  wxINT32_SWAP_ON_LE(iptr[5]),
3284  wxINT32_SWAP_ON_LE(iptr[6]),
3285  ""
3286  };
3287 
3288  // Ensure this program looks to belong to the current plugin
3289  if ((info.pluginUniqueID != mAEffect->uniqueID) &&
3290  (info.pluginVersion != mAEffect->version) &&
3291  (info.numElements != mAEffect->numParams))
3292  {
3293  return false;
3294  }
3295 
3296  // Get the number of parameters
3297  int numParams = info.numElements;
3298 
3299  // At this point, we have to have enough to include the program name as well
3300  if (len < 56)
3301  {
3302  return false;
3303  }
3304 
3305  // Get the program name
3306  wxString progName(wxString::From8BitData((char *)&iptr[7]));
3307 
3308  // Might be a regular program
3309  if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'C', 'k'))
3310  {
3311  // We finally know the full length of the program
3312  int proglen = 56 + (numParams * sizeof(float));
3313 
3314  // Verify that we have enough for all of the parameter values
3315  if (len < proglen)
3316  {
3317  return false;
3318  }
3319 
3320  // Validate all of the parameter values
3321  for (int i = 0; i < numParams; i++)
3322  {
3323  uint32_t ival = wxUINT32_SWAP_ON_LE(iptr[14 + i]);
3324  float val = reinterpretAsFloat(ival);
3325  if (val < 0.0 || val > 1.0)
3326  {
3327  return false;
3328  }
3329  }
3330 
3331  // They look okay...time to start changing things
3332  if (!dryrun)
3333  {
3334  // Ask the effect if this is an acceptable program
3335  if (callDispatcher(effBeginLoadProgram, 0, 0, &info, 0.0) == -1)
3336  {
3337  return false;
3338  }
3339 
3340  // Load all of the parameters
3341  callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
3342  for (int i = 0; i < numParams; i++)
3343  {
3344  wxUint32 val = wxUINT32_SWAP_ON_LE(iptr[14 + i]);
3346  }
3347  callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
3348  }
3349 
3350  // Update in case we're loading an "FxBk" format bank file
3351  *bptr += proglen;
3352  len -= proglen;
3353  }
3354  // Maybe we have a program chunk
3355  else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'P', 'C', 'h'))
3356  {
3357  // Can't load programs chunks if the plugin doesn't support it
3359  {
3360  return false;
3361  }
3362 
3363  // Verify that we have enough to grab the chunk size
3364  if (len < 60)
3365  {
3366  return false;
3367  }
3368 
3369  // Get the chunk size
3370  int size = wxINT32_SWAP_ON_LE(iptr[14]);
3371 
3372  // We finally know the full length of the program
3373  int proglen = 60 + size;
3374 
3375  // Verify that we have enough for the entire program
3376  if (len < proglen)
3377  {
3378  return false;
3379  }
3380 
3381  // Set the entire program in one shot
3382  if (!dryrun)
3383  {
3384  callSetChunk(true, size, &iptr[15], &info);
3385  }
3386 
3387  // Update in case we're loading an "FxBk" format bank file
3388  *bptr += proglen;
3389  len -= proglen;
3390  }
3391  else
3392  {
3393  // Unknown type
3394  return false;
3395  }
3396 
3397  if (!dryrun)
3398  {
3399  SetString(effSetProgramName, wxString(progName), index);
3400  }
3401 
3402  return true;
3403 }
3404 
3405 bool VSTEffect::LoadXML(const wxFileName & fn)
3406 {
3407  mInChunk = false;
3408  mInSet = false;
3409 
3410  // default to read as XML file
3411  // Load the program
3412  XMLFileReader reader;
3413  bool ok = reader.Parse(this, fn.GetFullPath());
3414 
3415  // Something went wrong with the file, clean up
3416  if (mInSet)
3417  {
3418  callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
3419 
3420  mInSet = false;
3421  }
3422 
3423  if (!ok)
3424  {
3425  // Inform user of load failure
3427  _("Error Loading VST Presets"),
3428  wxOK | wxCENTRE,
3429  mParent);
3430  return false;
3431  }
3432 
3433  return true;
3434 }
3435 
3436 void VSTEffect::SaveFXB(const wxFileName & fn)
3437 {
3438  // Create/Open the file
3439  const wxString fullPath{fn.GetFullPath()};
3440  wxFFile f(fullPath, wxT("wb"));
3441  if (!f.IsOpened())
3442  {
3443  AudacityMessageBox(wxString::Format(_("Could not open file: \"%s\""), fullPath),
3444  _("Error Saving VST Presets"),
3445  wxOK | wxCENTRE,
3446  mParent);
3447  return;
3448  }
3449 
3450  wxMemoryBuffer buf;
3451  wxInt32 subType;
3452  void *chunkPtr = nullptr;
3453  int chunkSize = 0;
3454  int dataSize = 148;
3455  wxInt32 tab[8];
3456  int curProg = 0 ; //mProgram->GetCurrentSelection();
3457 
3459  {
3460  subType = CCONST('F', 'B', 'C', 'h');
3461 
3462  chunkSize = callDispatcher(effGetChunk, 0, 0, &chunkPtr, 0.0);
3463  dataSize += 4 + chunkSize;
3464  }
3465  else
3466  {
3467  subType = CCONST('F', 'x', 'B', 'k');
3468 
3469  for (int i = 0; i < mAEffect->numPrograms; i++)
3470  {
3471  SaveFXProgram(buf, i);
3472  }
3473 
3474  dataSize += buf.GetDataLen();
3475  }
3476 
3477  tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K'));
3478  tab[1] = wxINT32_SWAP_ON_LE(dataSize);
3479  tab[2] = wxINT32_SWAP_ON_LE(subType);
3480  tab[3] = wxINT32_SWAP_ON_LE(curProg >= 0 ? 2 : 1);
3481  tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID);
3482  tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version);
3483  tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numPrograms);
3484  tab[7] = wxINT32_SWAP_ON_LE(curProg >= 0 ? curProg : 0);
3485 
3486  f.Write(tab, sizeof(tab));
3487  if (!f.Error())
3488  {
3489  char padding[124];
3490  memset(padding, 0, sizeof(padding));
3491  f.Write(padding, sizeof(padding));
3492 
3493  if (!f.Error())
3494  {
3496  {
3497  wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize);
3498  f.Write(&size, sizeof(size));
3499  f.Write(chunkPtr, chunkSize);
3500  }
3501  else
3502  {
3503  f.Write(buf.GetData(), buf.GetDataLen());
3504  }
3505  }
3506  }
3507 
3508  if (f.Error())
3509  {
3510  AudacityMessageBox(wxString::Format(_("Error writing to file: \"%s\""), fullPath),
3511  _("Error Saving VST Presets"),
3512  wxOK | wxCENTRE,
3513  mParent);
3514  }
3515 
3516  f.Close();
3517 
3518  return;
3519 }
3520 
3521 void VSTEffect::SaveFXP(const wxFileName & fn)
3522 {
3523  // Create/Open the file
3524  const wxString fullPath{ fn.GetFullPath() };
3525  wxFFile f(fullPath, wxT("wb"));
3526  if (!f.IsOpened())
3527  {
3528  AudacityMessageBox(wxString::Format(_("Could not open file: \"%s\""), fullPath),
3529  _("Error Saving VST Presets"),
3530  wxOK | wxCENTRE,
3531  mParent);
3532  return;
3533  }
3534 
3535  wxMemoryBuffer buf;
3536 
3537  int ndx = callDispatcher(effGetProgram, 0, 0, NULL, 0.0);
3538  SaveFXProgram(buf, ndx);
3539 
3540  f.Write(buf.GetData(), buf.GetDataLen());
3541  if (f.Error())
3542  {
3543  AudacityMessageBox(wxString::Format(_("Error writing to file: \"%s\""), fullPath),
3544  _("Error Saving VST Presets"),
3545  wxOK | wxCENTRE,
3546  mParent);
3547  }
3548 
3549  f.Close();
3550 
3551  return;
3552 }
3553 
3554 void VSTEffect::SaveFXProgram(wxMemoryBuffer & buf, int index)
3555 {
3556  wxInt32 subType;
3557  void *chunkPtr;
3558  int chunkSize;
3559  int dataSize = 48;
3560  char progName[28];
3561  wxInt32 tab[7];
3562 
3563  callDispatcher(effGetProgramNameIndexed, index, 0, &progName, 0.0);
3564  progName[27] = '\0';
3565  chunkSize = strlen(progName);
3566  memset(&progName[chunkSize], 0, sizeof(progName) - chunkSize);
3567 
3569  {
3570  subType = CCONST('F', 'P', 'C', 'h');
3571 
3572  chunkSize = callDispatcher(effGetChunk, 1, 0, &chunkPtr, 0.0);
3573  dataSize += 4 + chunkSize;
3574  }
3575  else
3576  {
3577  subType = CCONST('F', 'x', 'C', 'k');
3578 
3579  dataSize += (mAEffect->numParams << 2);
3580  }
3581 
3582  tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K'));
3583  tab[1] = wxINT32_SWAP_ON_LE(dataSize);
3584  tab[2] = wxINT32_SWAP_ON_LE(subType);
3585  tab[3] = wxINT32_SWAP_ON_LE(1);
3586  tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID);
3587  tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version);
3588  tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numParams);
3589 
3590  buf.AppendData(tab, sizeof(tab));
3591  buf.AppendData(progName, sizeof(progName));
3592 
3594  {
3595  wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize);
3596  buf.AppendData(&size, sizeof(size));
3597  buf.AppendData(chunkPtr, chunkSize);
3598  }
3599  else
3600  {
3601  for (int i = 0; i < mAEffect->numParams; i++)
3602  {
3603  float val = callGetParameter(i);
3604  wxUint32 ival = wxUINT32_SWAP_ON_LE(reinterpretAsUint32(val));
3605  buf.AppendData(&ival, sizeof(ival));
3606  }
3607  }
3608 
3609  return;
3610 }
3611 
3612 // Throws exceptions rather than giving error return.
3613 void VSTEffect::SaveXML(const wxFileName & fn)
3614 // may throw
3615 {
3616  XMLFileWriter xmlFile{ fn.GetFullPath(), _("Error Saving Effect Presets") };
3617 
3618  xmlFile.StartTag(wxT("vstprogrampersistence"));
3619  xmlFile.WriteAttr(wxT("version"), wxT("2"));
3620 
3621  xmlFile.StartTag(wxT("effect"));
3622  // Use internal name only in persistent information
3623  xmlFile.WriteAttr(wxT("name"), GetSymbol().Internal());
3624  xmlFile.WriteAttr(wxT("uniqueID"), mAEffect->uniqueID);
3625  xmlFile.WriteAttr(wxT("version"), mAEffect->version);
3626  xmlFile.WriteAttr(wxT("numParams"), mAEffect->numParams);
3627 
3628  xmlFile.StartTag(wxT("program"));
3629  xmlFile.WriteAttr(wxT("name"), wxEmptyString); //mProgram->GetValue());
3630 
3631  int clen = 0;
3633  {
3634  void *chunk = NULL;
3635 
3636  clen = (int) callDispatcher(effGetChunk, 1, 0, &chunk, 0.0);
3637  if (clen != 0)
3638  {
3639  xmlFile.StartTag(wxT("chunk"));
3640  xmlFile.WriteSubTree(VSTEffect::b64encode(chunk, clen) + wxT('\n'));
3641  xmlFile.EndTag(wxT("chunk"));
3642  }
3643  }
3644 
3645  if (clen == 0)
3646  {
3647  for (int i = 0; i < mAEffect->numParams; i++)
3648  {
3649  xmlFile.StartTag(wxT("param"));
3650 
3651  xmlFile.WriteAttr(wxT("index"), i);
3652  xmlFile.WriteAttr(wxT("name"),
3654  xmlFile.WriteAttr(wxT("value"),
3655  wxString::Format(wxT("%f"),
3656  callGetParameter(i)));
3657 
3658  xmlFile.EndTag(wxT("param"));
3659  }
3660  }
3661 
3662  xmlFile.EndTag(wxT("program"));
3663 
3664  xmlFile.EndTag(wxT("effect"));
3665 
3666  xmlFile.EndTag(wxT("vstprogrampersistence"));
3667 
3668  xmlFile.Commit();
3669 }
3670 
3671 bool VSTEffect::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
3672 {
3673  if (wxStrcmp(tag, wxT("vstprogrampersistence")) == 0)
3674  {
3675  while (*attrs)
3676  {
3677  const wxChar *attr = *attrs++;
3678  const wxChar *value = *attrs++;
3679 
3680  if (!value)
3681  {
3682  break;
3683  }
3684 
3685  const wxString strValue = value;
3686 
3687  if (wxStrcmp(attr, wxT("version")) == 0)
3688  {
3689  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&mXMLVersion))
3690  {
3691  return false;
3692  }
3693 
3694  if (mXMLVersion < 1 || mXMLVersion > 2)
3695  {
3696  return false;
3697  }
3698  }
3699  else
3700  {
3701  return false;
3702  }
3703  }
3704 
3705  return true;
3706  }
3707 
3708  if (wxStrcmp(tag, wxT("effect")) == 0)
3709  {
3710  memset(&mXMLInfo, 0, sizeof(mXMLInfo));
3711  mXMLInfo.version = 1;
3715 
3716  while (*attrs)
3717  {
3718  const wxChar *attr = *attrs++;
3719  const wxChar *value = *attrs++;
3720 
3721  if (!value)
3722  {
3723  break;
3724  }
3725 
3726  const wxString strValue = value;
3727 
3728  if (wxStrcmp(attr, wxT("name")) == 0)
3729  {
3730  if (!XMLValueChecker::IsGoodString(strValue))
3731  {
3732  return false;
3733  }
3734 
3735  if (value != GetSymbol().Internal())
3736  {
3737  wxString msg;
3738  msg.Printf(_("This parameter file was saved from %s. Continue?"), value);
3739  int result = AudacityMessageBox(msg, wxT("Confirm"), wxYES_NO, mParent);
3740  if (result == wxNO)
3741  {
3742  return false;
3743  }
3744  }
3745  }
3746  else if (wxStrcmp(attr, wxT("version")) == 0)
3747  {
3748  long version;
3749  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&version))
3750  {
3751  return false;
3752  }
3753 
3754  mXMLInfo.pluginVersion = (int) version;
3755  }
3756  else if (mXMLVersion > 1 && wxStrcmp(attr, wxT("uniqueID")) == 0)
3757  {
3758  long uniqueID;
3759  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&uniqueID))
3760  {
3761  return false;
3762  }
3763 
3764  mXMLInfo.pluginUniqueID = (int) uniqueID;
3765  }
3766  else if (mXMLVersion > 1 && wxStrcmp(attr, wxT("numParams")) == 0)
3767  {
3768  long numParams;
3769  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&numParams))
3770  {
3771  return false;
3772  }
3773 
3774  mXMLInfo.numElements = (int) numParams;
3775  }
3776  else
3777  {
3778  return false;
3779  }
3780  }
3781 
3782  return true;
3783  }
3784 
3785  if (wxStrcmp(tag, wxT("program")) == 0)
3786  {
3787  while (*attrs)
3788  {
3789  const wxChar *attr = *attrs++;
3790  const wxChar *value = *attrs++;
3791 
3792  if (!value)
3793  {
3794  break;
3795  }
3796 
3797  const wxString strValue = value;
3798 
3799  if (wxStrcmp(attr, wxT("name")) == 0)
3800  {
3801  if (!XMLValueChecker::IsGoodString(strValue))
3802  {
3803  return false;
3804  }
3805 
3806  if (strValue.length() > 24)
3807  {
3808  return false;
3809  }
3810 
3811  int ndx = 0; //mProgram->GetCurrentSelection();
3812  if (ndx == wxNOT_FOUND)
3813  {
3814  ndx = 0;
3815  }
3816 
3817  SetString(effSetProgramName, strValue, ndx);
3818  }
3819  else
3820  {
3821  return false;
3822  }
3823  }
3824 
3825  mInChunk = false;
3826 
3827  if (callDispatcher(effBeginLoadProgram, 0, 0, &mXMLInfo, 0.0) == -1)
3828  {
3829  return false;
3830  }
3831 
3832  callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
3833 
3834  mInSet = true;
3835 
3836  return true;
3837  }
3838 
3839  if (wxStrcmp(tag, wxT("param")) == 0)
3840  {
3841  long ndx = -1;
3842  double val = -1.0;
3843  while (*attrs)
3844  {
3845  const wxChar *attr = *attrs++;
3846  const wxChar *value = *attrs++;
3847 
3848  if (!value)
3849  {
3850  break;
3851  }
3852 
3853  const wxString strValue = value;
3854 
3855  if (wxStrcmp(attr, wxT("index")) == 0)
3856  {
3857  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&ndx))
3858  {
3859  return false;
3860  }
3861 
3862  if (ndx < 0 || ndx >= mAEffect->numParams)
3863  {
3864  // Could be a different version of the effect...probably should
3865  // tell the user
3866  return false;
3867  }
3868  }
3869  else if (wxStrcmp(attr, wxT("name")) == 0)
3870  {
3871  if (!XMLValueChecker::IsGoodString(strValue))
3872  {
3873  return false;
3874  }
3875  // Nothing to do with it for now
3876  }
3877  else if (wxStrcmp(attr, wxT("value")) == 0)
3878  {
3879  if (!XMLValueChecker::IsGoodInt(strValue) ||
3880  !Internat::CompatibleToDouble(strValue, &val))
3881  {
3882  return false;
3883  }
3884 
3885  if (val < 0.0 || val > 1.0)
3886  {
3887  return false;
3888  }
3889  }
3890  }
3891 
3892  if (ndx == -1 || val == -1.0)
3893  {
3894  return false;
3895  }
3896 
3897  callSetParameter(ndx, val);
3898 
3899  return true;
3900  }
3901 
3902  if (wxStrcmp(tag, wxT("chunk")) == 0)
3903  {
3904  mInChunk = true;
3905  return true;
3906  }
3907 
3908  return false;
3909 }
3910 
3911 void VSTEffect::HandleXMLEndTag(const wxChar *tag)
3912 {
3913  if (wxStrcmp(tag, wxT("chunk")) == 0)
3914  {
3915  if (mChunk.length())
3916  {
3917  ArrayOf<char> buf{ mChunk.length() / 4 * 3 };
3918 
3919  int len = VSTEffect::b64decode(mChunk, buf.get());
3920  if (len)
3921  {
3922  callSetChunk(true, len, buf.get(), &mXMLInfo);
3923  }
3924 
3925  mChunk.clear();
3926  }
3927  mInChunk = false;
3928  }
3929 
3930  if (wxStrcmp(tag, wxT("program")) == 0)
3931  {
3932  if (mInSet)
3933  {
3934  callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
3935 
3936  mInSet = false;
3937  }
3938  }
3939 }
3940 
3941 void VSTEffect::HandleXMLContent(const wxString & content)
3942 {
3943  if (mInChunk)
3944  {
3945  mChunk += wxString(content).Trim(true).Trim(false);
3946  }
3947 }
3948 
3950 {
3951  if (wxStrcmp(tag, wxT("vstprogrampersistence")) == 0)
3952  {
3953  return this;
3954  }
3955 
3956  if (wxStrcmp(tag, wxT("effect")) == 0)
3957  {
3958  return this;
3959  }
3960 
3961  if (wxStrcmp(tag, wxT("program")) == 0)
3962  {
3963  return this;
3964  }
3965 
3966  if (wxStrcmp(tag, wxT("param")) == 0)
3967  {
3968  return this;
3969  }
3970 
3971  if (wxStrcmp(tag, wxT("chunk")) == 0)
3972  {
3973  return this;
3974  }
3975 
3976  return NULL;
3977 }
3978 
3979 #endif // USE_VST
wxString GetDescription() override
Definition: VSTEffect.cpp:249
unsigned mNumChannels
Definition: VSTEffect.h:351
void PopulateOrExchange(ShuttleGui &S)
Definition: VSTEffect.cpp:794
void callSetParameter(int index, float value)
Definition: VSTEffect.cpp:2566
const int audioMasterGetSampleRate
Definition: aeffectx.h:50
VST Effects class, conforming to VST layout.
Definition: aeffectx.h:257
#define AUDACITY_REVISION
Definition: Audacity.h:65
EVT_COMMAND_RANGE(ID_Slider, ID_Slider+NUMBER_OF_BANDS-1, wxEVT_COMMAND_SLIDER_UPDATED, EffectEqualization::OnSlider) EffectEqualization
bool CanExportPresets() override
Definition: VSTEffect.cpp:1833
bool RealtimeFinalize() override
Definition: VSTEffect.cpp:1492
ComponentInterfaceSymbol GetVendor() override
Definition: VSTEffect.cpp:1198
virtual ~VSTEffectOptionsDialog()
Definition: VSTEffect.cpp:790
float mSampleRate
Definition: VSTEffect.h:278
const int effSetProgram
Definition: aeffectx.h:93
void SaveFXP(const wxFileName &fn)
Definition: VSTEffect.cpp:3521
int GetMidiInCount() override
Definition: VSTEffect.cpp:1344
const int audioMasterProcessEvents
Definition: aeffectx.h:42
void OnTimer()
Definition: VSTEffect.cpp:2376
#define AUDACITY_VERSION_STRING
Definition: Audacity.h:81
const wxString & Translation() const
const int audioMasterGetVendorVersion
Definition: aeffectx.h:69
void OnExit()
Definition: VSTEffect.cpp:187
const int effStopProcess
Definition: aeffectx.h:142
const int audioMasterWillReplaceOrAccumulate
Definition: aeffectx.h:56
const int kVstLangEnglish
Definition: aeffectx.h:145
bool mGui
Definition: VSTEffect.h:360
void BuildFancy()
Definition: VSTEffect.cpp:2781
virtual ~VSTEffectsModule()
Definition: VSTEffect.cpp:315
VSTEffectArray mSlaves
Definition: VSTEffect.h:350
void UpdateDisplay()
Definition: VSTEffect.cpp:2479
EffectType mType
Definition: VSTEffect.cpp:295
ComponentInterfaceSymbol GetFamilyId() override
Definition: VSTEffect.cpp:1256
wxString GetPath() override
Definition: VSTEffect.cpp:229
VSTEffect * mEffect
Definition: VSTEffect.cpp:909
const int audioMasterBeginEdit
Definition: aeffectx.h:78
bool RealtimeProcessStart() override
Definition: VSTEffect.cpp:1525
bool LoadFXB(const wxFileName &fn)
Definition: VSTEffect.cpp:3030
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
const int effOpen
Definition: aeffectx.h:91
int32_t pluginUniqueID
Definition: aeffectx.h:356
intptr_t(* audioMasterCallback)(AEffect *, int32_t, int32_t, intptr_t, void *, float)
Definition: aeffectx.h:337
const int effGetEffectName
Definition: aeffectx.h:120
const int effClose
Definition: aeffectx.h:92
static const wxString & GetExecutablePath()
unsigned GetAudioOutCount() override
Definition: VSTEffect.cpp:1339
const int effSetProgramName
Definition: aeffectx.h:96
unsigned GetAudioInCount() override
Definition: VSTEffect.cpp:1334
virtual void FindFilesInPathList(const wxString &pattern, const wxArrayString &pathList, wxArrayString &files, bool directories=false)=0
const int kVstTransportPlaying
Definition: aeffectx.h:157
EffectType
void(* setParameter)(AEffect *, int, float)
Definition: aeffectx.h:268
const int audioMasterCurrentId
Definition: aeffectx.h:36
bool mInSet
Definition: VSTEffect.h:370
void OnOk(wxCommandEvent &evt)
Definition: VSTEffect.cpp:866
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:113
const int effGetProgramNameIndexed
Definition: aeffectx.h:117
void NeedIdle()
Definition: VSTEffect.cpp:2401
#define OUTPUTKEY
Definition: VSTEffect.cpp:196
bool LoadFactoryDefaults() override
Definition: VSTEffect.cpp:1725
bool LoadFXProgram(unsigned char **bptr, ssize_t &len, int index, bool dryrun)
Definition: VSTEffect.cpp:3251
static uint32_t reinterpretAsUint32(float f)
Definition: VSTEffect.cpp:115
intptr_t(* dispatcher)(AEffect *, int, int, intptr_t, void *, float)
Definition: aeffectx.h:264
ComponentInterfaceSymbol GetVendor() override
Definition: VSTEffect.cpp:334
const int audioMasterGetCurrentProcessLevel
Definition: aeffectx.h:57
unsigned mAudioOuts
Definition: VSTEffect.h:274
void SetBufferDelay(int samples)
Definition: VSTEffect.cpp:2506
double nanoSeconds
Definition: aeffectx.h:313
ArrayOf< wxStaticText * > mLabels
Definition: VSTEffect.h:368
const int audioMasterVersion
Definition: aeffectx.h:35
const int effShellGetNextPlugin
Definition: aeffectx.h:134
static void Check(const wxChar *path)
Definition: VSTEffect.cpp:706
const int effMainsChanged
Definition: aeffectx.h:104
bool SupportsRealtime() override
Definition: VSTEffect.cpp:279
int magic
Definition: aeffectx.h:262
size_t mNumSamples
Definition: VSTEffect.h:353
void callSetProgram(int index)
Definition: VSTEffect.cpp:2577
int mVstVersion
Definition: VSTEffect.h:285
static intptr_t mCurrentEffectID
Definition: VSTEffect.h:287
const int effGetProductString
Definition: aeffectx.h:123
const int effIdle
Definition: aeffectx.h:127
#define VSTCMDKEY
Definition: VSTEffect.h:24
int mMidiOuts
Definition: VSTEffect.h:276
virtual wxString GetFactoryDefaultsGroup()=0
const int audioMasterSizeWindow
Definition: aeffectx.h:49
static intptr_t AudioMaster(AEffect *effect, int32_t opcode, int32_t index, intptr_t value, void *ptr, float opt)
Definition: VSTEffect.cpp:938
unsigned DiscoverPluginsAtPath(const wxString &path, wxString &errMsg, const RegistrationCallback &callback) override
Definition: VSTEffect.cpp:496
VstTimeInfo * GetTimeInfo()
Definition: VSTEffect.cpp:2413
void * ptr2
Definition: aeffectx.h:283
std::unique_ptr< VSTEffectTimer > mTimer
Definition: VSTEffect.h:345
void(* processReplacing)(AEffect *, float **, float **, int)
Definition: aeffectx.h:298
const int effFlagsHasEditor
Definition: aeffectx.h:86
void Unload()
Definition: VSTEffect.cpp:2248
EffectHostInterface * mHost
Definition: VSTEffect.h:270
int mMidiIns
Definition: VSTEffect.h:275
Base class for many of the effects in Audacity.
Definition: Effect.h:62
InfoKeys
Definition: VSTEffect.cpp:197
void RefreshParameters(int skip=-1)
Definition: VSTEffect.cpp:2947
#define XO(s)
Definition: Internat.h:33
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
Like a smart pointer, allows for object to not exist (nullptr)
Definition: MemoryX.h:209
bool LoadUserPreset(const wxString &name) override
Definition: VSTEffect.cpp:1681
ModuleManagerInterface * mModMan
Definition: VSTEffect.h:426
bool LoadXML(const wxFileName &fn)
Definition: VSTEffect.cpp:3405
bool SetAutomationParameters(CommandParameters &parms) override
Definition: VSTEffect.cpp:1651
int numOutputs
Definition: aeffectx.h:278
void PowerOff()
Definition: VSTEffect.cpp:2447
wxArrayString GetFactoryPresets() override
Definition: VSTEffect.cpp:1698
const int effEditIdle
Definition: aeffectx.h:108
const wxString & Internal() const
const int effGetParamDisplay
Definition: aeffectx.h:100
const int audioMasterPinConnected
Definition: aeffectx.h:38
bool RealtimeResume() override
Definition: VSTEffect.cpp:1515
const int effGetVendorString
Definition: aeffectx.h:122
void PowerOn()
Definition: VSTEffect.cpp:2429
Options & AutoPos(bool enable)
virtual wxString GetCurrentSettingsGroup()=0
bool mReady
Definition: VSTEffect.h:289
bool Load()
Definition: VSTEffect.cpp:1977
int numParams
Definition: aeffectx.h:274
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override
Definition: VSTEffect.cpp:3671
int32_t uniqueID
Definition: aeffectx.h:295
FloatBuffers mMasterIn
Definition: VSTEffect.h:352
NumericTextCtrl * mDuration
Definition: VSTEffect.h:364
bool mInChunk
Definition: VSTEffect.h:371
float callGetParameter(int index)
Definition: VSTEffect.cpp:2561
void SaveFXProgram(wxMemoryBuffer &buf, int index)
Definition: VSTEffect.cpp:3554
void NeedEditIdle(bool state)
Definition: VSTEffect.cpp:2407
bool SaveParameters(const wxString &group)
Definition: VSTEffect.cpp:2342
const int audioMasterAutomate
Definition: aeffectx.h:34
#define AUDACITY_VERSION
Definition: Audacity.h:63
int numPrograms
Definition: aeffectx.h:272
#define safenew
Definition: Audacity.h:230
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
bool mUseLatency
Definition: VSTEffect.h:333
wxString mName
Definition: VSTEffect.cpp:291
#define PLATFORM_MAX_PATH
Definition: Audacity.h:118
wxString GetDescription() override
Definition: VSTEffect.cpp:1222
static const char padc
Definition: VSTEffect.cpp:2639
void EndHorizontalLay()
ComponentInterfaceSymbol GetSymbol() override
Definition: VSTEffect.cpp:1193
ComponentInterface * CreateInstance(const wxString &path) override
Definition: VSTEffect.cpp:680
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
VstPatchChunkInfo mXMLInfo
Definition: VSTEffect.h:374
wxArrayString FindPluginPaths(PluginManagerInterface &pm) override
Definition: VSTEffect.cpp:387
const int effGetParamLabel
Definition: aeffectx.h:99
VstPlugCategory
Definition: aeffectx.h:363
void Terminate() override
Definition: VSTEffect.cpp:360
bool OnInit()
Definition: VSTEffect.cpp:165
const int audioMasterGetLanguage
Definition: aeffectx.h:73
const int effBeginSetProgram
Definition: aeffectx.h:130
bool IsGraphicalUI() override
Definition: VSTEffect.cpp:1779
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
const int effBeginLoadBank
Definition: aeffectx.h:136
int GetProcessLevel()
Definition: VSTEffect.cpp:2424
#define RTLD_DEEPBIND
int32_t version
Definition: aeffectx.h:296
bool RealtimeSuspend() override
Definition: VSTEffect.cpp:1505
static int b64decode(const wxString &in, void *out)
Definition: VSTEffect.cpp:2681
EffectHostInterface * mHost
Definition: VSTEffect.cpp:765
const int effStartProcess
Definition: aeffectx.h:141
void SetString(int opcode, const wxString &str, int index=0)
Definition: VSTEffect.cpp:2539
bool Initialize() override
Definition: VSTEffect.cpp:354
void EndVerticalLay()
void callSetChunk(bool isPgm, int len, void *buf)
Definition: VSTEffect.cpp:2588
long mXMLVersion
Definition: VSTEffect.h:373
bool HasOptions() override
Definition: VSTEffect.cpp:1955
wxString mPath
Definition: VSTEffect.h:272
EffectType GetType() override
Definition: VSTEffect.cpp:1235
const int effBeginLoadProgram
Definition: aeffectx.h:138
EffectUIHostInterface * mUIHost
Definition: VSTEffect.h:358
bool Parse(XMLTagHandler *baseHandler, const wxString &fname)
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:18
const int audioMasterIdle
Definition: aeffectx.h:37
ComponentInterfaceSymbol GetFamilyId() override
Definition: VSTEffect.cpp:254
VSTControl * mControl
Definition: VSTEffect.h:362
EffectDefinitionInterface is a ComponentInterface that additionally tracks flag-functions for interac...
static bool IsGoodString(const wxString &str)
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:122
ArrayOf< wxStaticText * > mNames
Definition: VSTEffect.h:365
void operator()(void *) const
Definition: VSTEffect.cpp:1103
ComponentInterfaceSymbol GetSymbol() override
Definition: VSTEffect.cpp:329
const int effGetProgram
Definition: aeffectx.h:94
int GetString(wxString &outstr, int opcode, int index=0)
Definition: VSTEffect.cpp:2517
const int audioMasterNeedIdle
Definition: aeffectx.h:48
Wrapper to output XML data to files.
Definition: XMLWriter.h:74
bool mHasPower
Definition: VSTEffect.h:339
EffectType GetType() override
Definition: VSTEffect.cpp:259
virtual double GetDuration()=0
const int effSetChunk
Definition: aeffectx.h:112
int timeSigDenominator
Definition: aeffectx.h:327
wxString mVendor
Definition: VSTEffect.h:281
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
bool IsInteractive() override
Definition: VSTEffect.cpp:264
bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap=NULL) override
Definition: VSTEffect.cpp:1388
void SetHostUI(EffectUIHostInterface *host) override
Definition: VSTEffect.cpp:1741
int numInputs
Definition: aeffectx.h:276
const int effIdentify
Definition: aeffectx.h:110
const int effFlagsProgramChunks
Definition: aeffectx.h:88
wxString mPath
Definition: VSTEffect.h:427
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the Shuttle cla...
bool IsDefault() override
Definition: VSTEffect.cpp:1266
virtual ~VSTEffect()
Definition: VSTEffect.cpp:1174
ModuleHandle mModule
Definition: VSTEffect.h:291
virtual bool GetSharedConfig(const wxString &group, const wxString &key, wxString &value, const wxString &defval)=0
wxString GetPath() override
Definition: VSTEffect.cpp:324
void RemoveHandler()
Definition: VSTEffect.cpp:2759
unsigned mBlockSize
Definition: VSTEffect.h:336
VSTEffect * mMaster
Definition: VSTEffect.h:349
unsigned GetChannelCount()
Definition: VSTEffect.cpp:1438
virtual bool GetPrivateConfig(const wxString &group, const wxString &key, wxString &value, const wxString &defval)=0
wxString mChunk
Definition: VSTEffect.h:372
const int effGetVstVersion
Definition: aeffectx.h:128
DECLARE_BUILTIN_MODULE(VSTBuiltin)
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:72
bool mInteractive
Definition: VSTEffect.h:284
bool SupportsRealtime() override
Definition: VSTEffect.cpp:1276
size_t RealtimeProcess(int group, float **inbuf, float **outbuf, size_t numSamples) override
Definition: VSTEffect.cpp:1535
const int audioMasterUpdateDisplay
Definition: aeffectx.h:77
wxTextCtrl * TieNumericTextBox(const wxString &Prompt, WrappedType &WrappedRef, const int nChars)
bool ValidateUI() override
Definition: VSTEffect.cpp:1784
bool GetParameters(wxString &parms)
bool PopulateUI(wxWindow *parent) override
Definition: VSTEffect.cpp:1746
const int effSetBlockSize
Definition: aeffectx.h:103
int min(int a, int b)
VSTEffectTimer(VSTEffect *effect)
Definition: VSTEffect.cpp:893
const int audioMasterWantMidi
Definition: aeffectx.h:40
#define AUDACITY_RELEASE
Definition: Audacity.h:64
wxSizerItem * mContainer
Definition: VSTEffect.h:359
Definition: VSTEffect.cpp:162
void HandleXMLEndTag(const wxChar *tag) override
Definition: VSTEffect.cpp:3911
wxString mDescription
Definition: VSTEffect.cpp:294
wxString GetVersion() override
Definition: VSTEffect.cpp:244
void SaveFXB(const wxFileName &fn)
Definition: VSTEffect.cpp:3436
bool mWantsEditIdle
Definition: VSTEffect.h:341
enum ChannelName * ChannelNames
const int kEffectMagic
Definition: aeffectx.h:144
#define CCONST(a, b, c, d)
Definition: aeffectx.h:29
void BuildPlain()
Definition: VSTEffect.cpp:2819
bool LoadParameters(const wxString &group)
Definition: VSTEffect.cpp:2298
DECLARE_MODULE_ENTRY(AudacityModule)
Definition: VSTEffect.cpp:138
size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) override
Definition: VSTEffect.cpp:1423
int32_t numElements
Definition: aeffectx.h:358
void SetChannelCount(unsigned numChannels)
Definition: VSTEffect.cpp:1443
wxString mName
Definition: VSTEffect.h:280
const int effFlagsCanReplacing
Definition: aeffectx.h:87
const int audioMasterCanDo
Definition: aeffectx.h:72
double tempo
Definition: aeffectx.h:317
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const int effGetVendorVersion
Definition: aeffectx.h:124
sampleCount GetLatency() override
Definition: VSTEffect.cpp:1365
bool HideUI() override
Definition: VSTEffect.cpp:1799
void Automate(int index, float value)
Definition: VSTEffect.cpp:2492
const int audioMasterIOChanged
Definition: aeffectx.h:47
wxString mVersion
Definition: VSTEffect.cpp:293
bool RealtimeProcessEnd() override
Definition: VSTEffect.cpp:1551
std::vector< int > GetEffectIDs()
Definition: VSTEffect.cpp:2277
static wxString SelectFile(Operation op, const wxString &message, const wxString &default_path, const wxString &default_filename, const wxString &default_extension, const wxString &wildcard, int flags, wxWindow *parent)
Definition: FileNames.cpp:427
VSTEffect(const wxString &path, VSTEffect *master=NULL)
Definition: VSTEffect.cpp:1126
static wxString b64encode(const void *in, int len)
Definition: VSTEffect.cpp:2641
void OnSlider(wxCommandEvent &evt)
Definition: VSTEffect.cpp:3020
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
const int effGetPlugCategory
Definition: aeffectx.h:119
wxDialog * mDialog
Definition: VSTEffect.h:356
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:426
bool SaveUserPreset(const wxString &name) override
Definition: VSTEffect.cpp:1693
const int effSetSampleRate
Definition: aeffectx.h:102
IMPLEMENT_DYNAMIC_CLASS(VSTSubEntry, wxModule)
void OnSizeWindow(wxCommandEvent &evt)
Definition: VSTEffect.cpp:2998
int GetMidiOutCount() override
Definition: VSTEffect.cpp:1349
int32_t pluginVersion
Definition: aeffectx.h:357
bool LoadFXP(const wxFileName &fn)
Definition: VSTEffect.cpp:3201
wxString GetVersion() override
Definition: VSTEffect.cpp:1203
void DeleteInstance(ComponentInterface *instance) override
Definition: VSTEffect.cpp:688
EffectHostInterface is a decorator of a EffectUIClientInterface. It adds virtual (abstract) functions...
ComponentInterfaceSymbol GetSymbol() override
Definition: VSTEffect.cpp:234
wxCheckBox * TieCheckBox(const wxString &Prompt, WrappedType &WrappedRef)
const int effEndSetProgram
Definition: aeffectx.h:132
void reinit(Integral count)
Definition: MemoryX.h:165
const wxChar * name
Definition: Distortion.cpp:94
intptr_t callDispatcher(int opcode, int index, intptr_t value, void *ptr, float opt) override
Definition: VSTEffect.cpp:2547
AEffect * mAEffect
Definition: VSTEffect.h:329
wxString GetDescription() override
Definition: VSTEffect.cpp:345
bool ShowInterface(wxWindow *parent, bool forceModal=false) override
Definition: VSTEffect.cpp:1588
ArrayOf< wxStaticText * > mDisplays
Definition: VSTEffect.h:367
bool CloseUI() override
Definition: VSTEffect.cpp:1804
int mTimerGuard
Definition: VSTEffect.h:346
#define AUDACITY_MODLEVEL
Definition: Audacity.h:66
void ImportPresets() override
Definition: VSTEffect.cpp:1894
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:422
virtual wxDialog * CreateUI(wxWindow *parent, EffectUIClientInterface *client)=0
bool IsInteractive() override
Definition: VSTEffect.cpp:1261
const int effGetChunk
Definition: aeffectx.h:111
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:771
const int audioMasterGetVendorString
Definition: aeffectx.h:67
void HandleXMLContent(const wxString &content) override
Definition: VSTEffect.cpp:3941
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:146
ComponentInterfaceSymbol GetVendor() override
Definition: VSTEffect.cpp:239
bool RealtimeAddProcessor(unsigned numChannels, float sampleRate) override
Definition: VSTEffect.cpp:1456
wxString mVendor
Definition: VSTEffect.cpp:292
int mProcessLevel
Definition: VSTEffect.h:338
bool AutoRegisterPlugins(PluginManagerInterface &pm) override
Definition: VSTEffect.cpp:381
void SizeWindow(int w, int h)
Definition: VSTEffect.cpp:2465
int initialDelay
Definition: aeffectx.h:284
float(* getParameter)(AEffect *, int)
Definition: aeffectx.h:270
XMLTagHandler * HandleXMLChild(const wxChar *tag) override
Definition: VSTEffect.cpp:3949
double sampleRate
Definition: aeffectx.h:311
AEffect *(* vstPluginMain)(audioMasterCallback audioMaster)
Definition: VSTEffect.cpp:936
bool ProcessFinalize() override
Definition: VSTEffect.cpp:1414
void SetSampleRate(double rate) override
Definition: VSTEffect.cpp:1360
VSTEffectsModule(ModuleManagerInterface *moduleManager, const wxString *path)
Definition: VSTEffect.cpp:305
virtual bool SetPrivateConfig(const wxString &group, const wxString &key, const wxString &value)=0
double samplePos
Definition: aeffectx.h:309
bool RealtimeInitialize() override
Definition: VSTEffect.cpp:1448
int flags
Definition: aeffectx.h:280
const int effFlagsIsSynth
Definition: aeffectx.h:89
std::function< const PluginID &(ModuleInterface *, ComponentInterface *) > RegistrationCallback
const int audioMasterEndEdit
Definition: aeffectx.h:79
const int audioMasterGetProductString
Definition: aeffectx.h:68
float GetSampleRate()
Definition: VSTEffect.cpp:2419
int32_t version
Definition: aeffectx.h:355
std::unique_ptr< T, Destroyer< T >> Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:361
bool IsReady() override
Definition: VSTEffect.cpp:1383
const int audioMasterGetTime
Definition: aeffectx.h:41
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
void SaveXML(const wxFileName &fn)
Definition: VSTEffect.cpp:3613
static float reinterpretAsFloat(uint32_t x)
Definition: VSTEffect.cpp:107
wxString GetErrorStr()
ArrayOf< wxSlider * > mSliders
Definition: VSTEffect.h:366
END_EVENT_TABLE()
wxString mPath
Definition: VSTEffect.cpp:290
int mBufferDelay
Definition: VSTEffect.h:334
size_t mUserBlockSize
Definition: VSTEffect.h:279
bool GetAutomationParameters(CommandParameters &parms) override
Definition: VSTEffect.cpp:1631
virtual void SetDuration(double seconds)=0
void ShowOptions() override
Definition: VSTEffect.cpp:1960
static void OnSize(wxSizeEvent &evt)
Definition: VSTEffect.cpp:2763
bool IsPluginValid(const wxString &path, bool bFast) override
Definition: VSTEffect.cpp:672
void SetBorder(int Border)
Definition: ShuttleGui.h:286
wxString GetPath() override
Definition: VSTEffect.cpp:1188
VstTimeInfo mTimeInfo
Definition: VSTEffect.h:331
size_t SetBlockSize(size_t maxBlockSize) override
Definition: VSTEffect.cpp:1354
wxArrayString FileExtensions() override
Definition: VSTEffect.cpp:366
void Close()
static const wxChar cset[]
Definition: VSTEffect.cpp:2638
bool mWantsIdle
Definition: VSTEffect.h:340
bool IsLegacy() override
Definition: VSTEffect.cpp:1271
bool LoadFactoryPreset(int id) override
Definition: VSTEffect.cpp:1716
bool SupportsAutomation() override
Definition: VSTEffect.cpp:1281
const int effCanBeAutomated
Definition: aeffectx.h:115
void ExportPresets() override
Definition: VSTEffect.cpp:1839
wxString GetVersion() override
Definition: VSTEffect.cpp:339
std::unique_ptr< char, ModuleDeleter > ModuleHandle
Definition: VSTEffect.h:267
int timeSigNumerator
Definition: aeffectx.h:325
void callProcessReplacing(float **inputs, float **outputs, int sampleframes)
Definition: VSTEffect.cpp:2555
bool IsLegacy() override
Definition: VSTEffect.cpp:274
bool SupportsAutomation() override
Definition: VSTEffect.cpp:284
virtual NumericFormatId GetDurationFormat()=0
EffectUIHostInterface has nothing in it. It is provided so that an Effect can call SetHostUI passing ...
wxString InstallPath() override
Definition: VSTEffect.cpp:373
DEFINE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW)
#define VSTPLUGINTYPE
Definition: VSTEffect.h:27
ComponentInterface provides name / vendor / version functions to identify plugins. It is what makes a class a plug-in. Additionally it provides an optional parameter definitions function, for those components such as commands, effects and (soon) preference pagess that define parameters.
const int effGetParamName
Definition: aeffectx.h:101
size_t GetTailSize() override
Definition: VSTEffect.cpp:1378
bool mAutomatable
Definition: VSTEffect.h:277
int mVersion
Definition: VSTEffect.h:283
FloatBuffers mMasterOut
Definition: VSTEffect.h:352
bool SetHost(EffectHostInterface *host) override
Definition: VSTEffect.cpp:1290
bool IsDefault() override
Definition: VSTEffect.cpp:269
EVT_COMMAND(OnTogglePinnedStateID, wxEVT_COMMAND_BUTTON_CLICKED, AdornedRulerPanel::OnTogglePinnedState) class AdornedRulerPanel
const int kVstTempoValid
Definition: aeffectx.h:150
unsigned mAudioIns
Definition: VSTEffect.h:273
const int kVstNanosValid
Definition: aeffectx.h:148
void StartVerticalLay(int iProp=1)
wxWindow * mParent
Definition: VSTEffect.h:357