Audacity 3.2.0
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
28#include "VSTEffect.h"
29#include "ModuleManager.h"
30#include "SampleCount.h"
31
32#include "../../widgets/ProgressDialog.h"
33
34#if 0
35#if defined(BUILDING_AUDACITY)
36#include "../../PlatformCompatibility.h"
37
38// Make the main function private
39#else
40#define USE_VST 1
41#endif
42#endif
43
44#if USE_VST
45
46#include <limits.h>
47#include <stdio.h>
48
49#include <wx/setup.h> // for wxUSE_* macros
50#include <wx/dynlib.h>
51#include <wx/app.h>
52#include <wx/defs.h>
53#include <wx/buffer.h>
54#include <wx/busyinfo.h>
55#include <wx/button.h>
56#include <wx/combobox.h>
57#include <wx/file.h>
58#include <wx/filename.h>
59#include <wx/imaglist.h>
60#include <wx/listctrl.h>
61#include <wx/log.h>
62#include <wx/module.h>
63#include <wx/process.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"
87#include "../../SelectFile.h"
88#include "../../ShuttleGui.h"
89#include "../../widgets/valnum.h"
90#include "../../widgets/AudacityMessageBox.h"
91#include "../../widgets/NumericTextCtrl.h"
92#include "XMLFileReader.h"
93#include "Base64.h"
94
95#if wxUSE_ACCESSIBILITY
96#include "../../widgets/WindowAccessible.h"
97#endif
98
99#include "ConfigInterface.h"
100
101#include <cstring>
102
103// Put this inclusion last. On Linux it makes some unfortunate pollution of
104// preprocessor macro name space that interferes with other headers.
105#if defined(__WXOSX__)
106#include "VSTControlOSX.h"
107#elif defined(__WXMSW__)
108#include "VSTControlMSW.h"
109#elif defined(__WXGTK__)
110#include "VSTControlGTK.h"
111#endif
112
113static float reinterpretAsFloat(uint32_t x)
114{
115 static_assert(sizeof(float) == sizeof(uint32_t), "Cannot reinterpret uint32_t to float since sizes are different.");
116 float f;
117 std::memcpy(&f, &x, sizeof(float));
118 return f;
119}
120
121static uint32_t reinterpretAsUint32(float f)
122{
123 static_assert(sizeof(float) == sizeof(uint32_t), "Cannot reinterpret float to uint32_t since sizes are different.");
124
125 uint32_t x;
126 std::memcpy(&x, &f, sizeof(uint32_t));
127 return x;
128}
129
130// NOTE: To debug the subprocess, use wxLogDebug and, on Windows, Debugview
131// from TechNet (Sysinternals).
132
133// ============================================================================
134//
135// Module registration entry point
136//
137// This is the symbol that Audacity looks for when the module is built as a
138// dynamic library.
139//
140// When the module is builtin to Audacity, we use the same function, but it is
141// declared static so as not to clash with other builtin modules.
142//
143// ============================================================================
145{
146 // Create our effects module and register
147 // Trust the module manager not to leak this
148 return safenew VSTEffectsModule();
149}
150
151// ============================================================================
152//
153// Register this as a builtin module
154//
155// We also take advantage of the fact that wxModules are initialized before
156// the wxApp::OnInit() method is called. We check to see if Audacity was
157// executed to scan a VST effect in a different process.
158//
159// ============================================================================
161
162
168
170{
171}
172
174{
175}
176
177// ============================================================================
178// ComponentInterface implementation
179// ============================================================================
180
182{
183 return {};
184}
185
187{
188 return XO("VST Effects");
189}
190
192{
193 return XO("The Audacity Team");
194}
195
197{
198 // This "may" be different if this were to be maintained as a separate DLL
199 return AUDACITY_VERSION_STRING;
200}
201
203{
204 return XO("Adds the ability to use VST effects in Audacity.");
205}
206
207// ============================================================================
208// PluginProvider implementation
209// ============================================================================
210
212{
213 // Nothing to do here
214 return true;
215}
216
218{
219 // Nothing to do here
220 return;
221}
222
224{
225#if USE_VST
226 return VSTPLUGINTYPE;
227#else
228 return {};
229#endif
230}
231
233{
234 static FileExtensions result{{ _T("vst") }};
235 return result;
236}
237
239{
240 // Not yet ready for VST drag-and-drop...
241 // return FileNames::PlugInDir();
242
243 return {};
244}
245
247{
248}
249
251{
252 FilePaths pathList;
253 FilePaths files;
254
255 // Check for the VST_PATH environment variable
256 wxString vstpath = wxString::FromUTF8(getenv("VST_PATH"));
257 if (!vstpath.empty())
258 {
259 wxStringTokenizer tok(vstpath, wxPATH_SEP);
260 while (tok.HasMoreTokens())
261 {
262 pathList.push_back(tok.GetNextToken());
263 }
264 }
265
266#if defined(__WXMAC__)
267#define VSTPATH wxT("/Library/Audio/Plug-Ins/VST")
268
269 // Look in ~/Library/Audio/Plug-Ins/VST and /Library/Audio/Plug-Ins/VST
270 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + VSTPATH);
271 pathList.push_back(VSTPATH);
272
273 // Recursively search all paths for Info.plist files. This will identify all
274 // bundles.
275 pm.FindFilesInPathList(wxT("Info.plist"), pathList, files, true);
276
277 // Remove the 'Contents/Info.plist' portion of the names
278 for (size_t i = 0; i < files.size(); i++)
279 {
280 files[i] = wxPathOnly(wxPathOnly(files[i]));
281 if (!files[i].EndsWith(wxT(".vst")))
282 {
283 files.erase( files.begin() + i-- );
284 }
285 }
286
287#elif defined(__WXMSW__)
288
289 TCHAR dpath[MAX_PATH];
290 TCHAR tpath[MAX_PATH];
291 DWORD len;
292
293 // Try HKEY_CURRENT_USER registry key first
294 len = WXSIZEOF(tpath);
295 if (SHRegGetUSValue(wxT("Software\\VST"),
296 wxT("VSTPluginsPath"),
297 NULL,
298 tpath,
299 &len,
300 FALSE,
301 NULL,
302 0) == ERROR_SUCCESS)
303 {
304 tpath[len] = 0;
305 dpath[0] = 0;
306 ExpandEnvironmentStrings(tpath, dpath, WXSIZEOF(dpath));
307 pathList.push_back(dpath);
308 }
309
310 // Then try HKEY_LOCAL_MACHINE registry key
311 len = WXSIZEOF(tpath);
312 if (SHRegGetUSValue(wxT("Software\\VST"),
313 wxT("VSTPluginsPath"),
314 NULL,
315 tpath,
316 &len,
317 TRUE,
318 NULL,
319 0) == ERROR_SUCCESS)
320 {
321 tpath[len] = 0;
322 dpath[0] = 0;
323 ExpandEnvironmentStrings(tpath, dpath, WXSIZEOF(dpath));
324 pathList.push_back(dpath);
325 }
326
327 // Add the default path last
328 dpath[0] = 0;
329 ExpandEnvironmentStrings(wxT("%ProgramFiles%\\Steinberg\\VSTPlugins"),
330 dpath,
331 WXSIZEOF(dpath));
332 pathList.push_back(dpath);
333
334 // Recursively scan for all DLLs
335 pm.FindFilesInPathList(wxT("*.dll"), pathList, files, true);
336
337#else
338
339 // Nothing specified in the VST_PATH environment variable...provide defaults
340 if (vstpath.empty())
341 {
342 // We add this "non-default" one
343 pathList.push_back(wxT(LIBDIR) wxT("/vst"));
344
345 // These are the defaults used by other hosts
346 pathList.push_back(wxT("/usr/lib/vst"));
347 pathList.push_back(wxT("/usr/local/lib/vst"));
348 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".vst"));
349 }
350
351 // Recursively scan for all shared objects
352 pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
353
354#endif
355
356 return { files.begin(), files.end() };
357}
358
360 const PluginPath & path, TranslatableString &errMsg,
361 const RegistrationCallback &callback)
362{
363
364 VSTEffect effect(path);
365 if(effect.InitializePlugin())
366 {
367 auto effectIDs = effect.GetEffectIDs();
368 if(effectIDs.empty())
369 //Each VST plugin path in Audacity should have id(index) part in it
370 effectIDs.push_back(0);
371
372 for(auto id : effectIDs)
373 {
374 //Subsequent VSTEffect::Load may seem like overhead, but we need
375 //to initialize EffectDefinitionInterface part, which includes
376 //properly formatted plugin path
377 VSTEffect subeffect(wxString::Format("%s;%d", path, id), &effect);
378 if(callback)
379 callback(this, &subeffect);
380 }
381 return effectIDs.size();
382 }
383 errMsg = XO("Could not load the library");
384 return 0;
385}
386
387bool VSTEffectsModule::IsPluginValid(const PluginPath & path, bool bFast)
388{
389 if( bFast )
390 return true;
391 wxString realPath = path.BeforeFirst(wxT(';'));
392 return wxFileName::FileExists(realPath) || wxFileName::DirExists(realPath);
393}
394
395std::unique_ptr<ComponentInterface>
397{
398 // Acquires a resource for the application.
399 // For us, the ID is simply the path to the effect
400 auto result = std::make_unique<VSTEffect>(path);
401 result->InitializePlugin();
402 return result;
403}
404
405// ============================================================================
406// ModuleEffectInterface implementation
407// ============================================================================
408
409// ============================================================================
410// VSTEffectsModule implementation
411// ============================================================================
412
414//
415// Dialog for configuring latency, buffer size and graphics mode for a
416// VST effect.
417//
420{
421public:
422 VSTEffectOptionsDialog(wxWindow * parent, EffectDefinitionInterface &effect);
423 virtual ~VSTEffectOptionsDialog();
424
426
427 void OnOk(wxCommandEvent & evt);
428
429private:
434
435 DECLARE_EVENT_TABLE()
436};
437
438BEGIN_EVENT_TABLE(VSTEffectOptionsDialog, wxDialogWrapper)
441
443 wxWindow * parent, EffectDefinitionInterface &effect)
444: wxDialogWrapper(parent, wxID_ANY, XO("VST Effect Options"))
445, mEffect{ effect }
446{
447 GetConfig(mEffect, PluginSettings::Shared, wxT("Options"),
448 wxT("BufferSize"), mBufferSize, 8192);
449 GetConfig(mEffect, PluginSettings::Shared, wxT("Options"),
450 wxT("UseLatency"), mUseLatency, true);
451 GetConfig(mEffect, PluginSettings::Shared, wxT("Options"),
452 wxT("UseGUI"), mUseGUI, true);
453
454 ShuttleGui S(this, eIsCreating);
455 PopulateOrExchange(S);
456}
457
459{
460}
461
463{
464 S.SetBorder(5);
465 S.StartHorizontalLay(wxEXPAND, 1);
466 {
467 S.StartVerticalLay(false);
468 {
469 S.StartStatic(XO("Buffer Size"));
470 {
471 S.AddVariableText( XO(
472"The buffer size controls the number of samples sent to the effect "
473"on each iteration. Smaller values will cause slower processing and "
474"some effects require 8192 samples or less to work properly. However "
475"most effects can accept large buffers and using them will greatly "
476"reduce processing time."),
477 false, 0, 650);
478
479 S.StartHorizontalLay(wxALIGN_LEFT);
480 {
481 wxTextCtrl *t;
482 t = S.Validator<IntegerValidator<int>>(
483 &mBufferSize, NumValidatorStyle::DEFAULT, 8, 1048576 * 1)
484 .MinSize( { 100, -1 } )
485 .TieNumericTextBox(XXO("&Buffer Size (8 to 1048576 samples):"),
487 12);
488 }
489 S.EndHorizontalLay();
490 }
491 S.EndStatic();
492
493 S.StartStatic(XO("Latency Compensation"));
494 {
495 S.AddVariableText( XO(
496"As part of their processing, some VST effects must delay returning "
497"audio to Audacity. When not compensating for this delay, you will "
498"notice that small silences have been inserted into the audio. "
499"Enabling this option will provide that compensation, but it may "
500"not work for all VST effects."),
501 false, 0, 650);
502
503 S.StartHorizontalLay(wxALIGN_LEFT);
504 {
505 S.TieCheckBox(XXO("Enable &compensation"),
507 }
508 S.EndHorizontalLay();
509 }
510 S.EndStatic();
511
512 S.StartStatic(XO("Graphical Mode"));
513 {
514 S.AddVariableText( XO(
515"Most VST effects have a graphical interface for setting parameter values."
516" A basic text-only method is also available. "
517" Reopen the effect for this to take effect."),
518 false, 0, 650);
519 S.TieCheckBox(XXO("Enable &graphical interface"),
520 mUseGUI);
521 }
522 S.EndStatic();
523 }
524 S.EndVerticalLay();
525 }
526 S.EndHorizontalLay();
527
528 S.AddStandardButtons();
529
530 Layout();
531 Fit();
532 Center();
533}
534
535void VSTEffectOptionsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
536{
537 if (!Validate())
538 {
539 return;
540 }
541
544
546 wxT("BufferSize"), mBufferSize);
548 wxT("UseLatency"), mUseLatency);
550 wxT("UseGUI"), mUseGUI);
551
552 EndModal(wxID_OK);
553}
554
562class VSTEffectTimer final : public wxTimer
563{
564public:
566 : wxTimer(),
567 mEffect(effect)
568 {
569 }
570
572 {
573 }
574
575 void Notify()
576 {
577 mEffect->OnTimer();
578 }
579
580private:
582};
583
585//
586// VSTEffect
587//
589enum
590{
591 ID_Duration = 20000,
592 ID_Sliders = 21000,
593};
594
596DEFINE_LOCAL_EVENT_TYPE(EVT_UPDATEDISPLAY);
597
598BEGIN_EVENT_TABLE(VSTEffect, wxEvtHandler)
599 EVT_COMMAND_RANGE(ID_Sliders, ID_Sliders + 999, wxEVT_COMMAND_SLIDER_UPDATED, VSTEffect::OnSlider)
600
601 // Events from the audioMaster callback
602 EVT_COMMAND(wxID_ANY, EVT_SIZEWINDOW, VSTEffect::OnSizeWindow)
604
605// Needed to support shell plugins...sucks, but whatcha gonna do???
606intptr_t VSTEffect::mCurrentEffectID;
607
609
610intptr_t VSTEffect::AudioMaster(AEffect * effect,
611 int32_t opcode,
612 int32_t index,
613 intptr_t value,
614 void * ptr,
615 float opt)
616{
617 VSTEffect *vst = (effect ? (VSTEffect *) effect->ptr2 : NULL);
618
619 // Handles operations during initialization...before VSTEffect has had a
620 // chance to set its instance pointer.
621 switch (opcode)
622 {
624 return (intptr_t) 2400;
625
627 return mCurrentEffectID;
628
630 strcpy((char *) ptr, "Audacity Team"); // Do not translate, max 64 + 1 for null terminator
631 return 1;
632
634 strcpy((char *) ptr, "Audacity"); // Do not translate, max 64 + 1 for null terminator
635 return 1;
636
638 return (intptr_t) (AUDACITY_VERSION << 24 |
639 AUDACITY_RELEASE << 16 |
640 AUDACITY_REVISION << 8 |
641 AUDACITY_MODLEVEL);
642
643 // Some (older) effects depend on an effIdle call when requested. An
644 // example is the Antress Modern plugins which uses the call to update
645 // the editors display when the program (preset) changes.
647 if (vst)
648 {
649 vst->NeedIdle();
650 return 1;
651 }
652 return 0;
653
654 // We would normally get this if the effect editor is dipslayed and something "major"
655 // has changed (like a program change) instead of multiple automation calls.
656 // Since we don't do anything with the parameters while the editor is displayed,
657 // there's no need for us to do anything.
659 if (vst)
660 {
661 vst->UpdateDisplay();
662 return 1;
663 }
664 return 0;
665
666 // Return the current time info.
668 if (vst)
669 {
670 return (intptr_t) vst->GetTimeInfo();
671 }
672 return 0;
673
674 // Inputs, outputs, or initial delay has changed...all we care about is initial delay.
676 if (vst)
677 {
678 vst->SetBufferDelay(effect->initialDelay);
679 return 1;
680 }
681 return 0;
682
684 if (vst)
685 {
686 return (intptr_t) vst->GetSampleRate();
687 }
688 return 0;
689
690 case audioMasterIdle:
691 wxYieldIfNeeded();
692 return 1;
693
695 if (vst)
696 {
697 return vst->GetProcessLevel();
698 }
699 return 0;
700
702 return kVstLangEnglish;
703
704 // We always replace, never accumulate
706 return 1;
707
708 // Resize the window to accommodate the effect size
710 if (vst)
711 {
712 vst->SizeWindow(index, value);
713 }
714 return 1;
715
716 case audioMasterCanDo:
717 {
718 char *s = (char *) ptr;
719 if (strcmp(s, "acceptIOChanges") == 0 ||
720 strcmp(s, "sendVstTimeInfo") == 0 ||
721 strcmp(s, "startStopProcess") == 0 ||
722 strcmp(s, "shellCategory") == 0 ||
723 strcmp(s, "sizeWindow") == 0)
724 {
725 return 1;
726 }
727
728#if defined(VST_DEBUG)
729#if defined(__WXMSW__)
730 wxLogDebug(wxT("VST canDo: %s"), wxString::FromAscii((char *)ptr));
731#else
732 wxPrintf(wxT("VST canDo: %s\n"), wxString::FromAscii((char *)ptr));
733#endif
734#endif
735
736 return 0;
737 }
738
741 return 0;
742
744 if (vst)
745 {
746 vst->Automate(index, opt);
747 }
748 return 0;
749
750 // We're always connected (sort of)
752
753 // We don't do MIDI yet
756
757 // Don't need to see any messages about these
758 return 0;
759 }
760
761#if defined(VST_DEBUG)
762#if defined(__WXMSW__)
763 wxLogDebug(wxT("vst: %p opcode: %d index: %d value: %p ptr: %p opt: %f user: %p"),
764 effect, (int) opcode, (int) index, (void *) value, ptr, opt, vst);
765#else
766 wxPrintf(wxT("vst: %p opcode: %d index: %d value: %p ptr: %p opt: %f user: %p\n"),
767 effect, (int) opcode, (int) index, (void *) value, ptr, opt, vst);
768#endif
769#endif
770
771 return 0;
772}
773
774#if !defined(__WXMSW__)
775void VSTEffect::ModuleDeleter::operator() (void* p) const
776{
777 if (p)
778 dlclose(p);
779}
780#endif
781
782#if defined(__WXMAC__)
784{
785 if (mpHandle)
786 CFBundleCloseBundleResourceMap(mpHandle, mNum);
787 mpHandle = nullptr;
788 mNum = 0;
789}
790#endif
791
793: mPath(path),
794 mMaster(master)
795{
796 mModule = NULL;
797 mAEffect = NULL;
798
799 mTimer = std::make_unique<VSTEffectTimer>(this);
800 mTimerGuard = 0;
801
802 mInteractive = false;
803 mAudioIns = 0;
804 mAudioOuts = 0;
805 mMidiIns = 0;
806 mMidiOuts = 0;
807 mSampleRate = 44100;
808 mBlockSize = mUserBlockSize = 8192;
809 mBufferDelay = 0;
810 mProcessLevel = 1; // in GUI thread
811 mHasPower = false;
812 mWantsIdle = false;
813 mWantsEditIdle = false;
814 mUseLatency = true;
815 mReady = false;
816
817 memset(&mTimeInfo, 0, sizeof(mTimeInfo));
818 mTimeInfo.samplePos = 0.0;
819 mTimeInfo.sampleRate = 44100.0; // this is a bogus value, but it's only for the display
820 mTimeInfo.nanoSeconds = wxGetUTCTimeMillis().ToDouble();
821 mTimeInfo.tempo = 120.0;
825
826 // UI
827
828 mGui = false;
829 mContainer = NULL;
830
831 // If we're a slave then go ahead a load immediately
832 if (mMaster)
833 {
834 Load();
835 }
836}
837
839{
840 Unload();
841}
842
843// ============================================================================
844// ComponentInterface Implementation
845// ============================================================================
846
848{
849 return mPath;
850}
851
853{
854 return mName;
855}
856
858{
859 return { mVendor };
860}
861
862wxString VSTEffect::GetVersion() const
863{
864 wxString version;
865
866 bool skipping = true;
867 for (int i = 0, s = 0; i < 4; i++, s += 8)
868 {
869 int dig = (mVersion >> s) & 0xff;
870 if (dig != 0 || !skipping)
871 {
872 version += !skipping ? wxT(".") : wxT("");
873 version += wxString::Format(wxT("%d"), dig);
874 skipping = false;
875 }
876 }
877
878 return version;
879}
880
882{
883 // VST does have a product string opcode and some effects return a short
884 // description, but most do not or they just return the name again. So,
885 // try to provide some sort of useful information.
886 return XO("Audio In: %d, Audio Out: %d").Format( mAudioIns, mAudioOuts );
887}
888
889// ============================================================================
890// EffectDefinitionInterface Implementation
891// ============================================================================
892
894{
895 if (mAudioIns == 0 && mAudioOuts == 0 && mMidiIns == 0 && mMidiOuts == 0)
896 {
897 return EffectTypeTool;
898 }
899
900 if (mAudioIns == 0 && mMidiIns == 0)
901 {
902 return EffectTypeGenerate;
903 }
904
905 if (mAudioOuts == 0 && mMidiOuts == 0)
906 {
907 return EffectTypeAnalyze;
908 }
909
910 return EffectTypeProcess;
911}
912
913
915{
916 return VSTPLUGINTYPE;
917}
918
920{
921 return mInteractive;
922}
923
925{
926 return false;
927}
928
930{
931 // TODO reenable after achieving statelessness
932 return false;
933 //return GetType() == EffectTypeProcess;
934}
935
937{
938 return mAutomatable;
939}
940
942{
943 if (!mAEffect)
944 {
945 Load();
946 }
947
948 if (!mAEffect)
949 {
950 return false;
951 }
952
953 // If we have a master then there's no need to load settings since the master will feed
954 // us everything we need.
955 if (mMaster)
956 {
957 return true;
958 }
959
960 return true;
961}
962
963std::shared_ptr<EffectInstance> VSTEffect::MakeInstance() const
964{
965 return const_cast<VSTEffect*>(this)->DoMakeInstance();
966}
967
968std::shared_ptr<EffectInstance> VSTEffect::DoMakeInstance()
969{
970 int userBlockSize;
971 GetConfig(*this, PluginSettings::Shared, wxT("Options"),
972 wxT("BufferSize"), userBlockSize, 8192);
973 mUserBlockSize = std::max( 1, userBlockSize );
974 GetConfig(*this, PluginSettings::Shared, wxT("Options"),
975 wxT("UseLatency"), mUseLatency, true);
977 return std::make_shared<Instance>(*this);
978}
979
981{
982 return mAudioIns;
983}
984
986{
987 return mAudioOuts;
988}
989
991{
992 return mMidiIns;
993}
994
996{
997 return mMidiOuts;
998}
999
1000size_t VSTEffect::SetBlockSize(size_t maxBlockSize)
1001{
1002 mBlockSize = std::min( maxBlockSize, mUserBlockSize );
1003 return mBlockSize;
1004}
1005
1007{
1008 return mBlockSize;
1009}
1010
1012{
1013 mSampleRate = (float) rate;
1014}
1015
1017{
1018 if (mUseLatency)
1019 {
1020 // ??? Threading issue ???
1021 auto delay = mBufferDelay;
1022 mBufferDelay = 0;
1023 return delay;
1024 }
1025
1026 return 0;
1027}
1028
1030{
1031 return mReady;
1032}
1033
1036{
1037 return DoProcessInitialize(count, names);
1038}
1039
1041{
1042 // Initialize time info
1043 memset(&mTimeInfo, 0, sizeof(mTimeInfo));
1045 mTimeInfo.nanoSeconds = wxGetUTCTimeMillis().ToDouble();
1046 mTimeInfo.tempo = 120.0;
1050
1051 // Set processing parameters...power must be off for this
1054
1055 // Turn on the power
1056 PowerOn();
1057
1058 // Set the initial buffer delay
1060
1061 mReady = true;
1062
1063 return true;
1064}
1065
1067{
1068 mReady = false;
1069
1070 PowerOff();
1071
1072 return true;
1073}
1074
1076 const float *const *inBlock, float *const *outBlock, size_t blockLen)
1077{
1078 // Only call the effect if there's something to do...some do not like zero-length block
1079 if (blockLen)
1080 {
1081 // Go let the plugin moleste the samples
1082 callProcessReplacing(inBlock, outBlock, blockLen);
1083
1084 // And track the position
1085 mTimeInfo.samplePos += (double) blockLen;
1086 }
1087
1088 return blockLen;
1089}
1090
1092{
1093 return mNumChannels;
1094}
1095
1096void VSTEffect::SetChannelCount(unsigned numChannels)
1097{
1098 mNumChannels = numChannels;
1099}
1100
1102{
1103 return ProcessInitialize(settings, 0, nullptr);
1104}
1105
1107 EffectSettings &settings, unsigned numChannels, float sampleRate)
1108{
1109 mSlaves.push_back(std::make_unique<VSTEffect>(mPath, this));
1110 VSTEffect *const slave = mSlaves.back().get();
1111
1112 slave->SetBlockSize(mBlockSize);
1113 slave->SetChannelCount(numChannels);
1114 slave->SetSampleRate(sampleRate);
1115
1116 int clen = 0;
1118 {
1119 void *chunk = NULL;
1120
1121 clen = (int) callDispatcher(effGetChunk, 1, 0, &chunk, 0.0); // get master's chunk, for the program only
1122 if (clen != 0)
1123 {
1124 slave->callSetChunk(true, clen, chunk); // copy state to slave, for the program only
1125 }
1126 }
1127
1128 if (clen == 0)
1129 {
1130 callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
1131
1132 for (int i = 0; i < mAEffect->numParams; i++)
1133 {
1134 slave->callSetParameter(i, callGetParameter(i));
1135 }
1136
1137 callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
1138 }
1139
1140 return slave->ProcessInitialize(settings, 0, nullptr);
1141}
1142
1144{
1145return GuardedCall<bool>([&]{
1146 for (const auto &slave : mSlaves)
1147 slave->ProcessFinalize();
1148 mSlaves.clear();
1149
1150 return ProcessFinalize();
1151});
1152}
1153
1155{
1156 PowerOff();
1157
1158 for (const auto &slave : mSlaves)
1159 slave->PowerOff();
1160
1161 return true;
1162}
1163
1165{
1166return GuardedCall<bool>([&]{
1167 PowerOn();
1168
1169 for (const auto &slave : mSlaves)
1170 slave->PowerOn();
1171
1172 return true;
1173});
1174}
1175
1177{
1178 return true;
1179}
1180
1182 const float *const *inbuf, float *const *outbuf, size_t numSamples)
1183{
1184 wxASSERT(numSamples <= mBlockSize);
1185 return mSlaves[group]->ProcessBlock(settings, inbuf, outbuf, numSamples);
1186}
1187
1189{
1190 return true;
1191}
1192
1220 wxWindow &parent, wxDialog &dialog, bool forceModal)
1221{
1222 // mProcessLevel = 1; // in GUI thread
1223
1224 // Set some defaults since some VSTs need them...these will be reset when
1225 // normal or realtime processing begins
1226 if (!IsReady())
1227 {
1228 mSampleRate = 44100;
1229 mBlockSize = 8192;
1230 // No settings here! Is this call really needed? It appears to be
1231 // redundant with later calls that reach process initialization from the
1232 // dialog, either with the Apply or Play buttons.
1233 DoProcessInitialize(0, nullptr);
1234 }
1235
1236 // Remember the dialog with a weak pointer, but don't control its lifetime
1237 mDialog = &dialog;
1238 mDialog->CentreOnParent();
1239
1240 if (SupportsRealtime() && !forceModal)
1241 {
1242 mDialog->Show();
1243 return 0;
1244 }
1245
1246 return mDialog->ShowModal();
1247}
1248
1250 const EffectSettings &, CommandParameters & parms) const
1251{
1252 for (int i = 0; i < mAEffect->numParams; i++)
1253 {
1254 wxString name = GetString(effGetParamName, i);
1255 if (name.empty())
1256 {
1257 name.Printf(wxT("parm_%d"), i);
1258 }
1259
1260 float value = callGetParameter(i);
1261 if (!parms.Write(name, value))
1262 {
1263 return false;
1264 }
1265 }
1266
1267 return true;
1268}
1269
1271 const CommandParameters & parms, EffectSettings &settings) const
1272{
1273 constCallDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
1274 for (int i = 0; i < mAEffect->numParams; i++)
1275 {
1276 wxString name = GetString(effGetParamName, i);
1277 if (name.empty())
1278 {
1279 name.Printf(wxT("parm_%d"), i);
1280 }
1281
1282 double d = 0.0;
1283 if (!parms.Read(name, &d))
1284 {
1285 return false;
1286 }
1287
1288 if (d >= -1.0 && d <= 1.0)
1289 {
1290 const_cast<VSTEffect*>(this)->callSetParameter(i, d);
1291 for (const auto &slave : mSlaves)
1292 slave->callSetParameter(i, d);
1293 }
1294 }
1295 constCallDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
1296
1297 return true;
1298}
1299
1301 const RegistryPath & name, EffectSettings &settings) const
1302{
1303 // To do: externalize state so const_cast isn't needed
1304 return const_cast<VSTEffect*>(this)->DoLoadUserPreset(name, settings);
1305}
1306
1309{
1311 {
1312 return false;
1313 }
1314
1316
1317 return true;
1318}
1319
1321 const RegistryPath & name, const EffectSettings &settings) const
1322{
1323 return SaveParameters(name, settings);
1324}
1325
1327{
1328 RegistryPaths progs;
1329
1330 // Some plugins, like Guitar Rig 5, only report 128 programs while they have hundreds. While
1331 // I was able to come up with a hack in the Guitar Rig case to gather all of the program names
1332 // it would not let me set a program outside of the first 128.
1333 if (mVstVersion >= 2)
1334 {
1335 for (int i = 0; i < mAEffect->numPrograms; i++)
1336 {
1337 progs.push_back(GetString(effGetProgramNameIndexed, i));
1338 }
1339 }
1340
1341 return progs;
1342}
1343
1345{
1346 // To do: externalize state so const_cast isn't needed
1347 return const_cast<VSTEffect*>(this)->DoLoadFactoryPreset(id);
1348}
1349
1351{
1352 callSetProgram(id);
1353
1355
1356 return true;
1357}
1358
1359// ============================================================================
1360// EffectUIClientInterface implementation
1361// ============================================================================
1362
1363std::unique_ptr<EffectUIValidator> VSTEffect::PopulateUI(ShuttleGui &S,
1365{
1366 auto parent = S.GetParent();
1367 mDialog = static_cast<wxDialog *>(wxGetTopLevelParent(parent));
1368 mParent = parent;
1369
1370 mParent->PushEventHandler(this);
1371
1372 // Determine if the VST editor is supposed to be used or not
1373 GetConfig(*this, PluginSettings::Shared, wxT("Options"),
1374 wxT("UseGUI"),
1375 mGui,
1376 true);
1377 mGui = mAEffect->flags & effFlagsHasEditor ? mGui : false;
1378
1379 // Must use the GUI editor if parameters aren't provided
1380 if (mAEffect->numParams == 0)
1381 {
1382 mGui = true;
1383 }
1384
1385 // Build the appropriate dialog type
1386 if (mGui)
1387 {
1388 BuildFancy();
1389 }
1390 else
1391 {
1392 BuildPlain(access);
1393 }
1394
1395 return std::make_unique<DefaultEffectUIValidator>(*this, access);
1396}
1397
1399{
1400 return mGui;
1401}
1402
1404{
1405 if (GetType() == EffectTypeGenerate)
1406 settings.extra.SetDuration(mDuration->GetValue());
1407
1408 return true;
1409}
1410
1412{
1413#ifdef __WXMAC__
1414#ifdef __WX_EVTLOOP_BUSY_WAITING__
1415 wxEventLoop::SetBusyWaiting(false);
1416#endif
1417 mControl->Close();
1418#endif
1419
1420 mParent->RemoveEventHandler(this);
1421
1422 PowerOff();
1423
1424 NeedEditIdle(false);
1425
1426 RemoveHandler();
1427
1428 mNames.reset();
1429 mSliders.reset();
1430 mDisplays.reset();
1431 mLabels.reset();
1432
1433 mParent = NULL;
1434 mDialog = NULL;
1435
1436 return true;
1437}
1438
1440{
1441 return true;
1442}
1443
1444// Throws exceptions rather than reporting errors.
1446{
1447 wxString path;
1448
1449 // Ask the user for the real name
1450 //
1451 // Passing a valid parent will cause some effects dialogs to malfunction
1452 // upon returning from the SelectFile().
1453 path = SelectFile(FileNames::Operation::Presets,
1454 XO("Save VST Preset As:"),
1455 wxEmptyString,
1456 wxT("preset"),
1457 wxT("xml"),
1458 {
1459 { XO("Standard VST bank file"), { wxT("fxb") }, true },
1460 { XO("Standard VST program file"), { wxT("fxp") }, true },
1461 { XO("Audacity VST preset file"), { wxT("xml") }, true },
1462 },
1463 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
1464 NULL);
1465
1466 // User canceled...
1467 if (path.empty())
1468 {
1469 return;
1470 }
1471
1472 wxFileName fn(path);
1473 wxString ext = fn.GetExt();
1474 if (ext.CmpNoCase(wxT("fxb")) == 0)
1475 {
1476 SaveFXB(fn);
1477 }
1478 else if (ext.CmpNoCase(wxT("fxp")) == 0)
1479 {
1480 SaveFXP(fn);
1481 }
1482 else if (ext.CmpNoCase(wxT("xml")) == 0)
1483 {
1484 // may throw
1485 SaveXML(fn);
1486 }
1487 else
1488 {
1489 // This shouldn't happen, but complain anyway
1491 XO("Unrecognized file extension."),
1492 XO("Error Saving VST Presets"),
1493 wxOK | wxCENTRE,
1494 mParent);
1495
1496 return;
1497 }
1498}
1499
1500//
1501// Load an "fxb", "fxp" or Audacuty "xml" file
1502//
1503// Based on work by Sven Giermann
1504//
1506{
1507 wxString path;
1508
1509 // Ask the user for the real name
1510 path = SelectFile(FileNames::Operation::Presets,
1511 XO("Load VST Preset:"),
1512 wxEmptyString,
1513 wxT("preset"),
1514 wxT("xml"),
1515 { {
1516 XO("VST preset files"),
1517 { wxT("fxb"), wxT("fxp"), wxT("xml") },
1518 true
1519 } },
1520 wxFD_OPEN | wxRESIZE_BORDER,
1521 mParent);
1522
1523 // User canceled...
1524 if (path.empty())
1525 {
1526 return;
1527 }
1528
1529 wxFileName fn(path);
1530 wxString ext = fn.GetExt();
1531 bool success = false;
1532 if (ext.CmpNoCase(wxT("fxb")) == 0)
1533 {
1534 success = LoadFXB(fn);
1535 }
1536 else if (ext.CmpNoCase(wxT("fxp")) == 0)
1537 {
1538 success = LoadFXP(fn);
1539 }
1540 else if (ext.CmpNoCase(wxT("xml")) == 0)
1541 {
1542 success = LoadXML(fn);
1543 }
1544 else
1545 {
1546 // This shouldn't happen, but complain anyway
1548 XO("Unrecognized file extension."),
1549 XO("Error Loading VST Presets"),
1550 wxOK | wxCENTRE,
1551 mParent);
1552
1553 return;
1554 }
1555
1556 if (!success)
1557 {
1559 XO("Unable to load presets file."),
1560 XO("Error Loading VST Presets"),
1561 wxOK | wxCENTRE,
1562 mParent);
1563
1564 return;
1565 }
1566
1568
1569 return;
1570}
1571
1573{
1574 return true;
1575}
1576
1578{
1579 VSTEffectOptionsDialog dlg(mParent, *this);
1580 if (dlg.ShowModal())
1581 {
1582 // Reinitialize configuration settings
1583 int userBlockSize;
1584 GetConfig(*this, PluginSettings::Shared, wxT("Options"),
1585 wxT("BufferSize"), userBlockSize, 8192);
1586 mUserBlockSize = std::max( 1, userBlockSize );
1587 GetConfig(*this, PluginSettings::Shared, wxT("Options"),
1588 wxT("UseLatency"), mUseLatency, true);
1589 }
1590}
1591
1592// ============================================================================
1593// VSTEffect implementation
1594// ============================================================================
1595
1597{
1598 vstPluginMain pluginMain;
1599 bool success = false;
1600
1601 long effectID = 0;
1602 wxString realPath = mPath.BeforeFirst(wxT(';'));
1603 mPath.AfterFirst(wxT(';')).ToLong(&effectID);
1604 mCurrentEffectID = (intptr_t) effectID;
1605
1606 mModule = NULL;
1607 mAEffect = NULL;
1608
1609#if defined(__WXMAC__)
1610 // Start clean
1611 mBundleRef.reset();
1612
1614
1615 // Convert the path to a CFSTring
1616 wxCFStringRef path(realPath);
1617
1618 // Create the bundle using the URL
1619 BundleHandle bundleRef{ CFBundleCreate(kCFAllocatorDefault,
1620 // Convert the path to a URL
1621 CF_ptr<CFURLRef>{
1622 CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
1623 path, kCFURLPOSIXPathStyle, true)
1624 }.get()
1625 )};
1626
1627 // Bail if the bundle wasn't created
1628 if (!bundleRef)
1629 return false;
1630
1631
1632 // Convert back to path
1633 UInt8 exePath[PLATFORM_MAX_PATH];
1634 Boolean good = CFURLGetFileSystemRepresentation(
1635 // Retrieve a reference to the executable
1636 CF_ptr<CFURLRef>{ CFBundleCopyExecutableURL(bundleRef.get()) }.get(),
1637 true, exePath, sizeof(exePath)
1638 );
1639
1640 // Bail if we couldn't resolve the executable path
1641 if (good == FALSE)
1642 return false;
1643
1644 // Attempt to open it
1645 mModule.reset((char*)dlopen((char *) exePath, RTLD_NOW | RTLD_LOCAL));
1646 if (!mModule)
1647 return false;
1648
1649 // Try to locate the NEW plugin entry point
1650 pluginMain = (vstPluginMain) dlsym(mModule.get(), "VSTPluginMain");
1651
1652 // If not found, try finding the old entry point
1653 if (pluginMain == NULL)
1654 {
1655 pluginMain = (vstPluginMain) dlsym(mModule.get(), "main_macho");
1656 }
1657
1658 // Must not be a VST plugin
1659 if (pluginMain == NULL)
1660 {
1661 mModule.reset();
1662 return false;
1663 }
1664
1665 // Need to keep the bundle reference around so we can map the
1666 // resources.
1667 mBundleRef = std::move(bundleRef);
1668
1669 // Open the resource map ... some plugins (like GRM Tools) need this.
1671 mBundleRef.get(), CFBundleOpenBundleResourceMap(mBundleRef.get())
1672 };
1673
1674#elif defined(__WXMSW__)
1675
1676 {
1677 wxLogNull nolog;
1678
1679 // Try to load the library
1680 auto lib = std::make_unique<wxDynamicLibrary>(realPath);
1681 if (!lib)
1682 return false;
1683
1684 // Bail if it wasn't successful
1685 if (!lib->IsLoaded())
1686 return false;
1687
1688 // Try to find the entry point, while suppressing error messages
1689 pluginMain = (vstPluginMain) lib->GetSymbol(wxT("VSTPluginMain"));
1690 if (pluginMain == NULL)
1691 {
1692 pluginMain = (vstPluginMain) lib->GetSymbol(wxT("main"));
1693 if (pluginMain == NULL)
1694 return false;
1695 }
1696
1697 // Save the library reference
1698 mModule = std::move(lib);
1699 }
1700
1701#else
1702
1703 // Attempt to load it
1704 //
1705 // Spent a few days trying to figure out why some VSTs where running okay and
1706 // others were hit or miss. The cause was that we export all of Audacity's
1707 // symbols and some of the loaded libraries were picking up Audacity's and
1708 // not their own.
1709 //
1710 // So far, I've only seen this issue on Linux, but we might just be getting
1711 // lucky on the Mac and Windows. The sooner we stop exporting everything
1712 // the better.
1713 //
1714 // To get around the problem, I just added the RTLD_DEEPBIND flag to the load
1715 // and that "basically" puts Audacity last when the loader needs to resolve
1716 // symbols.
1717 //
1718 // Once we define a proper external API, the flags can be removed.
1719#ifndef RTLD_DEEPBIND
1720#define RTLD_DEEPBIND 0
1721#endif
1722 ModuleHandle lib {
1723 (char*) dlopen((const char *)wxString(realPath).ToUTF8(),
1724 RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND)
1725 };
1726 if (!lib)
1727 {
1728 return false;
1729 }
1730
1731 // Try to find the entry point, while suppressing error messages
1732 pluginMain = (vstPluginMain) dlsym(lib.get(), "VSTPluginMain");
1733 if (pluginMain == NULL)
1734 {
1735 pluginMain = (vstPluginMain) dlsym(lib.get(), "main");
1736 if (pluginMain == NULL)
1737 return false;
1738 }
1739
1740 // Save the library reference
1741 mModule = std::move(lib);
1742
1743#endif
1744
1745 // Initialize the plugin
1746 try
1747 {
1748 mAEffect = pluginMain(VSTEffect::AudioMaster);
1749 }
1750 catch (...)
1751 {
1752 wxLogMessage(wxT("VST plugin initialization failed\n"));
1753 mAEffect = NULL;
1754 }
1755
1756 // Was it successful?
1757 if (mAEffect)
1758 {
1759 // Save a reference to ourselves
1760 //
1761 // Note: Some hosts use "user" and some use "ptr2/resvd2". It might
1762 // be worthwhile to check if user is NULL before using it and
1763 // then falling back to "ptr2/resvd2".
1764 mAEffect->ptr2 = this;
1765
1766 // Give the plugin an initial sample rate and blocksize
1767 callDispatcher(effSetSampleRate, 0, 0, NULL, 48000.0);
1768 callDispatcher(effSetBlockSize, 0, 512, NULL, 0);
1769
1770 // Ask the plugin to identify itself...might be needed for older plugins
1771 callDispatcher(effIdentify, 0, 0, NULL, 0);
1772
1773 // Open the plugin
1774 callDispatcher(effOpen, 0, 0, NULL, 0.0);
1775
1776 // Get the VST version the plugin understands
1778
1779 // Set it again in case plugin ignored it before the effOpen
1780 callDispatcher(effSetSampleRate, 0, 0, NULL, 48000.0);
1781 callDispatcher(effSetBlockSize, 0, 512, NULL, 0);
1782
1783 // Ensure that it looks like a plugin and can deal with ProcessReplacing
1784 // calls. Also exclude synths for now.
1785 if (mAEffect->magic == kEffectMagic &&
1788 {
1789 if (mVstVersion >= 2)
1790 {
1792 if (mName.length() == 0)
1793 {
1795 }
1796 }
1797 if (mName.length() == 0)
1798 {
1799 mName = wxFileName{realPath}.GetName();
1800 }
1801
1802 if (mVstVersion >= 2)
1803 {
1805 mVersion = wxINT32_SWAP_ON_LE(callDispatcher(effGetVendorVersion, 0, 0, NULL, 0));
1806 }
1807 if (mVersion == 0)
1808 {
1809 mVersion = wxINT32_SWAP_ON_LE(mAEffect->version);
1810 }
1811
1813 {
1814 mInteractive = true;
1815 }
1816
1819
1820 mMidiIns = 0;
1821 mMidiOuts = 0;
1822
1823 // Check to see if parameters can be automated. This isn't a guarantee
1824 // since it could be that the effect simply doesn't support the opcode.
1825 mAutomatable = false;
1826 for (int i = 0; i < mAEffect->numParams; i++)
1827 {
1828 if (callDispatcher(effCanBeAutomated, 0, i, NULL, 0.0))
1829 {
1830 mAutomatable = true;
1831 break;
1832 }
1833 }
1834
1835 // Make sure we start out with a valid program selection
1836 // I've found one plugin (SoundHack +morphfilter) that will
1837 // crash Audacity when saving the initial default parameters
1838 // with this.
1839 callSetProgram(0);
1840
1841 // Pretty confident that we're good to go
1842 success = true;
1843 }
1844 }
1845
1846 if (!success)
1847 {
1848 Unload();
1849 }
1850
1851 return success;
1852}
1853
1855{
1856 if (mDialog)
1857 {
1858 CloseUI();
1859 }
1860
1861 if (mAEffect)
1862 {
1863 // Turn the power off
1864 PowerOff();
1865
1866 // Finally, close the plugin
1867 callDispatcher(effClose, 0, 0, NULL, 0.0);
1868 mAEffect = NULL;
1869 }
1870
1871 if (mModule)
1872 {
1873#if defined(__WXMAC__)
1874 mResource.reset();
1875 mBundleRef.reset();
1876#endif
1877
1878 mModule.reset();
1879 mAEffect = NULL;
1880 }
1881}
1882
1883std::vector<int> VSTEffect::GetEffectIDs()
1884{
1885 std::vector<int> effectIDs;
1886
1887 // Are we a shell?
1889 {
1890 char name[64];
1891 int effectID;
1892
1893 effectID = (int) callDispatcher(effShellGetNextPlugin, 0, 0, &name, 0);
1894 while (effectID)
1895 {
1896 effectIDs.push_back(effectID);
1897 effectID = (int) callDispatcher(effShellGetNextPlugin, 0, 0, &name, 0);
1898 }
1899 }
1900
1901 return effectIDs;
1902}
1903
1905 const RegistryPath & group, EffectSettings &settings)
1906{
1907 wxString value;
1908
1910 GetConfig(*this, PluginSettings::Private, group, wxT("UniqueID"),
1911 info.pluginUniqueID, info.pluginUniqueID);
1912 GetConfig(*this, PluginSettings::Private, group, wxT("Version"),
1913 info.pluginVersion, info.pluginVersion);
1914 GetConfig(*this, PluginSettings::Private, group, wxT("Elements"),
1915 info.numElements, info.numElements);
1916
1917 if ((info.pluginUniqueID != mAEffect->uniqueID) ||
1918 (info.pluginVersion != mAEffect->version) ||
1919 (info.numElements != mAEffect->numParams))
1920 {
1921 return false;
1922 }
1923
1924 if (GetConfig(*this,
1925 PluginSettings::Private, group, wxT("Chunk"), value, wxEmptyString))
1926 {
1927 ArrayOf<char> buf{ value.length() / 4 * 3 };
1928
1929 int len = Base64::Decode(value, buf.get());
1930 if (len)
1931 {
1932 callSetChunk(true, len, buf.get(), &info);
1933 }
1934
1935 return true;
1936 }
1937
1938 wxString parms;
1939 if (!GetConfig(*this,
1940 PluginSettings::Private, group, wxT("Parameters"), parms, wxEmptyString))
1941 {
1942 return false;
1943 }
1944
1946 if (!eap.SetParameters(parms))
1947 {
1948 return false;
1949 }
1950
1951 return LoadSettings(eap, settings);
1952}
1953
1955 const RegistryPath & group, const EffectSettings &settings) const
1956{
1957 SetConfig(*this, PluginSettings::Private, group, wxT("UniqueID"),
1959 SetConfig(*this, PluginSettings::Private, group, wxT("Version"),
1960 mAEffect->version);
1961 SetConfig(*this, PluginSettings::Private, group, wxT("Elements"),
1963
1965 {
1966 void *chunk = NULL;
1967 int clen = (int) constCallDispatcher(effGetChunk, 1, 0, &chunk, 0.0);
1968 if (clen <= 0)
1969 {
1970 return false;
1971 }
1972
1973 SetConfig(*this, PluginSettings::Private, group, wxT("Chunk"),
1974 Base64::Encode(chunk, clen));
1975 return true;
1976 }
1977
1979 if (!SaveSettings(settings, eap))
1980 {
1981 return false;
1982 }
1983
1984 wxString parms;
1985 if (!eap.GetParameters(parms))
1986 {
1987 return false;
1988 }
1989
1990 return SetConfig(*this, PluginSettings::Private,
1991 group, wxT("Parameters"), parms);
1992}
1993
1995{
1996 wxRecursionGuard guard(mTimerGuard);
1997
1998 // Ignore it if we're recursing
1999 if (guard.IsInside())
2000 {
2001 return;
2002 }
2003
2004 if (mVstVersion >= 2 && mWantsIdle)
2005 {
2006 int ret = callDispatcher(effIdle, 0, 0, NULL, 0.0);
2007 if (!ret)
2008 {
2009 mWantsIdle = false;
2010 }
2011 }
2012
2013 if (mWantsEditIdle)
2014 {
2015 callDispatcher(effEditIdle, 0, 0, NULL, 0.0);
2016 }
2017}
2018
2020{
2021 mWantsIdle = true;
2022 mTimer->Start(100);
2023}
2024
2026{
2027 mWantsEditIdle = state;
2028 mTimer->Start(100);
2029}
2030
2032{
2033 mTimeInfo.nanoSeconds = wxGetUTCTimeMillis().ToDouble();
2034 return &mTimeInfo;
2035}
2036
2038{
2039 return mTimeInfo.sampleRate;
2040}
2041
2043{
2044 return mProcessLevel;
2045}
2046
2048{
2049 if (!mHasPower)
2050 {
2051 // Turn the power on
2052 callDispatcher(effMainsChanged, 0, 1, NULL, 0.0);
2053
2054 // Tell the effect we're going to start processing
2055 if (mVstVersion >= 2)
2056 {
2057 callDispatcher(effStartProcess, 0, 0, NULL, 0.0);
2058 }
2059
2060 // Set state
2061 mHasPower = true;
2062 }
2063}
2064
2066{
2067 if (mHasPower)
2068 {
2069 // Tell the effect we're going to stop processing
2070 if (mVstVersion >= 2)
2071 {
2072 callDispatcher(effStopProcess, 0, 0, NULL, 0.0);
2073 }
2074
2075 // Turn the power off
2076 callDispatcher(effMainsChanged, 0, 0, NULL, 0.0);
2077
2078 // Set state
2079 mHasPower = false;
2080 }
2081}
2082
2083void VSTEffect::SizeWindow(int w, int h)
2084{
2085 // Queue the event to make the resizes smoother
2086 if (mParent)
2087 {
2088 wxCommandEvent sw(EVT_SIZEWINDOW);
2089 sw.SetInt(w);
2090 sw.SetExtraLong(h);
2091 mParent->GetEventHandler()->AddPendingEvent(sw);
2092 }
2093
2094 return;
2095}
2096
2098{
2099#if 0
2100 // Tell the dialog to refresh effect information
2101 if (mParent)
2102 {
2103 wxCommandEvent ud(EVT_UPDATEDISPLAY);
2104 mParent->GetEventHandler()->AddPendingEvent(ud);
2105 }
2106#endif
2107 return;
2108}
2109
2110void VSTEffect::Automate(int index, float value)
2111{
2112 // Just ignore it if we're a slave
2113 if (mMaster)
2114 {
2115 return;
2116 }
2117
2118 for (const auto &slave : mSlaves)
2119 slave->callSetParameter(index, value);
2120
2121 return;
2122}
2123
2125{
2126 // We do not support negative delay
2127 if (samples >= 0 && mUseLatency)
2128 {
2129 mBufferDelay = samples;
2130 }
2131
2132 return;
2133}
2134
2135int VSTEffect::GetString(wxString & outstr, int opcode, int index) const
2136{
2137 char buf[256];
2138
2139 memset(buf, 0, sizeof(buf));
2140
2141 // Assume we are passed a read-only dispatcher function code
2142 constCallDispatcher(opcode, index, 0, buf, 0.0);
2143
2144 outstr = wxString::FromUTF8(buf);
2145
2146 return 0;
2147}
2148
2149wxString VSTEffect::GetString(int opcode, int index) const
2150{
2151 wxString str;
2152
2153 GetString(str, opcode, index);
2154
2155 return str;
2156}
2157
2158void VSTEffect::SetString(int opcode, const wxString & str, int index)
2159{
2160 char buf[256];
2161 strcpy(buf, str.Left(255).ToUTF8());
2162
2163 callDispatcher(opcode, index, 0, buf, 0.0);
2164}
2165
2166intptr_t VSTEffect::callDispatcher(int opcode,
2167 int index, intptr_t value, void *ptr, float opt)
2168{
2169 // Needed since we might be in the dispatcher when the timer pops
2170 wxCRIT_SECT_LOCKER(locker, mDispatcherLock);
2171 return mAEffect->dispatcher(mAEffect, opcode, index, value, ptr, opt);
2172}
2173
2175 int index, intptr_t value, void *ptr, float opt) const
2176{
2177 // Assume we are passed a read-only dispatcher function code
2178 return const_cast<VSTEffect*>(this)
2179 ->callDispatcher(opcode, index, value, ptr, opt);
2180}
2181
2182void VSTEffect::callProcessReplacing(const float *const *inputs,
2183 float *const *outputs, int sampleframes)
2184{
2186 const_cast<float**>(inputs),
2187 const_cast<float**>(outputs), sampleframes);
2188}
2189
2190float VSTEffect::callGetParameter(int index) const
2191{
2192 return mAEffect->getParameter(mAEffect, index);
2193}
2194
2195void VSTEffect::callSetParameter(int index, float value)
2196{
2197 if (mVstVersion == 0 || callDispatcher(effCanBeAutomated, 0, index, NULL, 0.0))
2198 {
2199 mAEffect->setParameter(mAEffect, index, value);
2200
2201 for (const auto &slave : mSlaves)
2202 slave->callSetParameter(index, value);
2203 }
2204}
2205
2207{
2208 callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
2209
2210 callDispatcher(effSetProgram, 0, index, NULL, 0.0);
2211 for (const auto &slave : mSlaves)
2212 slave->callSetProgram(index);
2213
2214 callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
2215}
2216
2217void VSTEffect::callSetChunk(bool isPgm, int len, void *buf)
2218{
2219 VstPatchChunkInfo info;
2220
2221 memset(&info, 0, sizeof(info));
2222 info.version = 1;
2226
2227 callSetChunk(isPgm, len, buf, &info);
2228}
2229
2230void VSTEffect::callSetChunk(bool isPgm, int len, void *buf, VstPatchChunkInfo *info)
2231{
2232 if (isPgm)
2233 {
2234 // Ask the effect if this is an acceptable program
2235 if (callDispatcher(effBeginLoadProgram, 0, 0, info, 0.0) == -1)
2236 {
2237 return;
2238 }
2239 }
2240 else
2241 {
2242 // Ask the effect if this is an acceptable bank
2243 if (callDispatcher(effBeginLoadBank, 0, 0, info, 0.0) == -1)
2244 {
2245 return;
2246 }
2247 }
2248
2249 callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
2250 callDispatcher(effSetChunk, isPgm ? 1 : 0, len, buf, 0.0);
2251 callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
2252
2253 for (const auto &slave : mSlaves)
2254 slave->callSetChunk(isPgm, len, buf, info);
2255}
2256
2258{
2259}
2260
2261static void OnSize(wxSizeEvent & evt)
2262{
2263 evt.Skip();
2264
2265 // Once the parent dialog reaches its final size as indicated by
2266 // a non-default minimum size, we set the maximum size to match.
2267 // This is a bit of a hack to prevent VSTs GUI windows from resizing
2268 // there's no real reason to allow it. But, there should be a better
2269 // way of handling it.
2270 wxWindow *w = (wxWindow *) evt.GetEventObject();
2271 wxSize sz = w->GetMinSize();
2272
2273 if (sz != wxDefaultSize)
2274 {
2275 w->SetMaxSize(sz);
2276 }
2277}
2278
2280{
2281 // Turn the power on...some effects need this when the editor is open
2282 PowerOn();
2283
2284 auto control = Destroy_ptr<VSTControl>{ safenew VSTControl };
2285 if (!control)
2286 {
2287 return;
2288 }
2289
2290 if (!control->Create(mParent, this))
2291 {
2292 return;
2293 }
2294
2295 {
2296 auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
2297
2298 mainSizer->Add((mControl = control.release()), 0, wxALIGN_CENTER);
2299
2300 mParent->SetMinSize(wxDefaultSize);
2301 mParent->SetSizer(mainSizer.release());
2302 }
2303
2304 NeedEditIdle(true);
2305
2306 mDialog->Bind(wxEVT_SIZE, OnSize);
2307
2308#ifdef __WXMAC__
2309#ifdef __WX_EVTLOOP_BUSY_WAITING__
2310 wxEventLoop::SetBusyWaiting(true);
2311#endif
2312#endif
2313
2314 return;
2315}
2316
2318{
2319 wxASSERT(mParent); // To justify safenew
2320 wxScrolledWindow *const scroller = safenew wxScrolledWindow(mParent,
2321 wxID_ANY,
2322 wxDefaultPosition,
2323 wxDefaultSize,
2324 wxVSCROLL | wxTAB_TRAVERSAL);
2325
2326 {
2327 auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
2328
2329 // Try to give the window a sensible default/minimum size
2330 scroller->SetMinSize(wxSize(wxMax(600, mParent->GetSize().GetWidth() * 2 / 3),
2331 mParent->GetSize().GetHeight() / 2));
2332 scroller->SetScrollRate(0, 20);
2333
2334 // This fools NVDA into not saying "Panel" when the dialog gets focus
2335 scroller->SetName(wxT("\a"));
2336 scroller->SetLabel(wxT("\a"));
2337
2338 mainSizer->Add(scroller, 1, wxEXPAND | wxALL, 5);
2339 mParent->SetSizer(mainSizer.release());
2340 }
2341
2342 mNames.reinit(static_cast<size_t>(mAEffect->numParams));
2343 mSliders.reinit(static_cast<size_t>(mAEffect->numParams));
2344 mDisplays.reinit(static_cast<size_t>(mAEffect->numParams));
2345 mLabels.reinit(static_cast<size_t>(mAEffect->numParams));
2346
2347 {
2348 auto paramSizer = std::make_unique<wxStaticBoxSizer>(wxVERTICAL, scroller, _("Effect Settings"));
2349
2350 {
2351 auto gridSizer = std::make_unique<wxFlexGridSizer>(4, 0, 0);
2352 gridSizer->AddGrowableCol(1);
2353
2354 // Add the duration control for generators
2355 if (GetType() == EffectTypeGenerate)
2356 {
2357 wxControl *item = safenew wxStaticText(scroller, 0, _("Duration:"));
2358 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
2359 auto &extra = access.Get().extra;
2361 NumericTextCtrl(scroller, ID_Duration,
2363 extra.GetDurationFormat(),
2364 extra.GetDuration(),
2367 .AutoPos(true));
2368 mDuration->SetName( XO("Duration") );
2369 gridSizer->Add(mDuration, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
2370 gridSizer->Add(1, 1, 0);
2371 gridSizer->Add(1, 1, 0);
2372 }
2373
2374 // Find the longest parameter name.
2375 int namew = 0;
2376 int w;
2377 int h;
2378 for (int i = 0; i < mAEffect->numParams; i++)
2379 {
2380 wxString text = GetString(effGetParamName, i);
2381
2382 if (text.Right(1) != wxT(':'))
2383 {
2384 text += wxT(':');
2385 }
2386
2387 scroller->GetTextExtent(text, &w, &h);
2388 if (w > namew)
2389 {
2390 namew = w;
2391 }
2392 }
2393
2394 scroller->GetTextExtent(wxT("HHHHHHHH"), &w, &h);
2395
2396 for (int i = 0; i < mAEffect->numParams; i++)
2397 {
2398 mNames[i] = safenew wxStaticText(scroller,
2399 wxID_ANY,
2400 wxEmptyString,
2401 wxDefaultPosition,
2402 wxSize(namew, -1),
2403 wxALIGN_RIGHT | wxST_NO_AUTORESIZE);
2404 gridSizer->Add(mNames[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
2405
2406 mSliders[i] = safenew wxSliderWrapper(scroller,
2407 ID_Sliders + i,
2408 0,
2409 0,
2410 1000,
2411 wxDefaultPosition,
2412 wxSize(200, -1));
2413 gridSizer->Add(mSliders[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);
2414#if wxUSE_ACCESSIBILITY
2415 // so that name can be set on a standard control
2416 mSliders[i]->SetAccessible(safenew WindowAccessible(mSliders[i]));
2417#endif
2418
2419 mDisplays[i] = safenew wxStaticText(scroller,
2420 wxID_ANY,
2421 wxEmptyString,
2422 wxDefaultPosition,
2423 wxSize(w, -1),
2424 wxALIGN_RIGHT | wxST_NO_AUTORESIZE);
2425 gridSizer->Add(mDisplays[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
2426
2427 mLabels[i] = safenew wxStaticText(scroller,
2428 wxID_ANY,
2429 wxEmptyString,
2430 wxDefaultPosition,
2431 wxSize(w, -1),
2432 wxALIGN_LEFT | wxST_NO_AUTORESIZE);
2433 gridSizer->Add(mLabels[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5);
2434 }
2435
2436 paramSizer->Add(gridSizer.release(), 1, wxEXPAND | wxALL, 5);
2437 }
2438 scroller->SetSizer(paramSizer.release());
2439 }
2440
2442
2443 mSliders[0]->SetFocus();
2444}
2445
2447{
2448 if (!mNames)
2449 {
2450 return;
2451 }
2452
2453 for (int i = 0; i < mAEffect->numParams; i++)
2454 {
2455 wxString text = GetString(effGetParamName, i);
2456
2457 text = text.Trim(true).Trim(false);
2458
2459 wxString name = text;
2460
2461 if (text.Right(1) != wxT(':'))
2462 {
2463 text += wxT(':');
2464 }
2465 mNames[i]->SetLabel(text);
2466
2467 // For some parameters types like on/off, setting the slider value has
2468 // a side effect that causes it to only move when the parameter changes
2469 // from off to on. However, this prevents changing the value using the
2470 // keyboard, so we skip the active slider if any.
2471 if (i != skip)
2472 {
2473 mSliders[i]->SetValue(callGetParameter(i) * 1000);
2474 }
2475 name = text;
2476
2477 text = GetString(effGetParamDisplay, i);
2478 if (text.empty())
2479 {
2480 text.Printf(wxT("%.5g"),callGetParameter(i));
2481 }
2482 mDisplays[i]->SetLabel(wxString::Format(wxT("%8s"), text));
2483 name += wxT(' ') + text;
2484
2485 text = GetString(effGetParamDisplay, i);
2486 if (!text.empty())
2487 {
2488 text.Printf(wxT("%-8s"), GetString(effGetParamLabel, i));
2489 mLabels[i]->SetLabel(wxString::Format(wxT("%8s"), text));
2490 name += wxT(' ') + text;
2491 }
2492
2493 mSliders[i]->SetName(name);
2494 }
2495}
2496
2497void VSTEffect::OnSizeWindow(wxCommandEvent & evt)
2498{
2499 if (!mControl)
2500 {
2501 return;
2502 }
2503
2504 mControl->SetMinSize(wxSize(evt.GetInt(), (int) evt.GetExtraLong()));
2505 mControl->SetSize(wxSize(evt.GetInt(), (int) evt.GetExtraLong()));
2506
2507 // DO NOT CHANGE THE ORDER OF THESE
2508 //
2509 // Guitar Rig (and possibly others) Cocoa VSTs can resize too large
2510 // if the bounds are unlimited.
2511 mDialog->SetMinSize(wxDefaultSize);
2512 mDialog->SetMaxSize(wxDefaultSize);
2513 mDialog->Layout();
2514 mDialog->SetMinSize(mDialog->GetBestSize());
2515 mDialog->SetMaxSize(mDialog->GetBestSize());
2516 mDialog->Fit();
2517}
2518
2519void VSTEffect::OnSlider(wxCommandEvent & evt)
2520{
2521 wxSlider *s = (wxSlider *) evt.GetEventObject();
2522 int i = s->GetId() - ID_Sliders;
2523
2524 callSetParameter(i, s->GetValue() / 1000.0);
2525
2527}
2528
2529bool VSTEffect::LoadFXB(const wxFileName & fn)
2530{
2531 bool ret = false;
2532
2533 // Try to open the file...will be closed automatically when method returns
2534 wxFFile f(fn.GetFullPath(), wxT("rb"));
2535 if (!f.IsOpened())
2536 {
2537 return false;
2538 }
2539
2540 // Allocate memory for the contents
2541 ArrayOf<unsigned char> data{ size_t(f.Length()) };
2542 if (!data)
2543 {
2545 XO("Unable to allocate memory when loading presets file."),
2546 XO("Error Loading VST Presets"),
2547 wxOK | wxCENTRE,
2548 mParent);
2549 return false;
2550 }
2551 unsigned char *bptr = data.get();
2552
2553 do
2554 {
2555 // Read in the whole file
2556 ssize_t len = f.Read((void *) bptr, f.Length());
2557 if (f.Error())
2558 {
2560 XO("Unable to read presets file."),
2561 XO("Error Loading VST Presets"),
2562 wxOK | wxCENTRE,
2563 mParent);
2564 break;
2565 }
2566
2567 // Most references to the data are via an "int" array
2568 int32_t *iptr = (int32_t *) bptr;
2569
2570 // Verify that we have at least enough for the header
2571 if (len < 156)
2572 {
2573 break;
2574 }
2575
2576 // Verify that we probably have an FX file
2577 if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K'))
2578 {
2579 break;
2580 }
2581
2582 // Ignore the size...sometimes it's there, other times it's zero
2583
2584 // Get the version and verify
2585 int version = wxINT32_SWAP_ON_LE(iptr[3]);
2586 if (version != 1 && version != 2)
2587 {
2588 break;
2589 }
2590
2591 VstPatchChunkInfo info =
2592 {
2593 1,
2594 wxINT32_SWAP_ON_LE(iptr[4]),
2595 wxINT32_SWAP_ON_LE(iptr[5]),
2596 wxINT32_SWAP_ON_LE(iptr[6]),
2597 ""
2598 };
2599
2600 // Ensure this program looks to belong to the current plugin
2601 if ((info.pluginUniqueID != mAEffect->uniqueID) &&
2602 (info.pluginVersion != mAEffect->version) &&
2603 (info.numElements != mAEffect->numPrograms))
2604 {
2605 break;
2606 }
2607
2608 // Get the number of programs
2609 int numProgs = info.numElements;
2610
2611 // Get the current program index
2612 int curProg = 0;
2613 if (version >= 2)
2614 {
2615 curProg = wxINT32_SWAP_ON_LE(iptr[7]);
2616 if (curProg < 0 || curProg >= numProgs)
2617 {
2618 break;
2619 }
2620 }
2621
2622 // Is it a bank of programs?
2623 if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'B', 'k'))
2624 {
2625 // Drop the header
2626 bptr += 156;
2627 len -= 156;
2628
2629 unsigned char *tempPtr = bptr;
2630 ssize_t tempLen = len;
2631
2632 // Validate all of the programs
2633 for (int i = 0; i < numProgs; i++)
2634 {
2635 if (!LoadFXProgram(&tempPtr, tempLen, i, true))
2636 {
2637 break;
2638 }
2639 }
2640
2641 // Ask the effect if this is an acceptable bank
2642 if (callDispatcher(effBeginLoadBank, 0, 0, &info, 0.0) == -1)
2643 {
2644 return false;
2645 }
2646
2647 // Start loading the individual programs
2648 for (int i = 0; i < numProgs; i++)
2649 {
2650 ret = LoadFXProgram(&bptr, len, i, false);
2651 }
2652 }
2653 // Or maybe a bank chunk?
2654 else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'B', 'C', 'h'))
2655 {
2656 // Can't load programs chunks if the plugin doesn't support it
2658 {
2659 break;
2660 }
2661
2662 // Verify that we have enough to grab the chunk size
2663 if (len < 160)
2664 {
2665 break;
2666 }
2667
2668 // Get the chunk size
2669 int size = wxINT32_SWAP_ON_LE(iptr[39]);
2670
2671 // We finally know the full length of the program
2672 int proglen = 160 + size;
2673
2674 // Verify that we have enough for the entire program
2675 if (len < proglen)
2676 {
2677 break;
2678 }
2679
2680 // Set the entire bank in one shot
2681 callSetChunk(false, size, &iptr[40], &info);
2682
2683 // Success
2684 ret = true;
2685 }
2686 // Unrecognizable type
2687 else
2688 {
2689 break;
2690 }
2691
2692 // Set the active program
2693 if (ret && version >= 2)
2694 {
2695 callSetProgram(curProg);
2696 }
2697 } while (false);
2698
2699 return ret;
2700}
2701
2702bool VSTEffect::LoadFXP(const wxFileName & fn)
2703{
2704 bool ret = false;
2705
2706 // Try to open the file...will be closed automatically when method returns
2707 wxFFile f(fn.GetFullPath(), wxT("rb"));
2708 if (!f.IsOpened())
2709 {
2710 return false;
2711 }
2712
2713 // Allocate memory for the contents
2714 ArrayOf<unsigned char> data{ size_t(f.Length()) };
2715 if (!data)
2716 {
2718 XO("Unable to allocate memory when loading presets file."),
2719 XO("Error Loading VST Presets"),
2720 wxOK | wxCENTRE,
2721 mParent);
2722 return false;
2723 }
2724 unsigned char *bptr = data.get();
2725
2726 do
2727 {
2728 // Read in the whole file
2729 ssize_t len = f.Read((void *) bptr, f.Length());
2730 if (f.Error())
2731 {
2733 XO("Unable to read presets file."),
2734 XO("Error Loading VST Presets"),
2735 wxOK | wxCENTRE,
2736 mParent);
2737 break;
2738 }
2739
2740 // Get (or default) currently selected program
2741 int i = 0; //mProgram->GetCurrentSelection();
2742 if (i < 0)
2743 {
2744 i = 0; // default to first program
2745 }
2746
2747 // Go verify and set the program
2748 ret = LoadFXProgram(&bptr, len, i, false);
2749 } while (false);
2750
2751 return ret;
2752}
2753
2754bool VSTEffect::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bool dryrun)
2755{
2756 // Most references to the data are via an "int" array
2757 int32_t *iptr = (int32_t *) *bptr;
2758
2759 // Verify that we have at least enough for a program without parameters
2760 if (len < 28)
2761 {
2762 return false;
2763 }
2764
2765 // Verify that we probably have an FX file
2766 if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K'))
2767 {
2768 return false;
2769 }
2770
2771 // Ignore the size...sometimes it's there, other times it's zero
2772
2773 // Get the version and verify
2774#if defined(IS_THIS_AN_FXP_ARTIFICAL_LIMITATION)
2775 int version = wxINT32_SWAP_ON_LE(iptr[3]);
2776 if (version != 1)
2777 {
2778 return false;
2779 }
2780#endif
2781
2782 VstPatchChunkInfo info =
2783 {
2784 1,
2785 wxINT32_SWAP_ON_LE(iptr[4]),
2786 wxINT32_SWAP_ON_LE(iptr[5]),
2787 wxINT32_SWAP_ON_LE(iptr[6]),
2788 ""
2789 };
2790
2791 // Ensure this program looks to belong to the current plugin
2792 if ((info.pluginUniqueID != mAEffect->uniqueID) &&
2793 (info.pluginVersion != mAEffect->version) &&
2794 (info.numElements != mAEffect->numParams))
2795 {
2796 return false;
2797 }
2798
2799 // Get the number of parameters
2800 int numParams = info.numElements;
2801
2802 // At this point, we have to have enough to include the program name as well
2803 if (len < 56)
2804 {
2805 return false;
2806 }
2807
2808 // Get the program name
2809 wxString progName(wxString::From8BitData((char *)&iptr[7]));
2810
2811 // Might be a regular program
2812 if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'C', 'k'))
2813 {
2814 // We finally know the full length of the program
2815 int proglen = 56 + (numParams * sizeof(float));
2816
2817 // Verify that we have enough for all of the parameter values
2818 if (len < proglen)
2819 {
2820 return false;
2821 }
2822
2823 // Validate all of the parameter values
2824 for (int i = 0; i < numParams; i++)
2825 {
2826 uint32_t ival = wxUINT32_SWAP_ON_LE(iptr[14 + i]);
2827 float val = reinterpretAsFloat(ival);
2828 if (val < 0.0 || val > 1.0)
2829 {
2830 return false;
2831 }
2832 }
2833
2834 // They look okay...time to start changing things
2835 if (!dryrun)
2836 {
2837 // Ask the effect if this is an acceptable program
2838 if (callDispatcher(effBeginLoadProgram, 0, 0, &info, 0.0) == -1)
2839 {
2840 return false;
2841 }
2842
2843 // Load all of the parameters
2844 callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
2845 for (int i = 0; i < numParams; i++)
2846 {
2847 wxUint32 val = wxUINT32_SWAP_ON_LE(iptr[14 + i]);
2849 }
2850 callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
2851 }
2852
2853 // Update in case we're loading an "FxBk" format bank file
2854 *bptr += proglen;
2855 len -= proglen;
2856 }
2857 // Maybe we have a program chunk
2858 else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'P', 'C', 'h'))
2859 {
2860 // Can't load programs chunks if the plugin doesn't support it
2862 {
2863 return false;
2864 }
2865
2866 // Verify that we have enough to grab the chunk size
2867 if (len < 60)
2868 {
2869 return false;
2870 }
2871
2872 // Get the chunk size
2873 int size = wxINT32_SWAP_ON_LE(iptr[14]);
2874
2875 // We finally know the full length of the program
2876 int proglen = 60 + size;
2877
2878 // Verify that we have enough for the entire program
2879 if (len < proglen)
2880 {
2881 return false;
2882 }
2883
2884 // Set the entire program in one shot
2885 if (!dryrun)
2886 {
2887 callSetChunk(true, size, &iptr[15], &info);
2888 }
2889
2890 // Update in case we're loading an "FxBk" format bank file
2891 *bptr += proglen;
2892 len -= proglen;
2893 }
2894 else
2895 {
2896 // Unknown type
2897 return false;
2898 }
2899
2900 if (!dryrun)
2901 {
2902 SetString(effSetProgramName, wxString(progName), index);
2903 }
2904
2905 return true;
2906}
2907
2908bool VSTEffect::LoadXML(const wxFileName & fn)
2909{
2910 mInChunk = false;
2911 mInSet = false;
2912
2913 // default to read as XML file
2914 // Load the program
2915 XMLFileReader reader;
2916 bool ok = reader.Parse(this, fn.GetFullPath());
2917
2918 // Something went wrong with the file, clean up
2919 if (mInSet)
2920 {
2921 callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
2922
2923 mInSet = false;
2924 }
2925
2926 if (!ok)
2927 {
2928 // Inform user of load failure
2930 reader.GetErrorStr(),
2931 XO("Error Loading VST Presets"),
2932 wxOK | wxCENTRE,
2933 mParent);
2934 return false;
2935 }
2936
2937 return true;
2938}
2939
2940void VSTEffect::SaveFXB(const wxFileName & fn) const
2941{
2942 // Create/Open the file
2943 const wxString fullPath{fn.GetFullPath()};
2944 wxFFile f(fullPath, wxT("wb"));
2945 if (!f.IsOpened())
2946 {
2948 XO("Could not open file: \"%s\"").Format( fullPath ),
2949 XO("Error Saving VST Presets"),
2950 wxOK | wxCENTRE,
2951 mParent);
2952 return;
2953 }
2954
2955 wxMemoryBuffer buf;
2956 wxInt32 subType;
2957 void *chunkPtr = nullptr;
2958 int chunkSize = 0;
2959 int dataSize = 148;
2960 wxInt32 tab[8];
2961 int curProg = 0 ; //mProgram->GetCurrentSelection();
2962
2964 {
2965 subType = CCONST('F', 'B', 'C', 'h');
2966
2967 // read-only dispatcher function
2968 chunkSize = constCallDispatcher(effGetChunk, 0, 0, &chunkPtr, 0.0);
2969 dataSize += 4 + chunkSize;
2970 }
2971 else
2972 {
2973 subType = CCONST('F', 'x', 'B', 'k');
2974
2975 for (int i = 0; i < mAEffect->numPrograms; i++)
2976 {
2977 SaveFXProgram(buf, i);
2978 }
2979
2980 dataSize += buf.GetDataLen();
2981 }
2982
2983 tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K'));
2984 tab[1] = wxINT32_SWAP_ON_LE(dataSize);
2985 tab[2] = wxINT32_SWAP_ON_LE(subType);
2986 tab[3] = wxINT32_SWAP_ON_LE(curProg >= 0 ? 2 : 1);
2987 tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID);
2988 tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version);
2989 tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numPrograms);
2990 tab[7] = wxINT32_SWAP_ON_LE(curProg >= 0 ? curProg : 0);
2991
2992 f.Write(tab, sizeof(tab));
2993 if (!f.Error())
2994 {
2995 char padding[124];
2996 memset(padding, 0, sizeof(padding));
2997 f.Write(padding, sizeof(padding));
2998
2999 if (!f.Error())
3000 {
3002 {
3003 wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize);
3004 f.Write(&size, sizeof(size));
3005 f.Write(chunkPtr, chunkSize);
3006 }
3007 else
3008 {
3009 f.Write(buf.GetData(), buf.GetDataLen());
3010 }
3011 }
3012 }
3013
3014 if (f.Error())
3015 {
3017 XO("Error writing to file: \"%s\"").Format( fullPath ),
3018 XO("Error Saving VST Presets"),
3019 wxOK | wxCENTRE,
3020 mParent);
3021 }
3022
3023 f.Close();
3024
3025 return;
3026}
3027
3028void VSTEffect::SaveFXP(const wxFileName & fn) const
3029{
3030 // Create/Open the file
3031 const wxString fullPath{ fn.GetFullPath() };
3032 wxFFile f(fullPath, wxT("wb"));
3033 if (!f.IsOpened())
3034 {
3036 XO("Could not open file: \"%s\"").Format( fullPath ),
3037 XO("Error Saving VST Presets"),
3038 wxOK | wxCENTRE,
3039 mParent);
3040 return;
3041 }
3042
3043 wxMemoryBuffer buf;
3044
3045 // read-only dispatcher function
3046 int ndx = constCallDispatcher(effGetProgram, 0, 0, NULL, 0.0);
3047 SaveFXProgram(buf, ndx);
3048
3049 f.Write(buf.GetData(), buf.GetDataLen());
3050 if (f.Error())
3051 {
3053 XO("Error writing to file: \"%s\"").Format( fullPath ),
3054 XO("Error Saving VST Presets"),
3055 wxOK | wxCENTRE,
3056 mParent);
3057 }
3058
3059 f.Close();
3060
3061 return;
3062}
3063
3064void VSTEffect::SaveFXProgram(wxMemoryBuffer & buf, int index) const
3065{
3066 wxInt32 subType;
3067 void *chunkPtr;
3068 int chunkSize;
3069 int dataSize = 48;
3070 char progName[28];
3071 wxInt32 tab[7];
3072
3073 // read-only dispatcher function
3074 constCallDispatcher(effGetProgramNameIndexed, index, 0, &progName, 0.0);
3075 progName[27] = '\0';
3076 chunkSize = strlen(progName);
3077 memset(&progName[chunkSize], 0, sizeof(progName) - chunkSize);
3078
3080 {
3081 subType = CCONST('F', 'P', 'C', 'h');
3082
3083 // read-only dispatcher function
3084 chunkSize = constCallDispatcher(effGetChunk, 1, 0, &chunkPtr, 0.0);
3085 dataSize += 4 + chunkSize;
3086 }
3087 else
3088 {
3089 subType = CCONST('F', 'x', 'C', 'k');
3090
3091 dataSize += (mAEffect->numParams << 2);
3092 }
3093
3094 tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K'));
3095 tab[1] = wxINT32_SWAP_ON_LE(dataSize);
3096 tab[2] = wxINT32_SWAP_ON_LE(subType);
3097 tab[3] = wxINT32_SWAP_ON_LE(1);
3098 tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID);
3099 tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version);
3100 tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numParams);
3101
3102 buf.AppendData(tab, sizeof(tab));
3103 buf.AppendData(progName, sizeof(progName));
3104
3106 {
3107 wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize);
3108 buf.AppendData(&size, sizeof(size));
3109 buf.AppendData(chunkPtr, chunkSize);
3110 }
3111 else
3112 {
3113 for (int i = 0; i < mAEffect->numParams; i++)
3114 {
3115 float val = callGetParameter(i);
3116 wxUint32 ival = wxUINT32_SWAP_ON_LE(reinterpretAsUint32(val));
3117 buf.AppendData(&ival, sizeof(ival));
3118 }
3119 }
3120
3121 return;
3122}
3123
3124// Throws exceptions rather than giving error return.
3125void VSTEffect::SaveXML(const wxFileName & fn) const
3126// may throw
3127{
3128 XMLFileWriter xmlFile{ fn.GetFullPath(), XO("Error Saving Effect Presets") };
3129
3130 xmlFile.StartTag(wxT("vstprogrampersistence"));
3131 xmlFile.WriteAttr(wxT("version"), wxT("2"));
3132
3133 xmlFile.StartTag(wxT("effect"));
3134 // Use internal name only in persistent information
3135 xmlFile.WriteAttr(wxT("name"), GetSymbol().Internal());
3136 xmlFile.WriteAttr(wxT("uniqueID"), mAEffect->uniqueID);
3137 xmlFile.WriteAttr(wxT("version"), mAEffect->version);
3138 xmlFile.WriteAttr(wxT("numParams"), mAEffect->numParams);
3139
3140 xmlFile.StartTag(wxT("program"));
3141 xmlFile.WriteAttr(wxT("name"), wxEmptyString); //mProgram->GetValue());
3142
3143 int clen = 0;
3144 if (mAEffect->flags & effFlagsProgramChunks)
3145 {
3146 void *chunk = NULL;
3147
3148 // read-only dispatcher function
3149 clen = (int) constCallDispatcher(effGetChunk, 1, 0, &chunk, 0.0);
3150 if (clen != 0)
3151 {
3152 xmlFile.StartTag(wxT("chunk"));
3153 xmlFile.WriteSubTree(Base64::Encode(chunk, clen) + wxT('\n'));
3154 xmlFile.EndTag(wxT("chunk"));
3155 }
3156 }
3157
3158 if (clen == 0)
3159 {
3160 for (int i = 0; i < mAEffect->numParams; i++)
3161 {
3162 xmlFile.StartTag(wxT("param"));
3163
3164 xmlFile.WriteAttr(wxT("index"), i);
3165 xmlFile.WriteAttr(wxT("name"),
3166 GetString(effGetParamName, i));
3167 xmlFile.WriteAttr(wxT("value"),
3168 wxString::Format(wxT("%f"),
3169 callGetParameter(i)));
3170
3171 xmlFile.EndTag(wxT("param"));
3172 }
3173 }
3174
3175 xmlFile.EndTag(wxT("program"));
3176
3177 xmlFile.EndTag(wxT("effect"));
3178
3179 xmlFile.EndTag(wxT("vstprogrampersistence"));
3180
3181 xmlFile.Commit();
3182}
3183
3184bool VSTEffect::HandleXMLTag(const std::string_view& tag, const AttributesList &attrs)
3185{
3186 if (tag == "vstprogrampersistence")
3187 {
3188 for (auto pair : attrs)
3189 {
3190 auto attr = pair.first;
3191 auto value = pair.second;
3192
3193 if (attr == "version")
3194 {
3195 if (!value.TryGet(mXMLVersion))
3196 {
3197 return false;
3198 }
3199
3200 if (mXMLVersion < 1 || mXMLVersion > 2)
3201 {
3202 return false;
3203 }
3204 }
3205 else
3206 {
3207 return false;
3208 }
3209 }
3210
3211 return true;
3212 }
3213
3214 if (tag == "effect")
3215 {
3216 memset(&mXMLInfo, 0, sizeof(mXMLInfo));
3217 mXMLInfo.version = 1;
3221
3222 for (auto pair : attrs)
3223 {
3224 auto attr = pair.first;
3225 auto value = pair.second;
3226
3227 if (attr == "name")
3228 {
3229 wxString strValue = value.ToWString();
3230
3231 if (strValue != GetSymbol().Internal())
3232 {
3233 auto msg = XO("This parameter file was saved from %s. Continue?")
3234 .Format( strValue );
3235 int result = AudacityMessageBox(
3236 msg,
3237 XO("Confirm"),
3238 wxYES_NO,
3239 mParent );
3240 if (result == wxNO)
3241 {
3242 return false;
3243 }
3244 }
3245 }
3246 else if (attr == "version")
3247 {
3248 long version;
3249 if (!value.TryGet(version))
3250 {
3251 return false;
3252 }
3253
3254 mXMLInfo.pluginVersion = (int) version;
3255 }
3256 else if (mXMLVersion > 1 && attr == "uniqueID")
3257 {
3258 long uniqueID;
3259 if (!value.TryGet(uniqueID))
3260 {
3261 return false;
3262 }
3263
3264 mXMLInfo.pluginUniqueID = (int) uniqueID;
3265 }
3266 else if (mXMLVersion > 1 && attr == "numParams")
3267 {
3268 long numParams;
3269 if (!value.TryGet(numParams))
3270 {
3271 return false;
3272 }
3273
3274 mXMLInfo.numElements = (int) numParams;
3275 }
3276 else
3277 {
3278 return false;
3279 }
3280 }
3281
3282 return true;
3283 }
3284
3285 if (tag == "program")
3286 {
3287 for (auto pair : attrs)
3288 {
3289 auto attr = pair.first;
3290 auto value = pair.second;
3291
3292 if (attr == "name")
3293 {
3294 const wxString strValue = value.ToWString();
3295
3296 if (strValue.length() > 24)
3297 {
3298 return false;
3299 }
3300
3301 int ndx = 0; //mProgram->GetCurrentSelection();
3302 if (ndx == wxNOT_FOUND)
3303 {
3304 ndx = 0;
3305 }
3306
3307 SetString(effSetProgramName, strValue, ndx);
3308 }
3309 else
3310 {
3311 return false;
3312 }
3313 }
3314
3315 mInChunk = false;
3316
3317 if (callDispatcher(effBeginLoadProgram, 0, 0, &mXMLInfo, 0.0) == -1)
3318 {
3319 return false;
3320 }
3321
3322 callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0);
3323
3324 mInSet = true;
3325
3326 return true;
3327 }
3328
3329 if (tag == "param")
3330 {
3331 long ndx = -1;
3332 double val = -1.0;
3333
3334 for (auto pair : attrs)
3335 {
3336 auto attr = pair.first;
3337 auto value = pair.second;
3338
3339 if (attr == "index")
3340 {
3341 if (!value.TryGet(ndx))
3342 {
3343 return false;
3344 }
3345
3346 if (ndx < 0 || ndx >= mAEffect->numParams)
3347 {
3348 // Could be a different version of the effect...probably should
3349 // tell the user
3350 return false;
3351 }
3352 }
3353 // "name" attribute is ignored for params
3354 /* else if (attr == "name")
3355 {
3356
3357 // Nothing to do with it for now
3358 }*/
3359 else if (attr == "value")
3360 {
3361 if (!value.TryGet(val))
3362 {
3363 return false;
3364 }
3365
3366 if (val < 0.0 || val > 1.0)
3367 {
3368 return false;
3369 }
3370 }
3371 }
3372
3373 if (ndx == -1 || val == -1.0)
3374 {
3375 return false;
3376 }
3377
3378 callSetParameter(ndx, val);
3379
3380 return true;
3381 }
3382
3383 if (tag == "chunk")
3384 {
3385 mInChunk = true;
3386 return true;
3387 }
3388
3389 return false;
3390}
3391
3392void VSTEffect::HandleXMLEndTag(const std::string_view& tag)
3393{
3394 if (tag == "chunk")
3395 {
3396 if (mChunk.length())
3397 {
3398 ArrayOf<char> buf{ mChunk.length() / 4 * 3 };
3399
3400 int len = Base64::Decode(mChunk, buf.get());
3401 if (len)
3402 {
3403 callSetChunk(true, len, buf.get(), &mXMLInfo);
3404 }
3405
3406 mChunk.clear();
3407 }
3408 mInChunk = false;
3409 }
3410
3411 if (tag == "program")
3412 {
3413 if (mInSet)
3414 {
3415 callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0);
3416
3417 mInSet = false;
3418 }
3419 }
3420}
3421
3422void VSTEffect::HandleXMLContent(const std::string_view& content)
3423{
3424 if (mInChunk)
3425 {
3426 mChunk += wxString(std::string(content)).Trim(true).Trim(false);
3427 }
3428}
3429
3430XMLTagHandler *VSTEffect::HandleXMLChild(const std::string_view& tag)
3431{
3432 if (tag == "vstprogrampersistence")
3433 {
3434 return this;
3435 }
3436
3437 if (tag == "effect")
3438 {
3439 return this;
3440 }
3441
3442 if (tag == "program")
3443 {
3444 return this;
3445 }
3446
3447 if (tag == "param")
3448 {
3449 return this;
3450 }
3451
3452 if (tag == "chunk")
3453 {
3454 return this;
3455 }
3456
3457 return NULL;
3458}
3459
3460#endif // USE_VST
@ Internal
Indicates internal failure from Audacity.
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
int min(int a, int b)
#define str(a)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:82
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeTool
@ EffectTypeProcess
enum ChannelName * ChannelNames
EVT_COMMAND_RANGE(ID_Slider, ID_Slider+NUMBER_OF_BANDS - 1, wxEVT_COMMAND_SLIDER_UPDATED, EffectEqualization::OnSlider) EffectEqualization
#define PLATFORM_MAX_PATH
Definition: FileNames.h:43
std::vector< PluginPath > PluginPaths
Definition: Identifier.h:215
wxString RegistryPath
Definition: Identifier.h:218
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:92
#define safenew
Definition: MemoryX.h:10
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:162
wxString FilePath
Definition: Project.h:20
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
@ eIsCreating
Definition: ShuttleGui.h:39
@ eIsGettingFromDialog
Definition: ShuttleGui.h:40
static TranslatableStrings names
Definition: TagsEditor.cpp:151
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
static uint32_t reinterpretAsUint32(float f)
Definition: VSTEffect.cpp:121
#define VSTPATH
@ ID_Duration
Definition: VSTEffect.cpp:591
@ ID_Sliders
Definition: VSTEffect.cpp:592
DECLARE_PROVIDER_ENTRY(AudacityModule)
Definition: VSTEffect.cpp:144
AEffect *(* vstPluginMain)(audioMasterCallback audioMaster)
Definition: VSTEffect.cpp:608
DEFINE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW)
static float reinterpretAsFloat(uint32_t x)
Definition: VSTEffect.cpp:113
static void OnSize(wxSizeEvent &evt)
Definition: VSTEffect.cpp:2261
DECLARE_BUILTIN_PROVIDER(VSTBuiltin)
#define VSTPLUGINTYPE
Definition: VSTEffect.h:35
static const auto fn
std::vector< Attribute > AttributesList
Definition: XMLTagHandler.h:40
VstPlugCategory
Definition: aeffectx.h:364
@ kPlugCategShell
Definition: aeffectx.h:375
const int effGetParamDisplay
Definition: aeffectx.h:100
const int effEditIdle
Definition: aeffectx.h:108
const int effGetVendorVersion
Definition: aeffectx.h:124
const int effGetVstVersion
Definition: aeffectx.h:128
const int kVstLangEnglish
Definition: aeffectx.h:145
const int effIdle
Definition: aeffectx.h:127
const int effMainsChanged
Definition: aeffectx.h:104
const int effGetProgram
Definition: aeffectx.h:94
const int effGetParamLabel
Definition: aeffectx.h:99
const int kVstNanosValid
Definition: aeffectx.h:148
const int effGetChunk
Definition: aeffectx.h:111
const int audioMasterGetVendorVersion
Definition: aeffectx.h:69
const int effCanBeAutomated
Definition: aeffectx.h:115
const int audioMasterGetCurrentProcessLevel
Definition: aeffectx.h:57
const int kEffectMagic
Definition: aeffectx.h:144
const int effGetProductString
Definition: aeffectx.h:123
intptr_t(* audioMasterCallback)(AEffect *, int32_t, int32_t, intptr_t, void *, float)
Definition: aeffectx.h:337
const int effStartProcess
Definition: aeffectx.h:141
const int effShellGetNextPlugin
Definition: aeffectx.h:134
const int effFlagsProgramChunks
Definition: aeffectx.h:88
const int effGetParamName
Definition: aeffectx.h:101
const int effGetProgramNameIndexed
Definition: aeffectx.h:117
const int audioMasterNeedIdle
Definition: aeffectx.h:48
const int audioMasterGetProductString
Definition: aeffectx.h:68
const int effSetBlockSize
Definition: aeffectx.h:103
const int effSetProgramName
Definition: aeffectx.h:96
const int effGetVendorString
Definition: aeffectx.h:122
const int kVstTransportPlaying
Definition: aeffectx.h:157
const int effClose
Definition: aeffectx.h:92
const int audioMasterWantMidi
Definition: aeffectx.h:40
const int audioMasterPinConnected
Definition: aeffectx.h:38
const int effFlagsIsSynth
Definition: aeffectx.h:89
const int audioMasterWillReplaceOrAccumulate
Definition: aeffectx.h:56
const int audioMasterUpdateDisplay
Definition: aeffectx.h:77
const int audioMasterGetTime
Definition: aeffectx.h:41
const int effGetEffectName
Definition: aeffectx.h:120
const int effGetPlugCategory
Definition: aeffectx.h:119
const int audioMasterEndEdit
Definition: aeffectx.h:79
const int effSetProgram
Definition: aeffectx.h:93
const int audioMasterIdle
Definition: aeffectx.h:37
const int audioMasterIOChanged
Definition: aeffectx.h:47
const int effFlagsCanReplacing
Definition: aeffectx.h:87
const int effBeginSetProgram
Definition: aeffectx.h:130
const int effStopProcess
Definition: aeffectx.h:142
const int effOpen
Definition: aeffectx.h:91
const int effBeginLoadBank
Definition: aeffectx.h:136
#define CCONST(a, b, c, d)
Definition: aeffectx.h:29
const int audioMasterProcessEvents
Definition: aeffectx.h:42
const int effSetSampleRate
Definition: aeffectx.h:102
const int audioMasterCurrentId
Definition: aeffectx.h:36
const int kVstTempoValid
Definition: aeffectx.h:150
const int audioMasterAutomate
Definition: aeffectx.h:34
const int effBeginLoadProgram
Definition: aeffectx.h:138
const int audioMasterVersion
Definition: aeffectx.h:35
const int audioMasterBeginEdit
Definition: aeffectx.h:78
const int audioMasterGetVendorString
Definition: aeffectx.h:67
const int audioMasterGetSampleRate
Definition: aeffectx.h:50
const int effFlagsHasEditor
Definition: aeffectx.h:86
const int effEndSetProgram
Definition: aeffectx.h:132
const int audioMasterGetLanguage
Definition: aeffectx.h:73
const int audioMasterSizeWindow
Definition: aeffectx.h:49
const int effIdentify
Definition: aeffectx.h:110
const int effSetChunk
Definition: aeffectx.h:112
const int audioMasterCanDo
Definition: aeffectx.h:72
VST Effects class, conforming to VST layout.
Definition: aeffectx.h:258
int numParams
Definition: aeffectx.h:274
void * ptr2
Definition: aeffectx.h:283
int numOutputs
Definition: aeffectx.h:278
int32_t version
Definition: aeffectx.h:296
int numInputs
Definition: aeffectx.h:276
void(* setParameter)(AEffect *, int, float)
Definition: aeffectx.h:268
int initialDelay
Definition: aeffectx.h:284
int flags
Definition: aeffectx.h:280
int numPrograms
Definition: aeffectx.h:272
int magic
Definition: aeffectx.h:262
void(* processReplacing)(AEffect *, float **, float **, int)
Definition: aeffectx.h:298
int32_t uniqueID
Definition: aeffectx.h:295
intptr_t(* dispatcher)(AEffect *, int, int, intptr_t, void *, float)
Definition: aeffectx.h:264
float(* getParameter)(AEffect *, int)
Definition: aeffectx.h:270
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
bool GetParameters(wxString &parms)
bool SetParameters(const wxString &parms)
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
EffectDefinitionInterface is a ComponentInterface that adds some basic read-only information about ef...
Base class for many of the effects in Audacity.
Definition: Effect.h:148
Performs effect computation.
virtual const EffectSettings & Get()=0
Abstract base class used in importing a file.
void SetName(const TranslatableString &name)
virtual void FindFilesInPathList(const wxString &pattern, const FilePaths &pathList, FilePaths &files, bool directories=false)=0
std::function< const PluginID &(PluginProvider *, ComponentInterface *) > RegistrationCallback
Further expand a path reported by FindModulePaths.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
Holds a msgid for the translation catalog; may also bind format arguments.
void Close()
bool SaveParameters(const RegistryPath &group, const EffectSettings &settings) const
Definition: VSTEffect.cpp:1954
void SaveXML(const wxFileName &fn) const
Definition: VSTEffect.cpp:3125
bool LoadUserPreset(const RegistryPath &name, EffectSettings &settings) const override
Change settings to a user-named preset.
Definition: VSTEffect.cpp:1300
bool HasOptions() override
Definition: VSTEffect.cpp:1572
int mVstVersion
Definition: VSTEffect.h:307
bool RealtimeResume() noexcept override
Definition: VSTEffect.cpp:1164
intptr_t callDispatcher(int opcode, int index, intptr_t value, void *ptr, float opt) override
Definition: VSTEffect.cpp:2166
void OnSizeWindow(wxCommandEvent &evt)
Definition: VSTEffect.cpp:2497
intptr_t constCallDispatcher(int opcode, int index, intptr_t value, void *ptr, float opt) const
Definition: VSTEffect.cpp:2174
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
Definition: VSTEffect.cpp:1326
PluginPath mPath
Definition: VSTEffect.h:294
std::unique_ptr< VSTEffectTimer > mTimer
Definition: VSTEffect.h:362
unsigned mNumChannels
Definition: VSTEffect.h:368
void SetString(int opcode, const wxString &str, int index=0)
Definition: VSTEffect.cpp:2158
int mProcessLevel
Definition: VSTEffect.h:355
size_t SetBlockSize(size_t maxBlockSize) override
Definition: VSTEffect.cpp:1000
EffectType GetType() const override
Type determines how it behaves.
Definition: VSTEffect.cpp:893
bool mInSet
Definition: VSTEffect.h:384
int GetString(wxString &outstr, int opcode, int index=0) const
Definition: VSTEffect.cpp:2135
bool DoLoadFactoryPreset(int id)
Definition: VSTEffect.cpp:1350
void SaveFXP(const wxFileName &fn) const
Definition: VSTEffect.cpp:3028
bool mWantsEditIdle
Definition: VSTEffect.h:358
void callSetChunk(bool isPgm, int len, void *buf)
Definition: VSTEffect.cpp:2217
void NeedEditIdle(bool state)
Definition: VSTEffect.cpp:2025
float GetSampleRate()
Definition: VSTEffect.cpp:2037
bool RealtimeSuspend() override
Definition: VSTEffect.cpp:1154
long mXMLVersion
Definition: VSTEffect.h:387
ArrayOf< wxSlider * > mSliders
Definition: VSTEffect.h:380
unsigned mAudioIns
Definition: VSTEffect.h:295
ArrayOf< wxStaticText * > mLabels
Definition: VSTEffect.h:382
std::unique_ptr< EffectUIValidator > PopulateUI(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Adds controls to a panel that is given as the parent window of S
Definition: VSTEffect.cpp:1363
EffectFamilySymbol GetFamily() const override
Report identifier and user-visible name of the effect protocol.
Definition: VSTEffect.cpp:914
std::unique_ptr< wxDynamicLibrary > ModuleHandle
Definition: VSTEffect.h:285
CF_ptr< CFBundleRef > BundleHandle
Definition: VSTEffect.h:318
void UpdateDisplay()
Definition: VSTEffect.cpp:2097
bool LoadXML(const wxFileName &fn)
Definition: VSTEffect.cpp:2908
bool SupportsRealtime() const override
Whether the effect supports realtime previewing (while audio is playing).
Definition: VSTEffect.cpp:929
bool RealtimeFinalize(EffectSettings &settings) noexcept override
Definition: VSTEffect.cpp:1143
bool mUseLatency
Definition: VSTEffect.h:350
PluginPath GetPath() const override
Definition: VSTEffect.cpp:847
int GetProcessLevel()
Definition: VSTEffect.cpp:2042
size_t GetBlockSize() const override
Definition: VSTEffect.cpp:1006
bool LoadFXB(const wxFileName &fn)
Definition: VSTEffect.cpp:2529
TranslatableString GetDescription() const override
Definition: VSTEffect.cpp:881
wxWindow * mParent
Definition: VSTEffect.h:372
bool mHasPower
Definition: VSTEffect.h:356
ArrayOf< wxStaticText * > mDisplays
Definition: VSTEffect.h:381
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
Definition: VSTEffect.cpp:963
void HandleXMLEndTag(const std::string_view &tag) override
Definition: VSTEffect.cpp:3392
void callSetParameter(int index, float value)
Definition: VSTEffect.cpp:2195
bool IsReady()
Definition: VSTEffect.cpp:1029
bool mReady
Definition: VSTEffect.h:311
wxWeakRef< wxDialog > mDialog
Definition: VSTEffect.h:371
wxString GetVersion() const override
Definition: VSTEffect.cpp:862
void SetChannelCount(unsigned numChannels)
Definition: VSTEffect.cpp:1096
wxSizerItem * mContainer
Definition: VSTEffect.h:373
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
Definition: VSTEffect.cpp:919
void NeedIdle()
Definition: VSTEffect.cpp:2019
unsigned mAudioOuts
Definition: VSTEffect.h:296
wxString mName
Definition: VSTEffect.h:302
float mSampleRate
Definition: VSTEffect.h:300
bool LoadFactoryPreset(int id, EffectSettings &settings) const override
Change settings to the preset whose name is GetFactoryPresets()[id]
Definition: VSTEffect.cpp:1344
bool LoadFXProgram(unsigned char **bptr, ssize_t &len, int index, bool dryrun)
Definition: VSTEffect.cpp:2754
VendorSymbol GetVendor() const override
Definition: VSTEffect.cpp:857
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
Definition: VSTEffect.cpp:1270
bool SupportsAutomation() const override
Whether the effect has any automatable controls.
Definition: VSTEffect.cpp:936
void SetSampleRate(double rate) override
Definition: VSTEffect.cpp:1011
sampleCount GetLatency() override
Definition: VSTEffect.cpp:1016
bool mInteractive
Definition: VSTEffect.h:306
bool RealtimeProcessEnd(EffectSettings &settings) noexcept override
Definition: VSTEffect.cpp:1188
static intptr_t AudioMaster(AEffect *effect, int32_t opcode, int32_t index, intptr_t value, void *ptr, float opt)
Definition: VSTEffect.cpp:610
bool mInChunk
Definition: VSTEffect.h:385
bool LoadFXP(const wxFileName &fn)
Definition: VSTEffect.cpp:2702
void OnSlider(wxCommandEvent &evt)
Definition: VSTEffect.cpp:2519
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
Definition: VSTEffect.cpp:980
bool RealtimeProcessStart(EffectSettings &settings) override
Definition: VSTEffect.cpp:1176
unsigned mBlockSize
Definition: VSTEffect.h:353
void callProcessReplacing(const float *const *inputs, float *const *outputs, int sampleframes)
Definition: VSTEffect.cpp:2182
int mMidiIns
Definition: VSTEffect.h:297
static intptr_t mCurrentEffectID
Definition: VSTEffect.h:309
int GetMidiInCount() const override
Function that has not yet found a use.
Definition: VSTEffect.cpp:990
wxString mVendor
Definition: VSTEffect.h:303
VstPatchChunkInfo mXMLInfo
Definition: VSTEffect.h:388
VSTEffect(const PluginPath &path, VSTEffect *master=NULL)
Definition: VSTEffect.cpp:792
int mMidiOuts
Definition: VSTEffect.h:298
AEffect * mAEffect
Definition: VSTEffect.h:346
bool CloseUI() override
Definition: VSTEffect.cpp:1411
bool SaveUserPreset(const RegistryPath &name, const EffectSettings &settings) const override
Save settings in the configuration file as a user-named preset.
Definition: VSTEffect.cpp:1320
int ShowClientInterface(wxWindow &parent, wxDialog &dialog, bool forceModal) override
Definition: VSTEffect.cpp:1219
VSTControl * mControl
Definition: VSTEffect.h:376
bool mWantsIdle
Definition: VSTEffect.h:357
void HandleXMLContent(const std::string_view &content) override
Definition: VSTEffect.cpp:3422
void PowerOff()
Definition: VSTEffect.cpp:2065
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: VSTEffect.cpp:985
bool DoProcessInitialize(sampleCount totalLen, ChannelNames chanMap)
Definition: VSTEffect.cpp:1040
void SetBufferDelay(int samples)
Definition: VSTEffect.cpp:2124
bool ProcessInitialize(EffectSettings &settings, sampleCount totalLen, ChannelNames chanMap) override
Definition: VSTEffect.cpp:1034
void PowerOn()
Definition: VSTEffect.cpp:2047
bool IsDefault() const override
Whether the effect sorts "above the line" in the menus.
Definition: VSTEffect.cpp:924
ModuleHandle mModule
Definition: VSTEffect.h:313
ComponentInterfaceSymbol GetSymbol() const override
Definition: VSTEffect.cpp:852
void ExportPresets(const EffectSettings &settings) const override
Definition: VSTEffect.cpp:1445
VstTimeInfo * GetTimeInfo()
Definition: VSTEffect.cpp:2031
std::shared_ptr< EffectInstance > DoMakeInstance()
Definition: VSTEffect.cpp:968
void RefreshParameters(int skip=-1)
Definition: VSTEffect.cpp:2446
std::vector< int > GetEffectIDs()
Definition: VSTEffect.cpp:1883
bool DoLoadUserPreset(const RegistryPath &name, EffectSettings &settings)
Definition: VSTEffect.cpp:1307
void OnTimer()
Definition: VSTEffect.cpp:1994
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: VSTEffect.cpp:1075
void BuildPlain(EffectSettingsAccess &access)
Definition: VSTEffect.cpp:2317
bool Load()
Definition: VSTEffect.cpp:1596
void Unload()
Definition: VSTEffect.cpp:1854
virtual ~VSTEffect()
Definition: VSTEffect.cpp:838
size_t mUserBlockSize
Definition: VSTEffect.h:301
size_t RealtimeProcess(int group, EffectSettings &settings, const float *const *inbuf, float *const *outbuf, size_t numSamples) override
Definition: VSTEffect.cpp:1181
bool IsGraphicalUI() override
Definition: VSTEffect.cpp:1398
bool InitializePlugin()
Definition: VSTEffect.cpp:941
bool ValidateUI(EffectSettings &) override
Definition: VSTEffect.cpp:1403
bool mAutomatable
Definition: VSTEffect.h:299
float callGetParameter(int index) const
Definition: VSTEffect.cpp:2190
void RemoveHandler()
Definition: VSTEffect.cpp:2257
void SaveFXB(const wxFileName &fn) const
Definition: VSTEffect.cpp:2940
int mTimerGuard
Definition: VSTEffect.h:363
unsigned GetChannelCount()
Definition: VSTEffect.cpp:1091
bool ProcessFinalize() override
Definition: VSTEffect.cpp:1066
bool RealtimeInitialize(EffectSettings &settings) override
Definition: VSTEffect.cpp:1101
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
Definition: VSTEffect.cpp:3430
bool LoadParameters(const RegistryPath &group, EffectSettings &settings)
Definition: VSTEffect.cpp:1904
void ImportPresets(EffectSettings &settings) override
Definition: VSTEffect.cpp:1505
void BuildFancy()
Definition: VSTEffect.cpp:2279
bool RealtimeAddProcessor(EffectSettings &settings, unsigned numChannels, float sampleRate) override
Definition: VSTEffect.cpp:1106
void Automate(int index, float value)
Definition: VSTEffect.cpp:2110
void callSetProgram(int index)
Definition: VSTEffect.cpp:2206
bool mGui
Definition: VSTEffect.h:374
VSTEffect * mMaster
Definition: VSTEffect.h:366
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
Definition: VSTEffect.cpp:3184
bool CanExportPresets() override
Definition: VSTEffect.cpp:1439
int mVersion
Definition: VSTEffect.h:305
bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const override
Store settings as keys and values.
Definition: VSTEffect.cpp:1249
VSTEffectArray mSlaves
Definition: VSTEffect.h:367
ResourceHandle mResource
Definition: VSTEffect.h:343
wxString mChunk
Definition: VSTEffect.h:386
int GetMidiOutCount() const override
Function that has not yet found a use.
Definition: VSTEffect.cpp:995
void SaveFXProgram(wxMemoryBuffer &buf, int index) const
Definition: VSTEffect.cpp:3064
NumericTextCtrl * mDuration
Definition: VSTEffect.h:378
int mBufferDelay
Definition: VSTEffect.h:351
BundleHandle mBundleRef
Definition: VSTEffect.h:320
void SizeWindow(int w, int h)
Definition: VSTEffect.cpp:2083
VstTimeInfo mTimeInfo
Definition: VSTEffect.h:348
void ShowOptions() override
Definition: VSTEffect.cpp:1577
ArrayOf< wxStaticText * > mNames
Definition: VSTEffect.h:379
void OnOk(wxCommandEvent &evt)
Definition: VSTEffect.cpp:535
EffectDefinitionInterface & mEffect
Definition: VSTEffect.cpp:430
void PopulateOrExchange(ShuttleGui &S)
Definition: VSTEffect.cpp:462
VSTEffectOptionsDialog(wxWindow *parent, EffectDefinitionInterface &effect)
Definition: VSTEffect.cpp:442
virtual ~VSTEffectOptionsDialog()
Definition: VSTEffect.cpp:458
VSTEffectTimer(VSTEffect *effect)
Definition: VSTEffect.cpp:565
VSTEffect * mEffect
Definition: VSTEffect.cpp:581
const FileExtensions & GetFileExtensions() override
File types associated with this protocol.
Definition: VSTEffect.cpp:232
bool Initialize() override
Called immediately after creation. Let provider initialize.
Definition: VSTEffect.cpp:211
EffectFamilySymbol GetOptionalFamilySymbol() override
A symbol identifying the family of plug-ins provided by this.
Definition: VSTEffect.cpp:223
bool IsPluginValid(const PluginPath &path, bool bFast) override
Definition: VSTEffect.cpp:387
FilePath InstallPath() override
Where plug-in files should be copied to install them.
Definition: VSTEffect.cpp:238
PluginPaths FindModulePaths(PluginManagerInterface &pm) override
Definition: VSTEffect.cpp:250
TranslatableString GetDescription() const override
Definition: VSTEffect.cpp:202
void AutoRegisterPlugins(PluginManagerInterface &pm) override
Called so that a provider of a static set of plug-ins can register them.
Definition: VSTEffect.cpp:246
virtual ~VSTEffectsModule()
Definition: VSTEffect.cpp:173
VendorSymbol GetVendor() const override
Definition: VSTEffect.cpp:191
PluginPath GetPath() const override
Definition: VSTEffect.cpp:181
wxString GetVersion() const override
Definition: VSTEffect.cpp:196
std::unique_ptr< ComponentInterface > LoadPlugin(const PluginPath &path) override
Load the plug-in at a path reported by DiscoverPluginsAtPath.
Definition: VSTEffect.cpp:396
unsigned DiscoverPluginsAtPath(const PluginPath &path, TranslatableString &errMsg, const RegistrationCallback &callback) override
Definition: VSTEffect.cpp:359
ComponentInterfaceSymbol GetSymbol() const override
Definition: VSTEffect.cpp:186
void Terminate() override
Called just prior to deletion to allow releasing any resources.
Definition: VSTEffect.cpp:217
double tempo
Definition: aeffectx.h:317
double sampleRate
Definition: aeffectx.h:311
double nanoSeconds
Definition: aeffectx.h:313
int timeSigDenominator
Definition: aeffectx.h:327
double samplePos
Definition: aeffectx.h:309
int timeSigNumerator
Definition: aeffectx.h:325
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:19
const TranslatableString & GetErrorStr() const
bool Parse(XMLTagHandler *baseHandler, const FilePath &fname)
Wrapper to output XML data to files.
Definition: XMLWriter.h:84
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:42
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
STRINGS_API wxString Encode(const void *in, int len)
Definition: Base64.cpp:27
STRINGS_API int Decode(const wxString &in, void *out)
Definition: Base64.cpp:67
bool SetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, const Value &value)
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
std::vector< CommandFlagOptions > & Options()
Definition: Menus.cpp:535
Externalized state of a plug-in.
EffectSettingsExtra extra
Options & AutoPos(bool enable)
CFBundleRefNum mNum
Definition: VSTEffect.h:341
int32_t version
Definition: aeffectx.h:355
int32_t pluginUniqueID
Definition: aeffectx.h:356
int32_t numElements
Definition: aeffectx.h:358
int32_t pluginVersion
Definition: aeffectx.h:357