Audacity  2.2.2
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 #include "../../Audacity.h"
26 
27 #include "ladspa.h"
28 
29 #include <float.h>
30 
31 #include <wx/wxprec.h>
32 #include <wx/button.h>
33 #include <wx/checkbox.h>
34 #include <wx/dcbuffer.h>
35 #include <wx/dcclient.h>
36 #include <wx/dynlib.h>
37 #include <wx/filename.h>
38 #include <wx/log.h>
39 #include <wx/menu.h>
40 #include <wx/sizer.h>
41 #include <wx/slider.h>
42 #include <wx/statbox.h>
43 #include <wx/stattext.h>
44 #include <wx/textctrl.h>
45 #include <wx/tokenzr.h>
46 #include <wx/intl.h>
47 #include <wx/scrolwin.h>
48 #include <wx/version.h>
49 
50 #include "LadspaEffect.h" // This class's header file
51 #include "../../FileNames.h"
52 #include "../../Internat.h"
53 #include "../../ShuttleGui.h"
54 #include "../../widgets/valnum.h"
55 #include "../../widgets/wxPanelWrapper.h"
56 
57 // ============================================================================
58 // List of effects that ship with Audacity. These will be autoregistered.
59 // ============================================================================
60 const static wxChar *kShippedEffects[] =
61 {
62  wxT("sc4_1882.dll"),
63 };
64 
65 // ============================================================================
66 // Module registration entry point
67 //
68 // This is the symbol that Audacity looks for when the module is built as a
69 // dynamic library.
70 //
71 // When the module is builtin to Audacity, we use the same function, but it is
72 // declared static so as not to clash with other builtin modules.
73 // ============================================================================
74 DECLARE_MODULE_ENTRY(AudacityModule)
75 {
76  // Create and register the importer
77  // Trust the module manager not to leak this
78  return safenew LadspaEffectsModule(moduleManager, path);
79 }
80 
81 // ============================================================================
82 // Register this as a builtin module
83 // ============================================================================
84 DECLARE_BUILTIN_MODULE(LadspaBuiltin);
85 
87 //
88 // LadspaEffectsModule
89 //
91 
92 LadspaEffectsModule::LadspaEffectsModule(ModuleManagerInterface *moduleManager,
93  const wxString *path)
94 {
95  mModMan = moduleManager;
96  if (path)
97  {
98  mPath = *path;
99  }
100 }
101 
103 {
104 }
105 
106 // ============================================================================
107 // IdentInterface implementation
108 // ============================================================================
109 
111 {
112  return mPath;
113 }
114 
116 {
117  return XO("LADSPA Effects");
118 }
119 
121 {
122  return GetSymbol();
123 }
124 
126 {
127  return XO("The Audacity Team");
128 }
129 
131 {
132  // This "may" be different if this were to be maintained as a separate DLL
133  return LADSPAEFFECTS_VERSION;
134 }
135 
137 {
138  return _("Provides LADSPA Effects");
139 }
140 
141 // ============================================================================
142 // ModuleInterface implementation
143 // ============================================================================
144 
146 {
147  // Nothing to do here
148  return true;
149 }
150 
152 {
153  // Nothing to do here
154  return;
155 }
156 
158 {
159  static const wxString ext[] = {
160 
161 #ifdef __WXMSW__
162 
163  { _T("dll") }
164 
165 #else
166 
167  { _T("so") }
168 
169  #ifdef __WXMAC__
170  // Is it correct that these are candidate plug-in files too for macOs?
171  , { _T("dylib") }
172  #endif
173 
174 #endif
175 
176  };
177  static const wxArrayString result{ sizeof(ext)/sizeof(*ext), ext };
178  return result;
179 }
180 
182 {
183  // To do: better choice
184  return FileNames::PlugInDir();
185 }
186 
187 bool LadspaEffectsModule::AutoRegisterPlugins(PluginManagerInterface & pm)
188 {
189  // Autoregister effects that we "think" are ones that have been shipped with
190  // Audacity. A little simplistic, but it should suffice for now.
191  wxArrayString pathList = GetSearchPaths();
192  wxArrayString files;
193  wxString ignoredErrMsg;
194 
195  for (int i = 0; i < WXSIZEOF(kShippedEffects); i++)
196  {
197  files.Clear();
198  pm.FindFilesInPathList(kShippedEffects[i], pathList, files);
199  for (size_t j = 0, cnt = files.GetCount(); j < cnt; j++)
200  {
201  if (!pm.IsPluginRegistered(files[j]))
202  {
203  // No checking for error ?
204  DiscoverPluginsAtPath(files[j], ignoredErrMsg,
205  PluginManagerInterface::DefaultRegistrationCallback);
206  }
207  }
208  }
209 
210  // We still want to be called during the normal registration process
211  return false;
212 }
213 
214 wxArrayString LadspaEffectsModule::FindPluginPaths(PluginManagerInterface & pm)
215 {
216  wxArrayString pathList = GetSearchPaths();
217  wxArrayString files;
218 
219 #if defined(__WXMAC__)
220 
221  // Recursively scan for all shared objects
222  pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
223 
224 #elif defined(__WXMSW__)
225 
226  // Recursively scan for all DLLs
227  pm.FindFilesInPathList(wxT("*.dll"), pathList, files, true);
228 
229 #else
230 
231  // Recursively scan for all shared objects
232  pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
233 
234 #endif
235 
236  return files;
237 }
238 
240  const wxString & path, wxString &errMsg,
241  const RegistrationCallback &callback)
242 {
243  errMsg.clear();
244  // Since we now have builtin VST support, ignore the VST bridge as it
245  // causes duplicate menu entries to appear.
246  wxFileName ff(path);
247  if (ff.GetName().CmpNoCase(wxT("vst-bridge")) == 0) {
248  errMsg = _("Audacity no longer uses vst-bridge");
249  return 0;
250  }
251 
252  // As a courtesy to some plug-ins that might be bridges to
253  // open other plug-ins, we set the current working
254  // directory to be the plug-in's directory.
255  wxString envpath;
256  bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
257  wxSetEnv(wxT("PATH"), ff.GetPath() + wxFILE_SEP_PATH + envpath);
258  wxString saveOldCWD = ff.GetCwd();
259  ff.SetCwd();
260 
261  int index = 0;
262  int nLoaded = 0;
263  LADSPA_Descriptor_Function mainFn = NULL;
264  wxDynamicLibrary lib;
265  if (lib.Load(path, wxDL_NOW)) {
266  wxLogNull logNo;
267 
268  mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor"));
269  if (mainFn) {
270  const LADSPA_Descriptor *data;
271 
272  for (data = mainFn(index); data; data = mainFn(++index)) {
273  LadspaEffect effect(path, index);
274  if (effect.SetHost(NULL)) {
275  ++nLoaded;
276  if (callback)
277  callback( this, &effect );
278  }
279  else
280  errMsg = _("Could not load the library");
281  }
282  }
283  }
284  else
285  errMsg = _("Could not load the library");
286 
287  if (lib.IsLoaded()) {
288  // PRL: I suspect Bug1257 -- Crash when enabling Amplio2 -- is the fault of a timing-
289  // dependent multi-threading bug in the Amplio2 library itself, in case the unload of the .dll
290  // comes too soon after the load. I saw the bug in Release builds but not Debug.
291  // A sleep of even 1 ms was enough to fix the problem for me, but let's be even more generous.
292  ::wxMilliSleep(10);
293  lib.Unload();
294  }
295 
296  wxSetWorkingDirectory(saveOldCWD);
297  hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));
298 
299  return nLoaded;
300 }
301 
302 bool LadspaEffectsModule::IsPluginValid(const wxString & path, bool bFast)
303 {
304  if( bFast )
305  return true;
306  wxString realPath = path.BeforeFirst(wxT(';'));
307  return wxFileName::FileExists(realPath);
308 }
309 
310 IdentInterface *LadspaEffectsModule::CreateInstance(const wxString & path)
311 {
312  // Acquires a resource for the application.
313  // For us, the path is two words.
314  // 1) The library's path
315  // 2) The LADSPA descriptor index
316  long index;
317  wxString realPath = path.BeforeFirst(wxT(';'));
318  path.AfterFirst(wxT(';')).ToLong(&index);
319 
320  // Safety of this depends on complementary calls to DeleteInstance on the module manager side.
321  return safenew LadspaEffect(realPath, (int)index);
322 }
323 
324 void LadspaEffectsModule::DeleteInstance(IdentInterface *instance)
325 {
326  std::unique_ptr < LadspaEffect > {
327  dynamic_cast<LadspaEffect *>(instance)
328  };
329 }
330 
332 {
333  wxArrayString pathList;
334  wxArrayString files;
335  wxString pathVar;
336 
337  // Check for the LADSPA_PATH environment variable
338  pathVar = wxString::FromUTF8(getenv("LADSPA_PATH"));
339  if (!pathVar.empty())
340  {
341  wxStringTokenizer tok(pathVar);
342  while (tok.HasMoreTokens())
343  {
344  pathList.Add(tok.GetNextToken());
345  }
346  }
347 
348 #if defined(__WXMAC__)
349 #define LADSPAPATH wxT("/Library/Audio/Plug-Ins/LADSPA")
350 
351  // Look in ~/Library/Audio/Plug-Ins/LADSPA and /Library/Audio/Plug-Ins/LADSPA
352  pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + LADSPAPATH);
353  pathList.Add(LADSPAPATH);
354 
355 #elif defined(__WXMSW__)
356 
357  // No special paths...probably should look in %CommonProgramFiles%\LADSPA
358 
359 #else
360 
361  pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".ladspa"));
362  pathList.Add(wxT("/usr/local/lib/ladspa"));
363  pathList.Add(wxT("/usr/lib/ladspa"));
364  pathList.Add(wxT(LIBDIR) wxT("/ladspa"));
365 
366 #endif
367 
368  return pathList;
369 }
370 
372 //
373 // LadspaEffectOptionsDialog
374 //
376 
378 {
379 public:
380  LadspaEffectOptionsDialog(wxWindow * parent, EffectHostInterface *host);
381  virtual ~LadspaEffectOptionsDialog();
382 
383  void PopulateOrExchange(ShuttleGui & S);
384 
385  void OnOk(wxCommandEvent & evt);
386 
387 private:
388  EffectHostInterface *mHost;
390 
391  DECLARE_EVENT_TABLE()
392 };
393 
394 BEGIN_EVENT_TABLE(LadspaEffectOptionsDialog, wxDialogWrapper)
395  EVT_BUTTON(wxID_OK, LadspaEffectOptionsDialog::OnOk)
397 
398 LadspaEffectOptionsDialog::LadspaEffectOptionsDialog(wxWindow * parent, EffectHostInterface *host)
399 : wxDialogWrapper(parent, wxID_ANY, wxString(_("LADSPA Effect Options")))
400 {
401  mHost = host;
402 
403  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
404 
405  ShuttleGui S(this, eIsCreating);
406  PopulateOrExchange(S);
407 }
408 
410 {
411 }
412 
414 {
415  S.SetBorder(5);
416  S.StartHorizontalLay(wxEXPAND, 1);
417  {
418  S.StartVerticalLay(false);
419  {
420  S.StartStatic(_("Latency Compensation"));
421  {
422  S.AddVariableText(wxString() +
423  _("As part of their processing, some LADSPA effects must delay returning ") +
424  _("audio to Audacity. When not compensating for this delay, you will ") +
425  _("notice that small silences have been inserted into the audio. ") +
426  _("Enabling this option will provide that compensation, but it may ") +
427  _("not work for all LADSPA effects."))->Wrap(650);
428 
429  S.StartHorizontalLay(wxALIGN_LEFT);
430  {
431  S.TieCheckBox(_("Enable &compensation"),
432  mUseLatency);
433  }
434  S.EndHorizontalLay();
435  }
436  S.EndStatic();
437  }
438  S.EndVerticalLay();
439  }
440  S.EndHorizontalLay();
441 
442  S.AddStandardButtons();
443 
444  Layout();
445  Fit();
446  Center();
447 }
448 
449 void LadspaEffectOptionsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
450 {
451  if (!Validate())
452  {
453  return;
454  }
455 
457  PopulateOrExchange(S);
458 
459  mHost->SetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency);
460 
461  EndModal(wxID_OK);
462 }
463 
464 enum
465 {
466  ID_Duration = 20000,
467  ID_Toggles = 21000,
468  ID_Sliders = 22000,
469  ID_Texts = 23000,
470 };
471 
473 //
474 // LadspaEffectMeter
475 //
477 
478 class LadspaEffectMeter final : public wxWindow
479 {
480 public:
481  LadspaEffectMeter(wxWindow *parent, const float & val, float min, float max);
482  virtual ~LadspaEffectMeter();
483 
484 private:
485  void OnErase(wxEraseEvent & evt);
486  void OnPaint(wxPaintEvent & evt);
487  void OnIdle(wxIdleEvent & evt);
488  void OnSize(wxSizeEvent & evt);
489 
490 private:
491  const float & mVal;
492  float mMin;
493  float mMax;
494  float mLastValue;
495 
496  DECLARE_EVENT_TABLE()
497 };
498 
499 BEGIN_EVENT_TABLE(LadspaEffectMeter, wxWindow)
500  EVT_IDLE(LadspaEffectMeter::OnIdle)
501  EVT_ERASE_BACKGROUND(LadspaEffectMeter::OnErase)
502  EVT_PAINT(LadspaEffectMeter::OnPaint)
503  EVT_SIZE(LadspaEffectMeter::OnSize)
505 
506 LadspaEffectMeter::LadspaEffectMeter(wxWindow *parent, const float & val, float min, float max)
507 : wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDEFAULT_CONTROL_BORDER),
508  mVal(val)
509 {
510  mMin = min;
511  mMax = max;
512  mLastValue = -mVal;
513 
514  SetBackgroundColour(*wxWHITE);
515 }
516 
518 {
519 }
520 
521 void LadspaEffectMeter::OnIdle(wxIdleEvent & WXUNUSED(evt))
522 {
523  if (mLastValue != mVal)
524  {
525  Refresh(false);
526  }
527 }
528 
529 void LadspaEffectMeter::OnErase(wxEraseEvent & WXUNUSED(evt))
530 {
531  // Just ignore it to prevent flashing
532 }
533 
534 void LadspaEffectMeter::OnPaint(wxPaintEvent & WXUNUSED(evt))
535 {
536  wxPaintDC dc(this);
537 
538  // Cache some metrics
539  wxRect r = GetClientRect();
540  wxCoord x = r.GetLeft();
541  wxCoord y = r.GetTop();
542  wxCoord w = r.GetWidth();
543  wxCoord h = r.GetHeight();
544 
545  // These use unscaled value, min, and max
546  float val = mVal;
547  if (val > mMax)
548  {
549  val = mMax;
550  }
551  if (val < mMin)
552  {
553  val = mMin;
554  }
555  val -= mMin;
556 
557  // Setup for erasing the background
558  dc.SetPen(*wxTRANSPARENT_PEN);
559  dc.SetBrush(wxColour(100, 100, 220));
560 
561  dc.Clear();
562  dc.DrawRectangle(x, y, (w * (val / fabs(mMax - mMin))), h);
563 
564  mLastValue = mVal;
565 }
566 
567 void LadspaEffectMeter::OnSize(wxSizeEvent & WXUNUSED(evt))
568 {
569  Refresh(false);
570 }
571 
573 //
574 // LadspaEffect
575 //
577 
578 BEGIN_EVENT_TABLE(LadspaEffect, wxEvtHandler)
579  EVT_COMMAND_RANGE(ID_Toggles, ID_Toggles + 999, wxEVT_COMMAND_CHECKBOX_CLICKED, LadspaEffect::OnCheckBox)
580  EVT_COMMAND_RANGE(ID_Sliders, ID_Sliders + 999, wxEVT_COMMAND_SLIDER_UPDATED, LadspaEffect::OnSlider)
583 
584 LadspaEffect::LadspaEffect(const wxString & path, int index)
585 {
586  mPath = path;
587  mIndex = index;
588  mData = NULL;
589 
590  mHost = NULL;
591  mMaster = NULL;
592  mReady = false;
593 
594  mInteractive = false;
595 
596  mAudioIns = 0;
597  mAudioOuts = 0;
598  mNumInputControls = 0;
599  mNumOutputControls = 0;
600  mSampleRate = 44100;
601  mBlockSize = 0;
602 
603  mLatencyPort = -1;
604 
605  mDialog = NULL;
606  mParent = NULL;
607 }
608 
610 {
611 }
612 
613 // ============================================================================
614 // IdentInterface implementation
615 // ============================================================================
616 
618 {
619  return wxString::Format(wxT("%s;%d"), mPath, mIndex);
620 }
621 
623 {
624  return LAT1CTOWX(mData->Name);
625 }
626 
628 {
629  return GetSymbol();
630 }
631 
633 {
634  return LAT1CTOWX(mData->Maker);
635 }
636 
638 {
639  return _("n/a");
640 }
641 
643 {
644  return LAT1CTOWX(mData->Copyright);
645 }
646 
647 // ============================================================================
648 // EffectIdentInterface implementation
649 // ============================================================================
650 
652 {
653  if (mAudioIns == 0 && mAudioOuts == 0)
654  {
655  return EffectTypeNone;
656  }
657 
658  if (mAudioIns == 0)
659  {
660  return EffectTypeGenerate;
661  }
662 
663  if (mAudioOuts == 0)
664  {
665  return EffectTypeAnalyze;
666  }
667 
668  return EffectTypeProcess;
669 }
670 
672 {
673  return LADSPAEFFECTS_FAMILY;
674 }
675 
677 {
678  return mInteractive;
679 }
680 
682 {
683  return false;
684 }
685 
687 {
688  return false;
689 }
690 
692 {
693  return GetType() != EffectTypeGenerate;
694 }
695 
697 {
698  return mNumInputControls > 0;
699 }
700 
701 // ============================================================================
702 // EffectClientInterface Implementation
703 // ============================================================================
704 
705 bool LadspaEffect::SetHost(EffectHostInterface *host)
706 {
707  mHost = host;
708 
709  if (!Load())
710  {
711  return false;
712  }
713 
714  mInputPorts.reinit( mData->PortCount );
715  mOutputPorts.reinit( mData->PortCount );
716  mInputControls.reinit( mData->PortCount );
717  mOutputControls.reinit( mData->PortCount );
718 
719  for (unsigned long p = 0; p < mData->PortCount; p++)
720  {
721  LADSPA_PortDescriptor d = mData->PortDescriptors[p];
722 
723  // Collect the audio ports
724  if (LADSPA_IS_PORT_AUDIO(d))
725  {
726  if (LADSPA_IS_PORT_INPUT(d))
727  {
728  mInputPorts[mAudioIns++] = p;
729  }
730  else if (LADSPA_IS_PORT_OUTPUT(d))
731  {
732  mOutputPorts[mAudioOuts++] = p;
733  }
734  }
735  // Determine the port's default value
737  {
738  mInteractive = true;
739 
740  LADSPA_PortRangeHint hint = mData->PortRangeHints[p];
741  float val = float(1.0);
742  float lower = hint.LowerBound;
743  float upper = hint.UpperBound;
744 
746  {
747  lower *= mSampleRate;
748  upper *= mSampleRate;
749  }
750 
751  if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) && val < lower)
752  {
753  val = lower;
754  }
755 
756  if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) && val > upper)
757  {
758  val = upper;
759  }
760 
762  {
763  val = lower;
764  }
765 
767  {
768  val = upper;
769  }
770 
772  {
774  {
775  val = exp(log(lower) * 0.75f + log(upper) * 0.25f);
776  }
777  else
778  {
779  val = lower * 0.75f + upper * 0.25f;
780  }
781  }
782 
784  {
786  {
787  val = exp(log(lower) * 0.5f + log(upper) * 0.5f);
788  }
789  else
790  {
791  val = lower * 0.5f + upper * 0.5f;
792  }
793  }
794 
796  {
798  {
799  val = exp(log(lower) * 0.25f + log(upper) * 0.75f);
800  }
801  else
802  {
803  val = lower * 0.25f + upper * 0.75f;
804  }
805  }
806 
808  {
809  val = 0.0f;
810  }
811 
813  {
814  val = 1.0f;
815  }
816 
818  {
819  val = 100.0f;
820  }
821 
823  {
824  val = 440.0f;
825  }
826 
827  mNumInputControls++;
828  mInputControls[p] = val;
829  }
831  {
832  mOutputControls[p] = 0.0;
833 
834  // LADSPA effects have a convention of providing latency on an output
835  // control port whose name is "latency".
836  if (strcmp(mData->PortNames[p], "latency") == 0)
837  {
838  mLatencyPort = p;
839  }
840  else
841  {
842  mInteractive = true;
843  mNumOutputControls++;
844  }
845  }
846  }
847 
848  // mHost will be null during registration
849  if (mHost)
850  {
851  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
852 
853  bool haveDefaults;
854  mHost->GetPrivateConfig(mHost->GetFactoryDefaultsGroup(), wxT("Initialized"), haveDefaults, false);
855  if (!haveDefaults)
856  {
857  SaveParameters(mHost->GetFactoryDefaultsGroup());
858  mHost->SetPrivateConfig(mHost->GetFactoryDefaultsGroup(), wxT("Initialized"), true);
859  }
860 
861  LoadParameters(mHost->GetCurrentSettingsGroup());
862  }
863 
864  return true;
865 }
866 
868 {
869  return mAudioIns;
870 }
871 
873 {
874  return mAudioOuts;
875 }
876 
878 {
879  return 0;
880 }
881 
883 {
884  return 0;
885 }
886 
888 {
889  mSampleRate = rate;
890 }
891 
892 size_t LadspaEffect::SetBlockSize(size_t maxBlockSize)
893 {
894  mBlockSize = maxBlockSize;
895 
896  return mBlockSize;
897 }
898 
900 {
901  if (mUseLatency && mLatencyPort >= 0 && !mLatencyDone)
902  {
903  mLatencyDone = true;
904  return sampleCount ( mOutputControls[mLatencyPort] );
905  }
906 
907  return 0;
908 }
909 
911 {
912  return 0;
913 }
914 
916 {
917  return mReady;
918 }
919 
920 bool LadspaEffect::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
921 {
922  /* Instantiate the plugin */
923  if (!mReady)
924  {
925  mMaster = InitInstance(mSampleRate);
926  if (!mMaster)
927  {
928  return false;
929  }
930  mReady = true;
931  }
932 
933  mLatencyDone = false;
934 
935  return true;
936 }
937 
939 {
940  if (mReady)
941  {
942  mReady = false;
943 
944  FreeInstance(mMaster);
945  mMaster = NULL;
946  }
947 
948  return true;
949 }
950 
951 size_t LadspaEffect::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
952 {
953  for (int i = 0; i < (int)mAudioIns; i++)
954  {
955  mData->connect_port(mMaster, mInputPorts[i], inBlock[i]);
956  }
957 
958  for (int i = 0; i < (int)mAudioOuts; i++)
959  {
960  mData->connect_port(mMaster, mOutputPorts[i], outBlock[i]);
961  }
962 
963  mData->run(mMaster, blockLen);
964 
965  RefreshControls(true);
966 
967  return blockLen;
968 }
969 
971 {
972  return true;
973 }
974 
975 bool LadspaEffect::RealtimeAddProcessor(unsigned WXUNUSED(numChannels), float sampleRate)
976 {
977  LADSPA_Handle slave = InitInstance(sampleRate);
978  if (!slave)
979  {
980  return false;
981  }
982 
983  mSlaves.Add(slave);
984 
985  return true;
986 }
987 
989 {
990  for (size_t i = 0, cnt = mSlaves.GetCount(); i < cnt; i++)
991  {
992  FreeInstance(mSlaves[i]);
993  }
994  mSlaves.Clear();
995 
996  return true;
997 }
998 
1000 {
1001  return true;
1002 }
1003 
1005 {
1006  return true;
1007 }
1008 
1010 {
1011  return true;
1012 }
1013 
1015  float **inbuf,
1016  float **outbuf,
1017  size_t numSamples)
1018 {
1019  for (int i = 0; i < (int)mAudioIns; i++)
1020  {
1021  mData->connect_port(mSlaves[group], mInputPorts[i], inbuf[i]);
1022  }
1023 
1024  for (int i = 0; i < (int)mAudioOuts; i++)
1025  {
1026  mData->connect_port(mSlaves[group], mOutputPorts[i], outbuf[i]);
1027  }
1028 
1029  mData->run(mSlaves[group], numSamples);
1030 
1031  return numSamples;
1032 }
1033 
1035 {
1036  return true;
1037 }
1038 
1039 bool LadspaEffect::ShowInterface(wxWindow *parent, bool forceModal)
1040 {
1041  if (mDialog)
1042  {
1043  if ( mDialog->Close(true) )
1044  mDialog = nullptr;
1045  return false;
1046  }
1047 
1048  // mDialog is null
1049  auto cleanup = valueRestorer( mDialog );
1050 
1051  mDialog = mHost->CreateUI(parent, this);
1052  if (!mDialog)
1053  {
1054  return false;
1055  }
1056 
1057  mDialog->Layout();
1058  mDialog->Fit();
1059  mDialog->SetMinSize(mDialog->GetSize());
1060 
1061  if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal)
1062  {
1063  mDialog->Show();
1064  cleanup.release();
1065 
1066  return false;
1067  }
1068 
1069  bool res = mDialog->ShowModal() != 0;
1070 
1071  return res;
1072 }
1073 
1074 bool LadspaEffect::GetAutomationParameters(EffectAutomationParameters & parms)
1075 {
1076  for (unsigned long p = 0; p < mData->PortCount; p++)
1077  {
1078  LADSPA_PortDescriptor d = mData->PortDescriptors[p];
1079 
1081  {
1082  if (!parms.Write(LAT1CTOWX(mData->PortNames[p]), mInputControls[p]))
1083  {
1084  return false;
1085  }
1086  }
1087  }
1088 
1089  return true;
1090 }
1091 
1092 bool LadspaEffect::SetAutomationParameters(EffectAutomationParameters & parms)
1093 {
1094  for (unsigned long p = 0; p < mData->PortCount; p++)
1095  {
1096  LADSPA_PortDescriptor d = mData->PortDescriptors[p];
1097 
1099  {
1100  wxString labelText = LAT1CTOWX(mData->PortNames[p]);
1101  double d = 0.0;
1102  if (!parms.Read(labelText, &d))
1103  {
1104  return false;
1105  }
1106 
1107  mInputControls[p] = d;
1108  }
1109  }
1110 
1111  return true;
1112 }
1113 
1114 bool LadspaEffect::LoadUserPreset(const wxString & name)
1115 {
1116  if (!LoadParameters(name))
1117  {
1118  return false;
1119  }
1120 
1121  RefreshControls();
1122 
1123  return true;
1124 }
1125 
1126 bool LadspaEffect::SaveUserPreset(const wxString & name)
1127 {
1128  return SaveParameters(name);
1129 }
1130 
1132 {
1133  return wxArrayString();
1134 }
1135 
1136 bool LadspaEffect::LoadFactoryPreset(int WXUNUSED(id))
1137 {
1138  return true;
1139 }
1140 
1142 {
1143  if (!LoadParameters(mHost->GetFactoryDefaultsGroup()))
1144  {
1145  return false;
1146  }
1147 
1148  RefreshControls();
1149 
1150  return true;
1151 }
1152 
1153 // ============================================================================
1154 // EffectUIClientInterface Implementation
1155 // ============================================================================
1156 
1157 void LadspaEffect::SetHostUI(EffectUIHostInterface *host)
1158 {
1159  mUIHost = host;
1160 }
1161 
1162 bool LadspaEffect::PopulateUI(wxWindow *parent)
1163 {
1164  mParent = parent;
1165 
1166  mParent->PushEventHandler(this);
1167 
1168  mToggles.reinit( mData->PortCount );
1169  mSliders.reinit( mData->PortCount );
1170  mFields.reinit( mData->PortCount, true);
1171  mLabels.reinit( mData->PortCount );
1172  mMeters.reinit( mData->PortCount );
1173 
1174  wxASSERT(mParent); // To justify safenew
1175  wxScrolledWindow *const w = safenew wxScrolledWindow(mParent,
1176  wxID_ANY,
1177  wxDefaultPosition,
1178  wxDefaultSize,
1179  wxVSCROLL | wxTAB_TRAVERSAL);
1180 
1181  {
1182  auto mainSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
1183  w->SetScrollRate(0, 20);
1184 
1185  // This fools NVDA into not saying "Panel" when the dialog gets focus
1186  w->SetName(wxT("\a"));
1187  w->SetLabel(wxT("\a"));
1188 
1189  mainSizer->Add(w, 1, wxEXPAND);
1190  mParent->SetSizer(mainSizer.release());
1191  }
1192 
1193  wxSizer *marginSizer;
1194  {
1195  auto uMarginSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
1196  marginSizer = uMarginSizer.get();
1197 
1198  if (mNumInputControls)
1199  {
1200  auto paramSizer = std::make_unique<wxStaticBoxSizer>(wxVERTICAL, w, _("Effect Settings"));
1201 
1202  auto gridSizer = std::make_unique<wxFlexGridSizer>(5, 0, 0);
1203  gridSizer->AddGrowableCol(3);
1204 
1205  wxControl *item;
1206 
1207  // Add the duration control for generators
1208  if (GetType() == EffectTypeGenerate)
1209  {
1210  item = safenew wxStaticText(w, 0, _("Duration:"));
1211  gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1212  mDuration = safenew
1214  w,
1215  ID_Duration,
1216  mHost->GetDurationFormat(),
1217  mHost->GetDuration(),
1218  mSampleRate,
1219  wxDefaultPosition,
1220  wxDefaultSize,
1221  true);
1222  mDuration->SetName(_("Duration"));
1223  mDuration->EnableMenu();
1224  gridSizer->Add(mDuration, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
1225  gridSizer->Add(1, 1, 0);
1226  gridSizer->Add(1, 1, 0);
1227  gridSizer->Add(1, 1, 0);
1228  }
1229 
1230  for (unsigned long p = 0; p < mData->PortCount; p++)
1231  {
1232  LADSPA_PortDescriptor d = mData->PortDescriptors[p];
1234  {
1235  continue;
1236  }
1237 
1238  wxString labelText = LAT1CTOWX(mData->PortNames[p]);
1239  item = safenew wxStaticText(w, 0, labelText + wxT(":"));
1240  gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1241 
1242  wxString fieldText;
1243  LADSPA_PortRangeHint hint = mData->PortRangeHints[p];
1244 
1246  {
1247  mToggles[p] = safenew wxCheckBox(w, ID_Toggles + p, wxT(""));
1248  mToggles[p]->SetName(labelText);
1249  mToggles[p]->SetValue(mInputControls[p] > 0);
1250  gridSizer->Add(mToggles[p], 0, wxALL, 5);
1251 
1252  gridSizer->Add(1, 1, 0);
1253  gridSizer->Add(1, 1, 0);
1254  gridSizer->Add(1, 1, 0);
1255  continue;
1256  }
1257 
1258  wxString bound;
1259  float lower = -FLT_MAX;
1260  float upper = FLT_MAX;
1261  bool haslo = false;
1262  bool hashi = false;
1263  bool forceint = false;
1264 
1266  {
1267  lower = hint.LowerBound;
1268  haslo = true;
1269  }
1270 
1272  {
1273  upper = hint.UpperBound;
1274  hashi = true;
1275  }
1276 
1278  {
1279  lower *= mSampleRate;
1280  upper *= mSampleRate;
1281  forceint = true;
1282  }
1283 
1284  // Limit to the UI precision
1285  lower = ceilf(lower * 1000000.0) / 1000000.0;
1286  upper = floorf(upper * 1000000.0) / 1000000.0;
1287  mInputControls[p] = roundf(mInputControls[p] * 1000000.0) / 1000000.0;
1288 
1289  if (haslo && mInputControls[p] < lower)
1290  {
1291  mInputControls[p] = lower;
1292  }
1293 
1294  if (hashi && mInputControls[p] > upper)
1295  {
1296  mInputControls[p] = lower;
1297  }
1298 
1299  // Don't specify a value at creation time. This prevents unwanted events
1300  // being sent to the OnTextCtrl() handler before the associated slider
1301  // has been created.
1302  mFields[p] = safenew wxTextCtrl(w, ID_Texts + p);
1303  mFields[p]->SetName(labelText);
1304  gridSizer->Add(mFields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
1305 
1306  wxString str;
1307  if (haslo)
1308  {
1309  if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1310  {
1311  str.Printf(wxT("%d"), (int)(lower + 0.5));
1312  }
1313  else
1314  {
1315  str = Internat::ToDisplayString(lower);
1316  }
1317  item = safenew wxStaticText(w, 0, str);
1318  gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1319  }
1320  else
1321  {
1322  gridSizer->Add(1, 1, 0);
1323  }
1324 
1325  mSliders[p] = safenew wxSlider(w, ID_Sliders + p,
1326  0, 0, 1000,
1327  wxDefaultPosition,
1328  wxSize(200, -1));
1329  mSliders[p]->SetName(labelText);
1330  gridSizer->Add(mSliders[p], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);
1331 
1332  if (hashi)
1333  {
1334  if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1335  {
1336  str.Printf(wxT("%d"), (int)(upper + 0.5));
1337  }
1338  else
1339  {
1340  str = Internat::ToDisplayString(upper);
1341  }
1342  item = safenew wxStaticText(w, 0, str);
1343  gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5);
1344  }
1345  else
1346  {
1347  gridSizer->Add(1, 1, 0);
1348  }
1349 
1350  if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1351  {
1352  fieldText.Printf(wxT("%d"), (int)(mInputControls[p] + 0.5));
1353 
1354  IntegerValidator<float> vld(&mInputControls[p]);
1355  vld.SetRange(haslo ? lower : INT_MIN,
1356  hashi ? upper : INT_MAX);
1357  mFields[p]->SetValidator(vld);
1358  }
1359  else
1360  {
1361  fieldText = Internat::ToDisplayString(mInputControls[p]);
1362 
1363  // > 12 decimal places can cause rounding errors in display.
1364  FloatingPointValidator<float> vld(6, &mInputControls[p]);
1365  vld.SetRange(lower, upper);
1366 
1367  // Set number of decimal places
1368  if (upper - lower < 10.0)
1369  {
1370  vld.SetStyle(NUM_VAL_THREE_TRAILING_ZEROES);
1371  }
1372  else if (upper - lower < 100.0)
1373  {
1374  vld.SetStyle(NUM_VAL_TWO_TRAILING_ZEROES);
1375  }
1376  else
1377  {
1378  vld.SetStyle(NUM_VAL_ONE_TRAILING_ZERO);
1379  }
1380 
1381  mFields[p]->SetValidator(vld);
1382  }
1383 
1384  // Set the textctrl value. This will trigger an event so OnTextCtrl()
1385  // can update the slider.
1386  mFields[p]->SetValue(fieldText);
1387  }
1388 
1389  paramSizer->Add(gridSizer.release(), 0, wxEXPAND | wxALL, 5);
1390  marginSizer->Add(paramSizer.release(), 0, wxEXPAND | wxALL, 5);
1391  }
1392 
1393  if (mNumOutputControls > 0)
1394  {
1395  auto paramSizer = std::make_unique<wxStaticBoxSizer>(wxVERTICAL, w, _("Effect Output"));
1396 
1397  auto gridSizer = std::make_unique<wxFlexGridSizer>(2, 0, 0);
1398  gridSizer->AddGrowableCol(1);
1399 
1400  wxControl *item;
1401 
1402  for (unsigned long p = 0; p < mData->PortCount; p++)
1403  {
1404  LADSPA_PortDescriptor d = mData->PortDescriptors[p];
1406  {
1407  continue;
1408  }
1409 
1410  wxString labelText = LAT1CTOWX(mData->PortNames[p]);
1411  item = safenew wxStaticText(w, 0, labelText + wxT(":"));
1412  gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
1413 
1414  //LADSPA_PortRangeHint hint = mData->PortRangeHints[p];
1415 
1416  wxString bound;
1417  float lower = 0.0;
1418  float upper = 1.0;
1419 
1420  /*
1421  bool haslo = false;
1422  bool hashi = false;
1423  bool forceint = false;
1424 
1425  if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor))
1426  {
1427  lower = hint.LowerBound;
1428  haslo = true;
1429  }
1430 
1431  if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor))
1432  {
1433  upper = hint.UpperBound;
1434  hashi = true;
1435  }
1436 
1437  if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor))
1438  {
1439  lower *= mSampleRate;
1440  upper *= mSampleRate;
1441  forceint = true;
1442  }
1443  */
1444 
1445  // Limit to the UI precision
1446  lower = ceilf(lower * 1000000.0) / 1000000.0;
1447  upper = floorf(upper * 1000000.0) / 1000000.0;
1448  mInputControls[p] = roundf(mInputControls[p] * 1000000.0) / 1000000.0;
1449 
1450  mMeters[p] = safenew LadspaEffectMeter(w, mOutputControls[p], lower, upper);
1451  mMeters[p]->SetName(labelText);
1452  gridSizer->Add(mMeters[p], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 5);
1453  }
1454 
1455  paramSizer->Add(gridSizer.release(), 0, wxEXPAND | wxALL, 5);
1456  marginSizer->Add(paramSizer.release(), 0, wxEXPAND | wxALL, 5);
1457 
1458  RefreshControls(true);
1459  }
1460 
1461  w->SetSizer(uMarginSizer.release());
1462  }
1463 
1464  w->Layout();
1465 
1466  // Try to give the window a sensible default/minimum size
1467  wxSize sz1 = marginSizer->GetMinSize();
1468  wxSize sz2 = mParent->GetMinSize();
1469  w->SetSizeHints(wxSize(wxMin(sz1.x, sz2.x), wxMin(sz1.y, sz2.y)));
1470 
1471  // And let the parent reduce to the NEW minimum if possible
1472  mParent->SetSizeHints(-1, -1);
1473 
1474  return true;
1475 }
1476 
1478 {
1479  return false;
1480 }
1481 
1483 {
1484  if (!mParent->Validate())
1485  {
1486  return false;
1487  }
1488 
1489  if (GetType() == EffectTypeGenerate)
1490  {
1491  mHost->SetDuration(mDuration->GetValue());
1492  }
1493 
1494  return true;
1495 }
1496 
1498 {
1499  return true;
1500 }
1501 
1503 {
1504  mParent->RemoveEventHandler(this);
1505 
1506  mToggles.reset();
1507  mSliders.reset();
1508  mFields.reset();
1509  mLabels.reset();
1510 
1511  mUIHost = NULL;
1512  mParent = NULL;
1513  mDialog = NULL;
1514 
1515  return true;
1516 }
1517 
1519 {
1520  return false;
1521 }
1522 
1524 {
1525 }
1526 
1528 {
1529 }
1530 
1532 {
1533  return true;
1534 }
1535 
1537 {
1538  LadspaEffectOptionsDialog dlg(mParent, mHost);
1539  if (dlg.ShowModal())
1540  {
1541  // Reinitialize configuration options
1542  mHost->GetSharedConfig(wxT("Options"), wxT("UseLatency"), mUseLatency, true);
1543  }
1544 }
1545 
1546 // ============================================================================
1547 // LadspaEffect Implementation
1548 // ============================================================================
1549 
1551 {
1552  if (mLib.IsLoaded())
1553  {
1554  return true;
1555  }
1556 
1557  wxFileName ff = mPath;
1558  wxString envpath;
1559  bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
1560  wxSetEnv(wxT("PATH"), ff.GetPath() + wxFILE_SEP_PATH + envpath);
1561  wxString saveOldCWD = ff.GetCwd();
1562  ff.SetCwd();
1563 
1564  LADSPA_Descriptor_Function mainFn = NULL;
1565 
1566  if (mLib.Load(mPath, wxDL_NOW))
1567  {
1568  wxLogNull logNo;
1569 
1570  mainFn = (LADSPA_Descriptor_Function) mLib.GetSymbol(wxT("ladspa_descriptor"));
1571  if (mainFn)
1572  {
1573  mData = mainFn(mIndex);
1574  return true;
1575  }
1576  }
1577 
1578  if (mLib.IsLoaded())
1579  {
1580  mLib.Unload();
1581  }
1582 
1583  wxSetWorkingDirectory(saveOldCWD);
1584  hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));
1585 
1586  return false;
1587 }
1588 
1590 {
1591  if (mLib.IsLoaded())
1592  {
1593  mLib.Unload();
1594  }
1595 }
1596 
1597 bool LadspaEffect::LoadParameters(const wxString & group)
1598 {
1599  wxString parms;
1600  if (!mHost->GetPrivateConfig(group, wxT("Parameters"), parms, wxEmptyString))
1601  {
1602  return false;
1603  }
1604 
1605  EffectAutomationParameters eap;
1606  if (!eap.SetParameters(parms))
1607  {
1608  return false;
1609  }
1610 
1611  return SetAutomationParameters(eap);
1612 }
1613 
1614 bool LadspaEffect::SaveParameters(const wxString & group)
1615 {
1616  EffectAutomationParameters eap;
1617  if (!GetAutomationParameters(eap))
1618  {
1619  return false;
1620  }
1621 
1622  wxString parms;
1623  if (!eap.GetParameters(parms))
1624  {
1625  return false;
1626  }
1627 
1628  return mHost->SetPrivateConfig(group, wxT("Parameters"), parms);
1629 }
1630 
1632 {
1633  /* Instantiate the plugin */
1634  LADSPA_Handle handle = mData->instantiate(mData, sampleRate);
1635  if (!handle)
1636  {
1637  return NULL;
1638  }
1639 
1640  for (unsigned long p = 0; p < mData->PortCount; p++)
1641  {
1642  LADSPA_PortDescriptor d = mData->PortDescriptors[p];
1643  if (LADSPA_IS_PORT_CONTROL(d))
1644  {
1645  if (LADSPA_IS_PORT_INPUT(d))
1646  {
1647  mData->connect_port(handle, p, &mInputControls[p]);
1648  }
1649  else
1650  {
1651  mData->connect_port(handle, p, &mOutputControls[p]);
1652  }
1653  }
1654  }
1655 
1656  if (mData->activate)
1657  {
1658  mData->activate(handle);
1659  }
1660 
1661  return handle;
1662 }
1663 
1665 {
1666  if (mData->deactivate)
1667  {
1668  mData->deactivate(handle);
1669  }
1670 
1671  mData->cleanup(handle);
1672 }
1673 
1674 void LadspaEffect::OnCheckBox(wxCommandEvent & evt)
1675 {
1676  int p = evt.GetId() - ID_Toggles;
1677 
1678  mInputControls[p] = mToggles[p]->GetValue();
1679 }
1680 
1681 void LadspaEffect::OnSlider(wxCommandEvent & evt)
1682 {
1683  int p = evt.GetId() - ID_Sliders;
1684 
1685  float val;
1686  float lower = float(0.0);
1687  float upper = float(10.0);
1688  float range;
1689  bool forceint = false;
1690 
1691  LADSPA_PortRangeHint hint = mData->PortRangeHints[p];
1693  lower = hint.LowerBound;
1695  upper = hint.UpperBound;
1697  lower *= mSampleRate;
1698  upper *= mSampleRate;
1699  forceint = true;
1700  }
1701 
1702  range = upper - lower;
1703 
1704  val = (mSliders[p]->GetValue() / 1000.0) * range + lower;
1705 
1706  wxString str;
1707  if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1708  str.Printf(wxT("%d"), (int)(val + 0.5));
1709  else
1710  str = Internat::ToDisplayString(val);
1711 
1712  mFields[p]->SetValue(str);
1713 
1714  mInputControls[p] = val;
1715 }
1716 
1717 void LadspaEffect::OnTextCtrl(wxCommandEvent & evt)
1718 {
1719  LadspaEffect *that = reinterpret_cast<LadspaEffect *>(this);
1720  int p = evt.GetId() - ID_Texts;
1721 
1722  float val;
1723  float lower = float(0.0);
1724  float upper = float(10.0);
1725  float range;
1726 
1727  val = Internat::CompatibleToDouble(that->mFields[p]->GetValue());
1728 
1729  LADSPA_PortRangeHint hint = that->mData->PortRangeHints[p];
1730  if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor))
1731  lower = hint.LowerBound;
1732  if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor))
1733  upper = hint.UpperBound;
1734  if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) {
1735  lower *= mSampleRate;
1736  upper *= mSampleRate;
1737  }
1738  range = upper - lower;
1739 
1740  if (val < lower)
1741  val = lower;
1742  if (val > upper)
1743  val = upper;
1744 
1745  mInputControls[p] = val;
1746 
1747  that->mSliders[p]->SetValue((int)(((val-lower)/range) * 1000.0 + 0.5));
1748 }
1749 
1750 void LadspaEffect::RefreshControls(bool outputOnly)
1751 {
1752  if (!mParent)
1753  {
1754  return;
1755  }
1756 
1757  for (unsigned long p = 0; p < mData->PortCount; p++)
1758  {
1759  LADSPA_PortDescriptor d = mData->PortDescriptors[p];
1760  if (!(LADSPA_IS_PORT_CONTROL(d)))
1761  {
1762  continue;
1763  }
1764 
1765  wxString fieldText;
1766  LADSPA_PortRangeHint hint = mData->PortRangeHints[p];
1767 
1768  bool forceint = false;
1770  {
1771  forceint = true;
1772  }
1773 
1774  if (LADSPA_IS_PORT_OUTPUT(d))
1775  {
1776  continue;
1777  }
1778 
1779  if (outputOnly)
1780  {
1781  continue;
1782  }
1783 
1785  {
1786  mToggles[p]->SetValue(mInputControls[p] > 0);
1787  continue;
1788  }
1789 
1790  if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
1791  {
1792  fieldText.Printf(wxT("%d"), (int)(mInputControls[p] + 0.5));
1793  }
1794  else
1795  {
1796  fieldText = Internat::ToDisplayString(mInputControls[p]);
1797  }
1798 
1799  // Set the textctrl value. This will trigger an event so OnTextCtrl()
1800  // can update the slider.
1801  mFields[p]->SetValue(fieldText);
1802  }
1803 }
bool RealtimeProcessEnd() override
EVT_COMMAND_RANGE(ID_Slider, ID_Slider+NUMBER_OF_BANDS-1, wxEVT_COMMAND_SLIDER_UPDATED, EffectEqualization::OnSlider) EffectEqualization
virtual ~LadspaEffectMeter()
wxString GetSymbol() override
const LADSPA_Descriptor *(* LADSPA_Descriptor_Function)(unsigned long Index)
Definition: ladspa.h:593
bool LoadFactoryPreset(int id) override
void * LADSPA_Handle
Definition: ladspa.h:363
#define LADSPA_IS_HINT_DEFAULT_LOW(x)
Definition: ladspa.h:320
bool HasOptions() override
void ShowOptions() override
An Effect that calls up a LADSPA plug in, i.e. many possible effects from this one class...
Definition: LadspaEffect.h:41
bool RealtimeAddProcessor(unsigned numChannels, float sampleRate) override
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
bool AutoRegisterPlugins(PluginManagerInterface &pm) override
void DeleteInstance(IdentInterface *instance) override
void OnPaint(wxPaintEvent &evt)
EffectType GetType() override
size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) override
bool CanExportPresets() override
bool SaveParameters(const wxString &group)
EffectHostInterface * mHost
size_t SetBlockSize(size_t maxBlockSize) override
#define LADSPA_IS_HINT_TOGGLED(x)
Definition: ladspa.h:312
#define LADSPA_IS_HINT_INTEGER(x)
Definition: ladspa.h:315
wxString GetPath() override
bool ProcessFinalize() override
void OnTextCtrl(wxCommandEvent &evt)
wxString GetDescription() override
const LADSPA_PortRangeHint * PortRangeHints
Definition: ladspa.h:419
bool IsGraphicalUI() override
int LADSPA_PortDescriptor
Definition: ladspa.h:152
void ImportPresets() override
#define LADSPA_IS_HINT_DEFAULT_100(x)
Definition: ladspa.h:332
wxString GetVersion() override
DECLARE_BUILTIN_MODULE(LadspaBuiltin)
#define LADSPA_IS_HINT_BOUNDED_BELOW(x)
Definition: ladspa.h:310
void EnableMenu(bool enable=true)
Base class for many of the effects in Audacity.
Definition: Effect.h:62
#define XO(s)
Definition: Internat.h:30
wxString GetSymbol() override
void OnOk(wxCommandEvent &evt)
bool HideUI() override
wxArrayString GetFactoryPresets() override
#define LADSPA_IS_HINT_DEFAULT_HIGH(x)
Definition: ladspa.h:324
#define LADSPA_IS_HINT_SAMPLE_RATE(x)
Definition: ladspa.h:313
int GetMidiInCount() override
wxString GetVendor() override
wxString GetVendor() override
void SetSampleRate(double rate) override
wxString GetDescription() override
#define safenew
Definition: Audacity.h:223
ArrayOf< wxSlider * > mSliders
Definition: LadspaEffect.h:189
void EndHorizontalLay()
Definition: ShuttleGui.cpp:975
bool RealtimeSuspend() override
ArrayOf< wxTextCtrl * > mFields
Definition: LadspaEffect.h:190
wxArrayString FindPluginPaths(PluginManagerInterface &pm) override
void SetHostUI(EffectUIHostInterface *host) override
LADSPA_PortRangeHintDescriptor HintDescriptor
Definition: ladspa.h:340
void EndVerticalLay()
Definition: ShuttleGui.cpp:991
const LADSPA_Descriptor * mData
Definition: LadspaEffect.h:153
wxString InstallPath() override
unsigned GetAudioInCount() override
LADSPA_Handle InitInstance(float sampleRate)
size_t GetTailSize() override
sampleCount GetLatency() override
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:121
LadspaEffectsModule(ModuleManagerInterface *moduleManager, const wxString *path)
#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x)
Definition: ladspa.h:322
bool RealtimeFinalize() override
#define LADSPA_IS_HINT_DEFAULT_0(x)
Definition: ladspa.h:328
void FreeInstance(LADSPA_Handle handle)
void RefreshControls(bool outputOnly=false)
#define LADSPA_IS_PORT_CONTROL(x)
Definition: ladspa.h:170
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:966
int GetMidiOutCount() override
#define LADSPA_IS_HINT_DEFAULT_440(x)
Definition: ladspa.h:334
wxArrayString GetSearchPaths()
bool RealtimeResume() override
wxEVT_COMMAND_TEXT_UPDATED
Definition: Nyquist.cpp:112
virtual ~LadspaEffect()
wxString GetName() override
const float & mVal
void OnIdle(wxIdleEvent &evt)
_LADSPA_PortRangeHint is a structure that gives parameter validation information for a LADSPA (Linux ...
Definition: ladspa.h:337
if(pTrack &&pTrack->GetDisplay()!=WaveTrack::Spectrum)
unsigned GetAudioOutCount() override
int min(int a, int b)
wxString GetName() override
bool SupportsAutomation() override
#define LAT1CTOWX(X)
Definition: Internat.h:168
bool RealtimeProcessStart() override
DECLARE_MODULE_ENTRY(AudacityModule)
bool LoadUserPreset(const wxString &name) override
bool SetAutomationParameters(EffectAutomationParameters &parms) override
static const wxChar * kShippedEffects[]
void PopulateOrExchange(ShuttleGui &S)
size_t RealtimeProcess(int group, float **inbuf, float **outbuf, size_t numSamples) override
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x)
Definition: ladspa.h:318
wxString GetPath() override
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
#define LADSPA_IS_PORT_AUDIO(x)
Definition: ladspa.h:171
ValueRestorer< T > valueRestorer(T &var)
Definition: MemoryX.h:875
_LADSPA_Descriptor is a structure that provides the API to a LADSPA (Linux Audio Plugin Architecture)...
Definition: ladspa.h:373
bool LoadParameters(const wxString &group)
#define LADSPAEFFECTS_FAMILY
Definition: LadspaEffect.h:29
ModuleManagerInterface * mModMan
Definition: LadspaEffect.h:246
void OnErase(wxEraseEvent &evt)
bool Initialize() override
#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x)
Definition: ladspa.h:326
wxCheckBox * TieCheckBox(const wxString &Prompt, WrappedType &WrappedRef)
unsigned DiscoverPluginsAtPath(const wxString &path, wxString &errMsg, const RegistrationCallback &callback) override
#define LADSPA_IS_PORT_INPUT(x)
Definition: ladspa.h:168
const wxChar * name
Definition: Distortion.cpp:94
LADSPA_Data LowerBound
Definition: ladspa.h:345
bool IsReady() override
bool RealtimeInitialize() override
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:373
#define LADSPA_IS_HINT_BOUNDED_ABOVE(x)
Definition: ladspa.h:311
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:148
void OnSize(wxSizeEvent &evt)
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:701
bool IsPluginValid(const wxString &path, bool bFast) override
wxString GetVersion() override
#define LADSPA_IS_HINT_LOGARITHMIC(x)
Definition: ladspa.h:314
wxString GetFamily() override
bool SaveUserPreset(const wxString &name) override
void OnCheckBox(wxCommandEvent &evt)
void ExportPresets() override
bool SetHost(EffectHostInterface *host) override
bool GetAutomationParameters(EffectAutomationParameters &parms) override
#define LADSPAEFFECTS_VERSION
Definition: LadspaEffect.h:28
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
bool IsInteractive() override
END_EVENT_TABLE()
#define LADSPA_IS_PORT_OUTPUT(x)
Definition: ladspa.h:169
bool IsDefault() override
bool ShowInterface(wxWindow *parent, bool forceModal=false) override
void Terminate() override
bool SupportsRealtime() override
void SetBorder(int Border)
Definition: ShuttleGui.h:251
LADSPA_Data UpperBound
Definition: ladspa.h:350
bool CloseUI() override
static wxString PlugInDir()
The user plug-in directory (not a system one)
Definition: FileNames.cpp:208
bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap=NULL) override
bool ValidateUI() override
bool PopulateUI(wxWindow *parent) override
bool IsLegacy() override
IdentInterface * CreateInstance(const wxString &path) override
#define LADSPA_IS_HINT_DEFAULT_1(x)
Definition: ladspa.h:330
bool LoadFactoryDefaults() override
void OnSlider(wxCommandEvent &evt)
wxArrayString FileExtensions() override
virtual ~LadspaEffectsModule()
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:982