Audacity 3.2.0
LadspaEffect.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 LadspaEffect.cpp
6
7 Dominic Mazzoni
8
9 This class implements a LADSPA Plug-in effect.
10
11*******************************************************************//****************************************************************//*******************************************************************/
23
24
25
26#include "LadspaEffect.h" // This class's header file
27#include "SampleCount.h"
28#include "ConfigInterface.h"
29
30#include <float.h>
31#include <thread>
32
33#if !defined(__WXMSW__)
34#include <dlfcn.h>
35
36#ifndef RTLD_DEEPBIND
37#define RTLD_DEEPBIND 0
38#endif
39#endif
40
41#include <wx/setup.h> // for wxUSE_* macros
42#include <wx/wxprec.h>
43#include <wx/button.h>
44#include <wx/checkbox.h>
45#include <wx/dcclient.h>
46#include <wx/filename.h>
47#include <wx/log.h>
48#include <wx/menu.h>
49#include <wx/sizer.h>
50#include <wx/slider.h>
51#include <wx/statbox.h>
52#include <wx/stattext.h>
53#include <wx/textctrl.h>
54#include <wx/tokenzr.h>
55#include <wx/intl.h>
56#include <wx/scrolwin.h>
57#include <wx/version.h>
58
59#include "AudacityException.h"
60#include "FileNames.h"
61#include "../../ShuttleGui.h"
62#include "../../widgets/NumericTextCtrl.h"
63#include "../../widgets/valnum.h"
64#include "../../widgets/wxPanelWrapper.h"
65#include "ModuleManager.h"
66
67#if wxUSE_ACCESSIBILITY
68#include "../../widgets/WindowAccessible.h"
69#endif
70
71// ============================================================================
72// List of effects that ship with Audacity. These will be autoregistered.
73// ============================================================================
74const static wxChar *kShippedEffects[] =
75{
76 wxT("sc4_1882.dll"),
77};
78
79// ============================================================================
80// Module registration entry point
81//
82// This is the symbol that Audacity looks for when the module is built as a
83// dynamic library.
84//
85// When the module is builtin to Audacity, we use the same function, but it is
86// declared static so as not to clash with other builtin modules.
87// ============================================================================
89{
90 // Create and register the importer
91 // Trust the module manager not to leak this
93}
94
95// ============================================================================
96// Register this as a builtin module
97// ============================================================================
99
101//
102// LadspaEffectsModule
103//
105
107{
108}
109
111{
112}
113
114// Don't use the template-generated MakeSettings(), which default-constructs
115// the structure. Instead allocate a number of values chosen by the plug-in
117{
118 auto result = EffectSettings::Make<LadspaEffectSettings>( mData->PortCount );
120 return result;
121}
122
124 const EffectSettings &src, EffectSettings &dst) const
125{
126 // Do not use the copy constructor of std::vector. Do an in-place rewrite
127 // of the destination vector, which will not allocate memory if dstControls
128 // began with sufficient capacity.
129 auto &srcControls = GetSettings(src).controls;
130 auto &dstControls = GetSettings(dst).controls;
131 dstControls.resize(0);
132 copy(srcControls.begin(), srcControls.end(), back_inserter(dstControls));
133 return true;
134}
135
136// ============================================================================
137// ComponentInterface implementation
138// ============================================================================
139
141{
142 return {};
143}
144
146{
147 /* i18n-hint: abbreviates "Linux Audio Developer's Simple Plugin API"
148 (Application programming interface)
149 */
150 return XO("LADSPA Effects");
151}
152
154{
155 return XO("The Audacity Team");
156}
157
159{
160 // This "may" be different if this were to be maintained as a separate DLL
162}
163
165{
166 return XO("Provides LADSPA Effects");
167}
168
169// ============================================================================
170// PluginProvider implementation
171// ============================================================================
172
174{
175 // Nothing to do here
176 return true;
177}
178
180{
181 // Nothing to do here
182 return;
183}
184
186{
187#if USE_LADSPA
189#else
190 return {};
191#endif
192}
193
195{
196 static FileExtensions result{{
197
198#ifdef __WXMSW__
199
200 _T("dll")
201
202#else
203
204 _T("so")
205
206 #ifdef __WXMAC__
207 // Is it correct that these are candidate plug-in files too for macOs?
208 , _T("dylib")
209 #endif
210
211#endif
212
213 }};
214 return result;
215}
216
218{
219 // To do: better choice
220 return FileNames::PlugInDir();
221}
222
224{
225 // Autoregister effects that we "think" are ones that have been shipped with
226 // Audacity. A little simplistic, but it should suffice for now.
227 auto pathList = GetSearchPaths();
228 FilePaths files;
229 TranslatableString ignoredErrMsg;
230
231 for (int i = 0; i < (int)WXSIZEOF(kShippedEffects); i++)
232 {
233 files.clear();
234 pm.FindFilesInPathList(kShippedEffects[i], pathList, files);
235 for (size_t j = 0, cnt = files.size(); j < cnt; j++)
236 {
237 if (!pm.IsPluginRegistered(files[j]))
238 {
239 // No checking for error ?
240 DiscoverPluginsAtPath(files[j], ignoredErrMsg,
242 }
243 }
244 }
245}
246
248{
249 auto pathList = GetSearchPaths();
250 FilePaths files;
251
252#if defined(__WXMAC__)
253
254 // Recursively scan for all shared objects
255 pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
256
257#elif defined(__WXMSW__)
258
259 // Recursively scan for all DLLs
260 pm.FindFilesInPathList(wxT("*.dll"), pathList, files, true);
261
262#else
263
264 // Recursively scan for all shared objects
265 pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
266
267#endif
268
269 return { files.begin(), files.end() };
270}
271
273 const PluginPath & path, TranslatableString &errMsg,
274 const RegistrationCallback &callback)
275{
276 errMsg = {};
277 // Since we now have builtin VST support, ignore the VST bridge as it
278 // causes duplicate menu entries to appear.
279 wxFileName ff(path);
280 if (ff.GetName().CmpNoCase(wxT("vst-bridge")) == 0) {
281 errMsg = XO("Audacity no longer uses vst-bridge");
282 return 0;
283 }
284
285 // As a courtesy to some plug-ins that might be bridges to
286 // open other plug-ins, we set the current working
287 // directory to be the plug-in's directory.
288 wxString envpath;
289 bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
290 wxSetEnv(wxT("PATH"), ff.GetPath() + wxFILE_SEP_PATH + envpath);
291 wxString saveOldCWD = ff.GetCwd();
292 ff.SetCwd();
293
294 int index = 0;
295 int nLoaded = 0;
296 LADSPA_Descriptor_Function mainFn = NULL;
297
298#if defined(__WXMSW__)
299 wxDynamicLibrary lib;
300 if (lib.Load(path, wxDL_NOW))
301#else
302 void *lib = dlopen((const char *)path.ToUTF8(), RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
303 if (lib)
304#endif
305 {
306
307#if defined(__WXMSW__)
308 wxLogNull logNo;
309
310 mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor"));
311#else
312 mainFn = (LADSPA_Descriptor_Function) dlsym(lib, "ladspa_descriptor");
313#endif
314
315 if (mainFn) {
316 const LADSPA_Descriptor *data;
317
318 for (data = mainFn(index); data; data = mainFn(++index)) {
319 LadspaEffect effect(path, index);
320 if (effect.InitializePlugin()) {
321 ++nLoaded;
322 if (callback)
323 callback( this, &effect );
324 }
325 else
326 errMsg = XO("Could not load the library");
327 }
328 }
329 }
330 else
331 errMsg = XO("Could not load the library");
332
333#if defined(__WXMSW__)
334 if (lib.IsLoaded()) {
335 // PRL: I suspect Bug1257 -- Crash when enabling Amplio2 -- is the fault of a timing-
336 // dependent multi-threading bug in the Amplio2 library itself, in case the unload of the .dll
337 // comes too soon after the load. I saw the bug in Release builds but not Debug.
338 // A sleep of even 1 ms was enough to fix the problem for me, but let's be even more generous.
339 using namespace std::chrono;
340 std::this_thread::sleep_for(10ms);
341 lib.Unload();
342 }
343#else
344 if (lib) {
345 dlclose(lib);
346 }
347#endif
348
349 wxSetWorkingDirectory(saveOldCWD);
350 hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));
351
352 return nLoaded;
353}
354
355bool LadspaEffectsModule::IsPluginValid(const PluginPath & path, bool bFast)
356{
357 if( bFast )
358 return true;
359 wxString realPath = path.BeforeFirst(wxT(';'));
360 return wxFileName::FileExists(realPath);
361}
362
363std::unique_ptr<ComponentInterface>
365{
366 // Acquires a resource for the application.
367 // For us, the path is two words.
368 // 1) The library's path
369 // 2) The LADSPA descriptor index
370 long index;
371 wxString realPath = path.BeforeFirst(wxT(';'));
372 path.AfterFirst(wxT(';')).ToLong(&index);
373 auto result = std::make_unique<LadspaEffect>(realPath, (int)index);
374 result->FullyInitializePlugin();
375 return result;
376}
377
379{
380 FilePaths pathList;
381 wxString pathVar;
382
383 // Check for the LADSPA_PATH environment variable
384 pathVar = wxString::FromUTF8(getenv("LADSPA_PATH"));
385 if (!pathVar.empty())
386 {
387 wxStringTokenizer tok(pathVar, wxPATH_SEP);
388 while (tok.HasMoreTokens())
389 {
390 pathList.push_back(tok.GetNextToken());
391 }
392 }
393
394#if defined(__WXMAC__)
395#define LADSPAPATH wxT("/Library/Audio/Plug-Ins/LADSPA")
396
397 // Look in ~/Library/Audio/Plug-Ins/LADSPA and /Library/Audio/Plug-Ins/LADSPA
398 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + LADSPAPATH);
399 pathList.push_back(LADSPAPATH);
400
401#elif defined(__WXMSW__)
402
403 // No special paths...probably should look in %CommonProgramFiles%\LADSPA
404
405#else
406
407 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".ladspa"));
408#if defined(__LP64__)
409 pathList.push_back(wxT("/usr/local/lib64/ladspa"));
410 pathList.push_back(wxT("/usr/lib64/ladspa"));
411#endif
412 pathList.push_back(wxT("/usr/local/lib/ladspa"));
413 pathList.push_back(wxT("/usr/lib/ladspa"));
414 pathList.push_back(wxT(LIBDIR) wxT("/ladspa"));
415
416#endif
417
418 return pathList;
419}
420
422//
423// LadspaEffectOptionsDialog
424//
426
428{
429public:
431 wxWindow * parent, EffectDefinitionInterface &effect, bool &var);
433
435
436 void OnOk(wxCommandEvent & evt);
437
438private:
441
442 DECLARE_EVENT_TABLE()
443};
444
448
450 wxWindow * parent, EffectDefinitionInterface &effect, bool &var)
451: wxDialogWrapper(parent, wxID_ANY, XO("LADSPA Effect Options"))
452, mEffect{ effect }
453, mUseLatency{ var }
454{
455 mUseLatency = LadspaEffect::LoadUseLatency(effect);
456
457 ShuttleGui S(this, eIsCreating);
458 PopulateOrExchange(S);
459}
460
462{
463}
464
465static const wchar_t *OptionsKey = L"Options";
466static const wchar_t *UseLatencyKey = L"UseLatency";
467
469{
470 bool result{};
472 OptionsKey, UseLatencyKey, result, true /* default value */);
473 return result;
474}
475
477 const EffectDefinitionInterface &effect, bool value)
478{
479 return SetConfig(
481}
482
484{
485 S.SetBorder(5);
486 S.StartHorizontalLay(wxEXPAND, 1);
487 {
488 S.StartVerticalLay(false);
489 {
490 S.StartStatic(XO("Latency Compensation"));
491 {
492 S.AddVariableText( XO(
493"As part of their processing, some LADSPA effects must delay returning "
494"audio to Audacity. When not compensating for this delay, you will "
495"notice that small silences have been inserted into the audio. "
496"Enabling this option will provide that compensation, but it may "
497"not work for all LADSPA effects."),
498 false, 0, 650);
499
500 S.StartHorizontalLay(wxALIGN_LEFT);
501 {
502 S.TieCheckBox(XXO("Enable &compensation"),
504 }
505 S.EndHorizontalLay();
506 }
507 S.EndStatic();
508 }
509 S.EndVerticalLay();
510 }
511 S.EndHorizontalLay();
512
513 S.AddStandardButtons();
514
515 Layout();
516 Fit();
517 Center();
518}
519
520void LadspaEffectOptionsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
521{
522 if (!Validate())
523 {
524 return;
525 }
526
528 // Note this call re-visits the controls, not to create them but to fetch
529 // the values, in this case mUseLatency
531
533
534 EndModal(wxID_OK);
535}
536
537enum
538{
539 ID_Duration = 20000,
540 ID_Toggles = 21000,
541 ID_Sliders = 22000,
542 ID_Texts = 23000,
543};
544
546//
547// LadspaEffectMeter
548//
550
551class LadspaEffectMeter final : public wxWindow
552{
553public:
554 LadspaEffectMeter(wxWindow *parent, const float & val, float min, float max);
555 virtual ~LadspaEffectMeter();
556
557private:
558 void OnErase(wxEraseEvent & evt);
559 void OnPaint(wxPaintEvent & evt);
560 void OnIdle(wxIdleEvent & evt);
561 void OnSize(wxSizeEvent & evt);
562
563private:
564 const float & mVal;
565 float mMin;
566 float mMax;
568
569 DECLARE_EVENT_TABLE()
570};
571
572BEGIN_EVENT_TABLE(LadspaEffectMeter, wxWindow)
574 EVT_ERASE_BACKGROUND(LadspaEffectMeter::OnErase)
578
579LadspaEffectMeter::LadspaEffectMeter(wxWindow *parent, const float & val, float min, float max)
580: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDEFAULT_CONTROL_BORDER),
581 mVal(val)
582{
583 mMin = min;
584 mMax = max;
585 mLastValue = -mVal;
586 SetBackgroundColour(*wxWHITE);
587}
588
590{
591}
592
593void LadspaEffectMeter::OnIdle(wxIdleEvent &evt)
594{
595 evt.Skip();
596 if (mLastValue != mVal)
597 Refresh(false);
598}
599
600void LadspaEffectMeter::OnErase(wxEraseEvent & WXUNUSED(evt))
601{
602 // Just ignore it to prevent flashing
603}
604
605void LadspaEffectMeter::OnPaint(wxPaintEvent & WXUNUSED(evt))
606{
607 wxPaintDC dc(this);
608
609 // Cache some metrics
610 wxRect r = GetClientRect();
611 wxCoord x = r.GetLeft();
612 wxCoord y = r.GetTop();
613 wxCoord w = r.GetWidth();
614 wxCoord h = r.GetHeight();
615
616 // These use unscaled value, min, and max
617 float val = mVal;
618 if (val > mMax)
619 val = mMax;
620 if (val < mMin)
621 val = mMin;
622 val -= mMin;
623
624 // Setup for erasing the background
625 dc.SetPen(*wxTRANSPARENT_PEN);
626 dc.SetBrush(wxColour(100, 100, 220));
627 dc.Clear();
628 dc.DrawRectangle(x, y, (w * (val / fabs(mMax - mMin))), h);
629
631}
632
633void LadspaEffectMeter::OnSize(wxSizeEvent & WXUNUSED(evt))
634{
635 Refresh(false);
636}
637
639//
640// LadspaEffect
641//
643
644LadspaEffect::LadspaEffect(const wxString & path, int index)
645 : mPath{ path }
646 , mIndex{ index }
647{
648}
649
651{
652}
653
654// ============================================================================
655// ComponentInterface implementation
656// ============================================================================
657
659{
660 return wxString::Format(wxT("%s;%d"), mPath, mIndex);
661}
662
664{
665 return LAT1CTOWX(mData->Name);
666}
667
669{
670 return { LAT1CTOWX(mData->Maker) };
671}
672
674{
675 return "n/a";
676}
677
679{
680 return Verbatim( LAT1CTOWX(mData->Copyright) );
681}
682
683// ============================================================================
684// EffectDefinitionInterface implementation
685// ============================================================================
686
688{
689 if (mAudioIns == 0 && mAudioOuts == 0)
690 {
691 return EffectTypeTool;
692 }
693
694 if (mAudioIns == 0)
695 {
696 return EffectTypeGenerate;
697 }
698
699 if (mAudioOuts == 0)
700 {
701 return EffectTypeAnalyze;
702 }
703
704 return EffectTypeProcess;
705}
706
708{
710}
711
713{
714 return mInteractive;
715}
716
718{
719 return false;
720}
721
723{
724 return GetType() != EffectTypeGenerate;
725}
726
728{
729 return mNumInputControls > 0;
730}
731
732namespace {
733std::pair<float, float>
734InputControlPortBounds(const LADSPA_PortRangeHint &hint, double sampleRate)
735{
736 // Find lower and upper bound values for ths hint
737 const auto multiplier =
738 LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? sampleRate : 1.0;
739 return { hint.LowerBound * multiplier, hint.UpperBound * multiplier };
740}
742 const LADSPA_PortRangeHint &hint, float val, float lower, float upper)
743{
744 if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) && val < lower)
745 val = lower;
746 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) && val > upper)
747 val = upper;
748 return val;
749}
751 const LADSPA_PortRangeHint &hint, double sampleRate)
752{
753 // See comments in library header ladspa.h about interpretation of macros
754 const auto bounds = InputControlPortBounds(hint, sampleRate);
755
756 // Function to find low, middle, or high default values
757 const auto combine = [bounds,
759 ](float lowWeight, float highWeight){
760 auto [lower, upper] = bounds;
761 return logarithmic
762 ? exp(log(lower) * lowWeight + log(upper) * highWeight)
763 : lower * lowWeight + upper * highWeight;
764 };
765
766 auto [lower, upper] = bounds;
767 auto val = 1.0f;
768 // Four bits of the descriptor describe mutually exclusive cases
771 default:
772 break;
774 val = lower; break;
776 val = combine(0.75, 0.25); break;
778 val = combine(0.5, 0.5); break;
780 val = combine(0.25, 0.75); break;
782 val = upper; break;
784 val = 0.0f; break;
786 val = 1.0f; break;
788 val = 100.0f; break;
790 val = 440.0f; break;
791 }
792
793 return ClampInputControlValue(hint, val, lower, upper);
794}
795}
796
798{
799 if (!Load())
800 return false;
801
804 for (unsigned long p = 0; p < mData->PortCount; p++) {
806
807 // Collect the audio ports
808 if (LADSPA_IS_PORT_AUDIO(d)) {
809 if (LADSPA_IS_PORT_INPUT(d))
810 mInputPorts[mAudioIns++] = p;
811 else if (LADSPA_IS_PORT_OUTPUT(d))
813 }
814 // Count control ports
815 else if (LADSPA_IS_PORT_CONTROL(d)) {
816 if (LADSPA_IS_PORT_INPUT(d)) {
817 mInteractive = true;
819 }
820 else if (LADSPA_IS_PORT_OUTPUT(d)) {
821 // LADSPA effects have a convention of providing latency on an output
822 // control port whose name is "latency".
823 if (strcmp(mData->PortNames[p], "latency") == 0)
824 mLatencyPort = p;
825 else {
826 mInteractive = true;
828 }
829 }
830 }
831 }
832 return true;
833}
834
836{
837 if (!InitializePlugin())
838 return false;
839
840 // Reading these values from the config file can't be done in the PluginHost
841 // process but isn't needed only for plugin discovery.
842
844 return true;
845}
846
848{
849 auto &controls = settings.controls;
850 // (Re-)initialize with right-sized vector
851 std::vector<float>(mData->PortCount).swap(controls);
852
853 for (unsigned long p = 0; p < mData->PortCount; ++p) {
856 // Determine the port's default value
857 controls[p] = InputControlPortDefaultValue(
859 else
860 controls[p] = 0;
861 }
862 return true;
863}
864
868{
870 bool ProcessInitialize(EffectSettings &settings, double sampleRate,
871 sampleCount totalLen, ChannelNames chanMap) override;
872 bool ProcessFinalize() override;
874 const float *const *inBlock, float *const *outBlock, size_t blockLen)
875 override;
876
877 sampleCount GetLatency(const EffectSettings &settings, double sampleRate)
878 override;
879
880 bool RealtimeInitialize(EffectSettings &settings, double sampleRate)
881 override;
883 EffectSettings &settings, unsigned numChannels, float sampleRate)
884 override;
885 bool RealtimeSuspend() override;
886 bool RealtimeResume() override;
888 size_t RealtimeProcess(size_t group, EffectSettings &settings,
889 const float *const *inBuf, float *const *outBuf, size_t numSamples)
890 override;
891 bool RealtimeProcessEnd(EffectSettings &settings) noexcept override;
892 bool RealtimeFinalize(EffectSettings &settings) noexcept override;
893
894 const LadspaEffect &GetEffect() const
895 { return static_cast<const LadspaEffect &>(mProcessor); }
896
897 bool mReady{ false };
898 bool mLatencyDone{ false };
900
901 // Realtime processing
902 std::vector<LADSPA_Handle> mSlaves;
903};
904
905std::shared_ptr<EffectInstance> LadspaEffect::MakeInstance() const
906{
907 return std::make_shared<Instance>(*this);
908}
909
911{
912 return mAudioIns;
913}
914
916{
917 return mAudioOuts;
918}
919
921{
922 return 0;
923}
924
926{
927 return 0;
928}
929
931 const EffectSettings &settings, double)
932{
933 auto &effect = GetEffect();
934 auto &controls = GetSettings(settings).controls;
935 if (effect.mUseLatency && effect.mLatencyPort >= 0 && !mLatencyDone) {
936 mLatencyDone = true;
937 return sampleCount{ controls[effect.mLatencyPort] };
938 }
939 return 0;
940}
941
943 EffectSettings &settings, double sampleRate, sampleCount, ChannelNames)
944{
945 /* Instantiate the plugin */
946 if (!mReady) {
947 auto &effect = GetEffect();
948 auto &ladspaSettings = GetSettings(settings);
949 mMaster = effect.InitInstance(sampleRate, ladspaSettings);
950 if (!mMaster)
951 return false;
952 mReady = true;
953 }
954 mLatencyDone = false;
955 return true;
956}
957
959{
960 if (mReady) {
961 mReady = false;
962 GetEffect().FreeInstance(mMaster);
963 mMaster = nullptr;
964 }
965
966 return true;
967}
968
970 const float *const *inBlock, float *const *outBlock, size_t blockLen)
971{
972 auto &effect = GetEffect();
973 for (unsigned i = 0; i < effect.mAudioIns; ++i)
974 effect.mData->connect_port(mMaster, effect.mInputPorts[i],
975 const_cast<float*>(inBlock[i]));
976
977 for (unsigned i = 0; i < effect.mAudioOuts; ++i)
978 effect.mData->connect_port(mMaster, effect.mOutputPorts[i], outBlock[i]);
979
980 effect.mData->run(mMaster, blockLen);
981 return blockLen;
982}
983
985{
986 return true;
987}
988
990 EffectSettings &settings, unsigned, float sampleRate)
991{
992 auto &effect = GetEffect();
993 auto &ladspaSettings = GetSettings(settings);
994 LADSPA_Handle slave = effect.InitInstance(sampleRate, ladspaSettings);
995 if (!slave)
996 {
997 return false;
998 }
999
1000 mSlaves.push_back(slave);
1001
1002 return true;
1003}
1004
1006{
1007return GuardedCall<bool>([&]{
1008 auto &effect = GetEffect();
1009 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; ++i)
1010 effect.FreeInstance(mSlaves[i]);
1011 mSlaves.clear();
1012
1013 return true;
1014});
1015}
1016
1018{
1019 return true;
1020}
1021
1023{
1024 return true;
1025}
1026
1028{
1029 return true;
1030}
1031
1033 const float *const *inbuf, float *const *outbuf, size_t numSamples)
1034{
1035 if (group >= mSlaves.size())
1036 return 0;
1037
1038 auto &effect = GetEffect();
1039 for (unsigned i = 0; i < effect.mAudioIns; ++i)
1040 effect.mData->connect_port(mSlaves[group], effect.mInputPorts[i],
1041 const_cast<float*>(inbuf[i]));
1042
1043 for (unsigned i = 0; i < effect.mAudioOuts; ++i)
1044 effect.mData->connect_port(
1045 mSlaves[group], effect.mOutputPorts[i], outbuf[i]);
1046
1047 effect.mData->run(mSlaves[group], numSamples);
1048
1049 return numSamples;
1050}
1051
1053{
1054 return true;
1055}
1056
1058 wxWindow &parent, wxDialog &dialog, bool forceModal)
1059{
1060 dialog.Layout();
1061 dialog.Fit();
1062 dialog.SetMinSize(dialog.GetSize());
1063
1064 if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal)
1065 {
1066 dialog.Show();
1067 return 0;
1068 }
1069
1070 return dialog.ShowModal();
1071}
1072
1074 const EffectSettings &settings, CommandParameters & parms) const
1075{
1076 const auto &controls = GetSettings(settings).controls;
1077 for (unsigned long p = 0; p < mData->PortCount; p++) {
1080 if (!parms.Write(LAT1CTOWX(mData->PortNames[p]), controls[p]))
1081 return false;
1082 }
1083 return true;
1084}
1085
1087 const CommandParameters & parms, EffectSettings &settings) const
1088{
1089 auto &controls = GetSettings(settings).controls;
1090 for (unsigned long p = 0; p < mData->PortCount; p++) {
1092
1093 if (LADSPA_IS_PORT_CONTROL(descriptor) &&
1094 LADSPA_IS_PORT_INPUT(descriptor)) {
1095 wxString labelText = LAT1CTOWX(mData->PortNames[p]);
1096 double d = 0.0;
1097 if (!parms.Read(labelText, &d))
1098 return false;
1099 controls[p] = d;
1100 }
1101 }
1102 return true;
1103}
1104
1106 const RegistryPath & name, EffectSettings &settings) const
1107{
1108 return LoadParameters(name, settings);
1109}
1110
1112 const RegistryPath & name, const EffectSettings &settings) const
1113{
1114 return SaveParameters(name, settings);
1115}
1116
1118{
1119 return {};
1120}
1121
1123{
1124 return true;
1125}
1126
1127// ============================================================================
1128// EffectUIClientInterface Implementation
1129// ============================================================================
1130
1133 EffectSettingsAccess &access, double sampleRate, EffectType type)
1134 : EffectUIValidator{ effect, access }
1135 , mSampleRate{ sampleRate }
1136 , mType{ type }
1137 // Copy settings
1138 , mSettings{ GetSettings(access.Get()) }
1139 {}
1140
1141 bool UpdateUI() override;
1142 bool ValidateUI() override;
1143
1144 void PopulateUI(ShuttleGui &S);
1145
1146 void OnCheckBox(wxCommandEvent & evt);
1147 void OnSlider(wxCommandEvent & evt);
1148 void OnTextCtrl(wxCommandEvent & evt);
1149 void RefreshControls();
1150
1152 { return static_cast<const LadspaEffect &>(mEffect); }
1153
1154 const double mSampleRate;
1157
1159 wxWeakRef<wxDialog> mDialog;
1160 wxWindow *mParent{};
1166};
1167
1169{
1170 RefreshControls();
1171 return true;
1172}
1173
1175{
1176 auto &effect = GetEffect();
1177 auto &controls = mSettings.controls;
1178 auto parent = S.GetParent();
1179
1180 mParent = parent;
1181
1182 const auto &data = *effect.mData;
1183 mToggles.reinit( data.PortCount );
1184 mSliders.reinit( data.PortCount );
1185 mFields.reinit( data.PortCount, true);
1186 mLabels.reinit( data.PortCount );
1187 mMeters.reinit( data.PortCount );
1188
1189 wxASSERT(mParent); // To justify safenew
1190 wxScrolledWindow *const w = safenew wxScrolledWindow(mParent,
1191 wxID_ANY,
1192 wxDefaultPosition,
1193 wxDefaultSize,
1194 wxVSCROLL | wxTAB_TRAVERSAL);
1195
1196 {
1197 auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
1198 w->SetScrollRate(0, 20);
1199
1200 // This fools NVDA into not saying "Panel" when the dialog gets focus
1201 w->SetName(wxT("\a"));
1202 w->SetLabel(wxT("\a"));
1203
1204 mainSizer->Add(w, 1, wxEXPAND);
1205 mParent->SetSizer(mainSizer.release());
1206 }
1207
1208 wxSizer *marginSizer;
1209 {
1210 auto uMarginSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
1211 marginSizer = uMarginSizer.get();
1212
1213 // Make user-adjustible input controls
1214 if (effect.mNumInputControls) {
1215 auto paramSizer = std::make_unique<wxStaticBoxSizer>(wxVERTICAL, w, _("Effect Settings"));
1216
1217 auto gridSizer = std::make_unique<wxFlexGridSizer>(5, 0, 0);
1218 gridSizer->AddGrowableCol(3);
1219
1220 wxControl *item;
1221
1222 // Add the duration control for generators
1223 if (mType == EffectTypeGenerate) {
1224 item = safenew wxStaticText(w, 0, _("Duration:"));
1225 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1226 auto &extra = mAccess.Get().extra;
1227 mDuration = safenew
1230 extra.GetDurationFormat(),
1231 extra.GetDuration(),
1232 mSampleRate,
1234 .AutoPos(true));
1235 mDuration->SetName( XO("Duration") );
1236 gridSizer->Add(mDuration, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
1237 gridSizer->Add(1, 1, 0);
1238 gridSizer->Add(1, 1, 0);
1239 gridSizer->Add(1, 1, 0);
1240 }
1241
1242 for (unsigned long p = 0; p < data.PortCount; ++p) {
1243 LADSPA_PortDescriptor d = data.PortDescriptors[p];
1245 {
1246 continue;
1247 }
1248
1249 wxString labelText = LAT1CTOWX(data.PortNames[p]);
1250 item = safenew wxStaticText(w, 0, wxString::Format(_("%s:"), labelText));
1251 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1252
1253 wxString fieldText;
1254 LADSPA_PortRangeHint hint = data.PortRangeHints[p];
1255
1257 mToggles[p] = safenew wxCheckBox(w, ID_Toggles + p, wxT(""));
1258 mToggles[p]->SetName(labelText);
1259 mToggles[p]->SetValue(controls[p] > 0);
1260 BindTo(*mToggles[p],
1261 wxEVT_COMMAND_CHECKBOX_CLICKED, &Validator::OnCheckBox);
1262 gridSizer->Add(mToggles[p], 0, wxALL, 5);
1263
1264 gridSizer->Add(1, 1, 0);
1265 gridSizer->Add(1, 1, 0);
1266 gridSizer->Add(1, 1, 0);
1267 continue;
1268 }
1269
1270 wxString bound;
1271 float lower = -FLT_MAX;
1272 float upper = FLT_MAX;
1273 bool haslo = false;
1274 bool hashi = false;
1275 bool forceint = false;
1276
1278 lower = hint.LowerBound;
1279 haslo = true;
1280 }
1281
1283 upper = hint.UpperBound;
1284 hashi = true;
1285 }
1286
1288 lower *= mSampleRate;
1289 upper *= mSampleRate;
1290 forceint = true;
1291 }
1292
1293 // Limit to the UI precision
1294 lower = ceilf(lower * 1000000.0) / 1000000.0;
1295 upper = floorf(upper * 1000000.0) / 1000000.0;
1296 controls[p] = roundf(controls[p] * 1000000.0) / 1000000.0;
1297
1298 if (haslo && controls[p] < lower)
1299 controls[p] = lower;
1300
1301 if (hashi && controls[p] > upper)
1302 controls[p] = upper;
1303
1304 // Don't specify a value at creation time. This prevents unwanted events
1305 // being sent to the OnTextCtrl() handler before the associated slider
1306 // has been created.
1307 mFields[p] = safenew wxTextCtrl(w, ID_Texts + p);
1308 mFields[p]->SetName(labelText);
1309 BindTo(*mFields[p],
1311 gridSizer->Add(mFields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
1312
1313 wxString str;
1314 if (haslo) {
1315 if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1316 {
1317 str.Printf(wxT("%d"), (int)(lower + 0.5));
1318 }
1319 else
1320 {
1322 }
1323 item = safenew wxStaticText(w, 0, str);
1324 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1325 }
1326 else
1327 gridSizer->Add(1, 1, 0);
1328
1329 mSliders[p] = safenew wxSliderWrapper(w, ID_Sliders + p,
1330 0, 0, 1000,
1331 wxDefaultPosition,
1332 wxSize(200, -1));
1333#if wxUSE_ACCESSIBILITY
1334 // so that name can be set on a standard control
1335 mSliders[p]->SetAccessible(safenew WindowAccessible(mSliders[p]));
1336#endif
1337 mSliders[p]->SetName(labelText);
1338 BindTo(*mSliders[p],
1339 wxEVT_COMMAND_SLIDER_UPDATED, &Validator::OnSlider);
1340 gridSizer->Add(mSliders[p], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);
1341
1342 if (hashi) {
1343 if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1344 str.Printf(wxT("%d"), (int)(upper + 0.5));
1345 else
1347 item = safenew wxStaticText(w, 0, str);
1348 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5);
1349 }
1350 else
1351 gridSizer->Add(1, 1, 0);
1352
1353 if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) {
1354 fieldText.Printf(wxT("%d"), (int)(controls[p] + 0.5));
1355
1356 IntegerValidator<float> vld(&controls[p]);
1357 vld.SetRange(haslo ? lower : INT_MIN,
1358 hashi ? upper : INT_MAX);
1359 mFields[p]->SetValidator(vld);
1360 }
1361 else {
1362 fieldText = Internat::ToDisplayString(controls[p]);
1363
1364 // > 12 decimal places can cause rounding errors in display.
1365 FloatingPointValidator<float> vld(6, &controls[p]);
1366 vld.SetRange(lower, upper);
1367
1368 // Set number of decimal places
1369 if (upper - lower < 10.0)
1370 vld.SetStyle(NumValidatorStyle::THREE_TRAILING_ZEROES);
1371 else if (upper - lower < 100.0)
1372 vld.SetStyle(NumValidatorStyle::TWO_TRAILING_ZEROES);
1373 else
1374 vld.SetStyle(NumValidatorStyle::ONE_TRAILING_ZERO);
1375
1376 mFields[p]->SetValidator(vld);
1377 }
1378
1379 // Set the textctrl value. This will trigger an event so OnTextCtrl()
1380 // can update the slider.
1381 mFields[p]->SetValue(fieldText);
1382 }
1383
1384 paramSizer->Add(gridSizer.release(), 0, wxEXPAND | wxALL, 5);
1385 marginSizer->Add(paramSizer.release(), 0, wxEXPAND | wxALL, 5);
1386 }
1387
1388 // Make output meters
1389 if (effect.mNumOutputControls > 0) {
1390 auto paramSizer = std::make_unique<wxStaticBoxSizer>(wxVERTICAL, w, _("Effect Output"));
1391
1392 auto gridSizer = std::make_unique<wxFlexGridSizer>(2, 0, 0);
1393 gridSizer->AddGrowableCol(1);
1394
1395 wxControl *item;
1396
1397 for (unsigned long p = 0; p < data.PortCount; ++p) {
1398 LADSPA_PortDescriptor d = data.PortDescriptors[p];
1400 continue;
1401
1402 wxString labelText = LAT1CTOWX(data.PortNames[p]);
1403 item = safenew wxStaticText(
1404 w, 0, wxString::Format(_("%s:"), labelText));
1405 gridSizer->Add(
1406 item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1407
1408 //LADSPA_PortRangeHint hint = data.PortRangeHints[p];
1409
1410 wxString bound;
1411 float lower = 0.0;
1412 float upper = 1.0;
1413
1414 // Limit to the UI precision
1415 lower = ceilf(lower * 1000000.0) / 1000000.0;
1416 upper = floorf(upper * 1000000.0) / 1000000.0;
1417 controls[p] = lower;
1418
1419 // Capture const reference to output control value for later
1420 // display update
1421 mMeters[p] = safenew LadspaEffectMeter(
1422 w, controls[p], lower, upper);
1423 mMeters[p]->SetLabel(labelText); // for screen readers
1424 gridSizer->Add(mMeters[p], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 5);
1425 }
1426
1427 paramSizer->Add(gridSizer.release(), 0, wxEXPAND | wxALL, 5);
1428 marginSizer->Add(paramSizer.release(), 0, wxEXPAND | wxALL, 5);
1429 }
1430
1431 w->SetSizer(uMarginSizer.release());
1432 }
1433
1434 w->Layout();
1435
1436 // Try to give the window a sensible default/minimum size
1437 wxSize sz1 = marginSizer->GetMinSize();
1438 wxSize sz2 = mParent->GetMinSize();
1439 w->SetMinSize( { std::min(sz1.x, sz2.x), std::min(sz1.y, sz2.y) } );
1440
1441 // And let the parent reduce to the NEW minimum if possible
1442 mParent->SetMinSize({ -1, -1 });
1443}
1444
1445std::unique_ptr<EffectUIValidator>
1448{
1449 auto result =
1450 std::make_unique<Validator>(*this, access, mProjectRate, GetType());
1451 result->PopulateUI(S);
1452 return result;
1453}
1454
1456{
1457 return false;
1458}
1459
1461{
1462 mAccess.ModifySettings([this](EffectSettings &settings){
1463 if (mType == EffectTypeGenerate)
1464 settings.extra.SetDuration(mDuration->GetValue());
1465 GetSettings(settings) = mSettings;
1466 });
1467 return true;
1468}
1469
1471{
1472 return false;
1473}
1474
1476{
1477}
1478
1480{
1481}
1482
1484{
1485 return true;
1486}
1487
1489{
1491 dlg.ShowModal();
1492}
1493
1494// ============================================================================
1495// LadspaEffect Implementation
1496// ============================================================================
1497
1499{
1500 if (mLib.IsLoaded())
1501 {
1502 return true;
1503 }
1504
1505 wxFileName ff = mPath;
1506 wxString envpath;
1507 bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
1508 wxSetEnv(wxT("PATH"), ff.GetPath() + wxFILE_SEP_PATH + envpath);
1509 wxString saveOldCWD = ff.GetCwd();
1510 ff.SetCwd();
1511
1512 LADSPA_Descriptor_Function mainFn = NULL;
1513
1514 if (mLib.Load(mPath, wxDL_NOW))
1515 {
1516 wxLogNull logNo;
1517
1518 mainFn = (LADSPA_Descriptor_Function) mLib.GetSymbol(wxT("ladspa_descriptor"));
1519 if (mainFn)
1520 {
1521 mData = mainFn(mIndex);
1522 return true;
1523 }
1524 }
1525
1526 if (mLib.IsLoaded())
1527 {
1528 mLib.Unload();
1529 }
1530
1531 wxSetWorkingDirectory(saveOldCWD);
1532 hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));
1533
1534 return false;
1535}
1536
1538{
1539 if (mLib.IsLoaded())
1540 {
1541 mLib.Unload();
1542 }
1543}
1544
1546 const RegistryPath & group, EffectSettings &settings) const
1547{
1548 wxString parms;
1549 if (!GetConfig(*this, PluginSettings::Private, group, wxT("Parameters"),
1550 parms, wxEmptyString))
1551 {
1552 return false;
1553 }
1554
1556 if (!eap.SetParameters(parms))
1557 {
1558 return false;
1559 }
1560
1561 return LoadSettings(eap, settings);
1562}
1563
1565 const RegistryPath & group, const EffectSettings &settings) const
1566{
1568 if (!SaveSettings(settings, eap))
1569 {
1570 return false;
1571 }
1572
1573 wxString parms;
1574 if (!eap.GetParameters(parms))
1575 {
1576 return false;
1577 }
1578
1579 return SetConfig(*this, PluginSettings::Private,
1580 group, wxT("Parameters"), parms);
1581}
1582
1584 float sampleRate, LadspaEffectSettings &settings) const
1585{
1586 /* Instantiate the plugin */
1587 LADSPA_Handle handle = mData->instantiate(mData, sampleRate);
1588 if (!handle)
1589 return nullptr;
1590
1591 auto &controls = settings.controls;
1592 for (unsigned long p = 0; p < mData->PortCount; ++p) {
1595 mData->connect_port(handle, p, &controls[p]);
1596 }
1597 if (mData->activate)
1598 mData->activate(handle);
1599
1600 return handle;
1601}
1602
1604{
1605 if (mData->deactivate)
1606 {
1607 mData->deactivate(handle);
1608 }
1609
1610 mData->cleanup(handle);
1611}
1612
1613void LadspaEffect::Validator::OnCheckBox(wxCommandEvent & evt)
1614{
1615 auto &controls = mSettings.controls;
1616 int p = evt.GetId() - ID_Toggles;
1617 controls[p] = mToggles[p]->GetValue();
1618 ValidateUI();
1619}
1620
1621void LadspaEffect::Validator::OnSlider(wxCommandEvent & evt)
1622{
1623 auto &controls = mSettings.controls;
1624 int p = evt.GetId() - ID_Sliders;
1625
1626 float val;
1627 float lower = float(0.0);
1628 float upper = float(10.0);
1629 float range;
1630 bool forceint = false;
1631
1632 LADSPA_PortRangeHint hint = GetEffect().mData->PortRangeHints[p];
1634 lower = hint.LowerBound;
1636 upper = hint.UpperBound;
1638 lower *= mSampleRate;
1639 upper *= mSampleRate;
1640 forceint = true;
1641 }
1642
1643 range = upper - lower;
1644 val = (mSliders[p]->GetValue() / 1000.0) * range + lower;
1645 wxString str;
1646 if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1647 str.Printf(wxT("%d"), (int)(val + 0.5));
1648 else
1650
1651 mFields[p]->SetValue(str);
1652 controls[p] = val;
1653 ValidateUI();
1654}
1655
1656void LadspaEffect::Validator::OnTextCtrl(wxCommandEvent & evt)
1657{
1658 auto &controls = mSettings.controls;
1659 int p = evt.GetId() - ID_Texts;
1660
1661 float val;
1662 float lower = float(0.0);
1663 float upper = float(10.0);
1664 float range;
1665
1666 val = Internat::CompatibleToDouble(mFields[p]->GetValue());
1667
1668 LADSPA_PortRangeHint hint = GetEffect().mData->PortRangeHints[p];
1670 lower = hint.LowerBound;
1672 upper = hint.UpperBound;
1674 lower *= mSampleRate;
1675 upper *= mSampleRate;
1676 }
1677 range = upper - lower;
1678 if (val < lower)
1679 val = lower;
1680 if (val > upper)
1681 val = upper;
1682
1683 controls[p] = val;
1684 mSliders[p]->SetValue((int)(((val-lower)/range) * 1000.0 + 0.5));
1685 ValidateUI();
1686}
1687
1689{
1690 if (!mParent)
1691 return;
1692
1693 auto &controls = mSettings.controls;
1694 // Copy from the dialog
1695 controls = GetSettings(mAccess.Get()).controls;
1696 const auto &data = *GetEffect().mData;
1697 for (unsigned long p = 0; p < data.PortCount; ++p) {
1698 LADSPA_PortDescriptor d = data.PortDescriptors[p];
1699 if (!(LADSPA_IS_PORT_CONTROL(d)))
1700 continue;
1701
1702 wxString fieldText;
1703 LADSPA_PortRangeHint hint = data.PortRangeHints[p];
1704
1705 bool forceint = false;
1707 forceint = true;
1708
1709 if (LADSPA_IS_PORT_OUTPUT(d))
1710 continue;
1711
1713 mToggles[p]->SetValue(controls[p] > 0);
1714 continue;
1715 }
1716
1717 if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1718 fieldText.Printf(wxT("%d"), (int)(controls[p] + 0.5));
1719 else
1720 fieldText = Internat::ToDisplayString(controls[p]);
1721
1722 // Set the textctrl value. This will trigger an event so OnTextCtrl()
1723 // can update the slider.
1724 mFields[p]->SetValue(fieldText);
1725 }
1726}
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
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
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 LAT1CTOWX(X)
Definition: Internat.h:160
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
DECLARE_PROVIDER_ENTRY(AudacityModule)
static const wxChar * kShippedEffects[]
static const wchar_t * UseLatencyKey
#define LADSPAPATH
@ ID_Texts
@ ID_Duration
@ ID_Sliders
@ ID_Toggles
DECLARE_BUILTIN_PROVIDER(LadspaBuiltin)
static const wchar_t * OptionsKey
#define LADSPAEFFECTS_VERSION
Definition: LadspaEffect.h:29
#define LADSPAEFFECTS_FAMILY
Definition: LadspaEffect.h:33
#define safenew
Definition: MemoryX.h:10
wxEVT_COMMAND_TEXT_UPDATED
Definition: Nyquist.cpp:133
wxString FilePath
Definition: Project.h:20
@ eIsCreating
Definition: ShuttleGui.h:39
@ eIsGettingFromDialog
Definition: ShuttleGui.h:40
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
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,...
double mProjectRate
Definition: EffectBase.h:99
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:29
wxWindow * mUIParent
Definition: Effect.h:270
bool ValidateUI(EffectSettings &) override
Definition: Effect.cpp:313
Performs effect computation.
Inherit to add a state variable to an EffectInstance subclass.
EffectUIClientInterface is an abstract base class to populate a UI and validate UI values....
Interface for transferring values from a panel of effect controls.
EffectUIClientInterface & mEffect
static LadspaEffectSettings & GetSettings(EffectSettings &settings)
Assume settings originated from MakeSettings() and copies thereof.
Definition: Effect.h:296
static wxString ToDisplayString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, uses the user's locale's decimal separator.
Definition: Internat.cpp:162
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:134
An Effect that calls up a LADSPA plug in, i.e. many possible effects from this one class.
Definition: LadspaEffect.h:55
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
LadspaEffect(const wxString &path, int index)
bool CopySettingsContents(const EffectSettings &src, EffectSettings &dst) const override
Update one settings object from another.
EffectFamilySymbol GetFamily() const override
Report identifier and user-visible name of the effect protocol.
bool SupportsAutomation() const override
Whether the effect has any automatable controls.
static bool LoadUseLatency(const EffectDefinitionInterface &effect)
int GetMidiInCount() const override
Function that has not yet found a use.
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Add controls to effect panel; always succeeds.
bool InitializePlugin()
bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const override
Store settings as keys and values.
bool CanExportPresets() override
void ImportPresets(EffectSettings &settings) override
unsigned mAudioOuts
Definition: LadspaEffect.h:160
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
const LADSPA_Descriptor * mData
Definition: LadspaEffect.h:148
bool IsGraphicalUI() override
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
bool SaveParameters(const RegistryPath &group, const EffectSettings &settings) const
int GetMidiOutCount() const override
Function that has not yet found a use.
int mNumInputControls
Definition: LadspaEffect.h:164
EffectType GetType() const override
Type determines how it behaves.
wxDynamicLibrary mLib
Definition: LadspaEffect.h:147
ComponentInterfaceSymbol GetSymbol() const override
static bool SaveUseLatency(const EffectDefinitionInterface &effect, bool value)
int ShowClientInterface(wxWindow &parent, wxDialog &dialog, bool forceModal) override
void FreeInstance(LADSPA_Handle handle) const
ArrayOf< unsigned long > mOutputPorts
Definition: LadspaEffect.h:162
const wxString mPath
Definition: LadspaEffect.h:144
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
LADSPA_Handle InitInstance(float sampleRate, LadspaEffectSettings &settings) const
bool SaveUserPreset(const RegistryPath &name, const EffectSettings &settings) const override
Save settings in the configuration file as a user-named preset.
bool HasOptions() override
wxString GetVersion() const override
void ShowOptions() override
void ExportPresets(const EffectSettings &settings) const override
bool LoadFactoryPreset(int id, EffectSettings &settings) const override
Change settings to the preset whose name is GetFactoryPresets()[id]
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
TranslatableString GetDescription() const override
bool InitializeControls(LadspaEffectSettings &settings) const
unsigned mAudioIns
Definition: LadspaEffect.h:156
const int mIndex
Definition: LadspaEffect.h:145
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
bool IsDefault() const override
Whether the effect sorts "above the line" in the menus.
bool FullyInitializePlugin()
PluginPath GetPath() const override
EffectSettings MakeSettings() const override
ArrayOf< unsigned long > mInputPorts
Definition: LadspaEffect.h:158
bool LoadParameters(const RegistryPath &group, EffectSettings &settings) const
VendorSymbol GetVendor() const override
bool SupportsRealtime() const override
Whether the effect supports realtime previewing (while audio is playing).
int mNumOutputControls
Definition: LadspaEffect.h:165
bool LoadUserPreset(const RegistryPath &name, EffectSettings &settings) const override
Change settings to a user-named preset.
virtual ~LadspaEffect()
const float & mVal
void OnErase(wxEraseEvent &evt)
void OnSize(wxSizeEvent &evt)
LadspaEffectMeter(wxWindow *parent, const float &val, float min, float max)
void OnIdle(wxIdleEvent &evt)
virtual ~LadspaEffectMeter()
void OnPaint(wxPaintEvent &evt)
LadspaEffectOptionsDialog(wxWindow *parent, EffectDefinitionInterface &effect, bool &var)
void PopulateOrExchange(ShuttleGui &S)
void OnOk(wxCommandEvent &evt)
EffectDefinitionInterface & mEffect
PluginPaths FindModulePaths(PluginManagerInterface &pm) override
virtual ~LadspaEffectsModule()
ComponentInterfaceSymbol GetSymbol() const override
std::unique_ptr< ComponentInterface > LoadPlugin(const PluginPath &path) override
Load the plug-in at a path reported by DiscoverPluginsAtPath.
FilePath InstallPath() override
Where plug-in files should be copied to install them.
TranslatableString GetDescription() const override
EffectFamilySymbol GetOptionalFamilySymbol() override
A symbol identifying the family of plug-ins provided by this.
bool IsPluginValid(const PluginPath &path, bool bFast) override
unsigned DiscoverPluginsAtPath(const PluginPath &path, TranslatableString &errMsg, const RegistrationCallback &callback) override
FilePaths GetSearchPaths()
const FileExtensions & GetFileExtensions() override
File types associated with this protocol.
VendorSymbol GetVendor() const override
void Terminate() override
Called just prior to deletion to allow releasing any resources.
wxString GetVersion() const override
bool Initialize() override
Called immediately after creation. Let provider initialize.
PluginPath GetPath() const override
void AutoRegisterPlugins(PluginManagerInterface &pm) override
Called so that a provider of a static set of plug-ins can register them.
Instance(const PerTrackEffect &processor)
const PerTrackEffect & mProcessor
virtual void FindFilesInPathList(const wxString &pattern, const FilePaths &pathList, FilePaths &files, bool directories=false)=0
virtual bool IsPluginRegistered(const PluginPath &path, const TranslatableString *pName=nullptr)=0
Was the plugin registry already populated for a path (maybe from loading the config file)?
static const PluginID & DefaultRegistrationCallback(PluginProvider *provider, ComponentInterface *ident)
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:628
Holds a msgid for the translation catalog; may also bind format arguments.
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
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.
#define LADSPA_HINT_DEFAULT_100
Definition: ladspa.h:303
#define LADSPA_IS_HINT_BOUNDED_BELOW(x)
Definition: ladspa.h:310
#define LADSPA_HINT_DEFAULT_MAXIMUM
Definition: ladspa.h:290
#define LADSPA_HINT_DEFAULT_440
Definition: ladspa.h:308
#define LADSPA_HINT_DEFAULT_LOW
Definition: ladspa.h:272
#define LADSPA_IS_HINT_BOUNDED_ABOVE(x)
Definition: ladspa.h:311
#define LADSPA_HINT_DEFAULT_0
Definition: ladspa.h:295
#define LADSPA_IS_HINT_INTEGER(x)
Definition: ladspa.h:315
#define LADSPA_IS_HINT_LOGARITHMIC(x)
Definition: ladspa.h:314
#define LADSPA_HINT_DEFAULT_HIGH
Definition: ladspa.h:286
#define LADSPA_IS_HINT_TOGGLED(x)
Definition: ladspa.h:312
#define LADSPA_HINT_DEFAULT_MASK
Definition: ladspa.h:258
#define LADSPA_HINT_DEFAULT_MIDDLE
Definition: ladspa.h:279
int LADSPA_PortDescriptor
Definition: ladspa.h:152
#define LADSPA_HINT_DEFAULT_1
Definition: ladspa.h:300
#define LADSPA_HINT_DEFAULT_MINIMUM
Definition: ladspa.h:265
const LADSPA_Descriptor *(* LADSPA_Descriptor_Function)(unsigned long Index)
Definition: ladspa.h:593
#define LADSPA_IS_PORT_INPUT(x)
Definition: ladspa.h:168
#define LADSPA_IS_PORT_AUDIO(x)
Definition: ladspa.h:171
void * LADSPA_Handle
Definition: ladspa.h:363
#define LADSPA_IS_PORT_CONTROL(x)
Definition: ladspa.h:170
#define LADSPA_IS_PORT_OUTPUT(x)
Definition: ladspa.h:169
#define LADSPA_HINT_DEFAULT_NONE
Definition: ladspa.h:261
#define LADSPA_IS_HINT_SAMPLE_RATE(x)
Definition: ladspa.h:313
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:26
FILES_API FilePath PlugInDir()
The user plug-in directory (not a system one)
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)
float InputControlPortDefaultValue(const LADSPA_PortRangeHint &hint, double sampleRate)
std::pair< float, float > InputControlPortBounds(const LADSPA_PortRangeHint &hint, double sampleRate)
float ClampInputControlValue(const LADSPA_PortRangeHint &hint, float val, float lower, float upper)
std::vector< CommandFlagOptions > & Options()
Definition: Menus.cpp:535
_LADSPA_Descriptor is a structure that provides the API to a LADSPA (Linux Audio Plugin Architecture)...
Definition: ladspa.h:373
LADSPA_Handle(* instantiate)(const struct _LADSPA_Descriptor *Descriptor, unsigned long SampleRate)
Definition: ladspa.h:437
void(* deactivate)(LADSPA_Handle Instance)
Definition: ladspa.h:549
void(* cleanup)(LADSPA_Handle Instance)
Definition: ladspa.h:558
const char *const * PortNames
Definition: ladspa.h:415
void(* activate)(LADSPA_Handle Instance)
Definition: ladspa.h:489
const char * Copyright
Definition: ladspa.h:402
void(* connect_port)(LADSPA_Handle Instance, unsigned long Port, LADSPA_Data *DataLocation)
Definition: ladspa.h:466
const LADSPA_PortDescriptor * PortDescriptors
Definition: ladspa.h:410
unsigned long PortCount
Definition: ladspa.h:406
const char * Name
Definition: ladspa.h:393
const char * Maker
Definition: ladspa.h:397
const LADSPA_PortRangeHint * PortRangeHints
Definition: ladspa.h:419
_LADSPA_PortRangeHint is a structure that gives parameter validation information for a LADSPA (Linux ...
Definition: ladspa.h:337
LADSPA_PortRangeHintDescriptor HintDescriptor
Definition: ladspa.h:340
LADSPA_Data LowerBound
Definition: ladspa.h:345
LADSPA_Data UpperBound
Definition: ladspa.h:350
Externalized state of a plug-in.
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
size_t RealtimeProcess(size_t group, EffectSettings &settings, const float *const *inBuf, float *const *outBuf, size_t numSamples) override
bool RealtimeResume() override
bool RealtimeAddProcessor(EffectSettings &settings, unsigned numChannels, float sampleRate) override
bool RealtimeProcessEnd(EffectSettings &settings) noexcept override
settings can be updated to let a dialog change appearance at idle
bool RealtimeInitialize(EffectSettings &settings, double sampleRate) override
bool ProcessInitialize(EffectSettings &settings, double sampleRate, sampleCount totalLen, ChannelNames chanMap) override
bool RealtimeProcessStart(EffectSettings &settings) override
settings are possibly changed, since last call, by an asynchronous dialog
bool ProcessFinalize() override
bool RealtimeSuspend() override
std::vector< LADSPA_Handle > mSlaves
const LadspaEffect & GetEffect() const
bool RealtimeFinalize(EffectSettings &settings) noexcept override
sampleCount GetLatency(const EffectSettings &settings, double sampleRate) override
bool UpdateUI() override
Update appearance of the panel for changes in settings.
void OnSlider(wxCommandEvent &evt)
ArrayOf< wxTextCtrl * > mFields
bool ValidateUI() override
Get settings data from the panel; may make error dialogs and return false.
ArrayOf< wxStaticText * > mLabels
ArrayOf< wxSlider * > mSliders
wxWeakRef< wxDialog > mDialog
void PopulateUI(ShuttleGui &S)
void OnCheckBox(wxCommandEvent &evt)
ArrayOf< wxCheckBox * > mToggles
LadspaEffectSettings mSettings
const LadspaEffect & GetEffect()
ArrayOf< LadspaEffectMeter * > mMeters
void OnTextCtrl(wxCommandEvent &evt)
NumericTextCtrl * mDuration
Validator(EffectUIClientInterface &effect, EffectSettingsAccess &access, double sampleRate, EffectType type)
const EffectType mType
std::vector< float > controls
Definition: LadspaEffect.h:50
Options & AutoPos(bool enable)