Audacity 3.2.0
LV2Effect.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 LV2Effect.cpp
6
7 Audacity(R) is copyright (c) 1999-2008 Audacity Team.
8 License: GPL v2 or later. See License.txt.
9
10**********************************************************************/
11
12
13
14#if defined(USE_LV2)
15
16#if defined(__GNUC__)
17#pragma GCC diagnostic ignored "-Wparentheses"
18#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
19#elif defined(__clang__)
20#pragma clang diagnostic ignored "-Wparentheses"
21#pragma clang diagnostic ignored "-Wdeprecated-declarations"
22#endif
23
24#include "LV2Effect.h"
25#include "SampleCount.h"
26
27#include <cmath>
28
29#include <wx/button.h>
30#include <wx/checkbox.h>
31#include <wx/choice.h>
32#include <wx/dcbuffer.h>
33#include <wx/dialog.h>
34#include <wx/crt.h>
35#include <wx/log.h>
36#include <wx/msgqueue.h>
37
38#ifdef __WXMAC__
39#include <wx/evtloop.h>
40#endif
41
42#include <wx/sizer.h>
43#include <wx/slider.h>
44#include <wx/statbox.h>
45#include <wx/stattext.h>
46#include <wx/tokenzr.h>
47#include <wx/intl.h>
48#include <wx/scrolwin.h>
49
50#include "AudacityException.h"
51#include "ConfigInterface.h"
52#include "../../ShuttleGui.h"
53#include "../../widgets/valnum.h"
54#include "../../widgets/AudacityMessageBox.h"
55#include "../../widgets/wxPanelWrapper.h"
56#include "../../widgets/NumericTextCtrl.h"
57
58#include "lv2/buf-size/buf-size.h"
59#include "lv2/instance-access/instance-access.h"
60
61#if defined(__WXGTK__)
62#include <gtk/gtk.h>
63#endif
64
65#if defined(__WXMSW__)
66#include <wx/msw/wrapwin.h>
67#endif
68
69// Define a maximum block size in number of samples (not bytes)
70#define DEFAULT_BLOCKSIZE 1048576
71
72// Define a reasonable default sequence size in bytes
73#define DEFAULT_SEQSIZE 8192
74
76//
77// LV2EffectMeter
78//
80
81class LV2EffectMeter final : public wxWindow
82{
83public:
84 LV2EffectMeter(wxWindow *parent, const LV2ControlPortPtr ctrl);
85 virtual ~LV2EffectMeter();
86
87private:
88 void OnErase(wxEraseEvent &evt);
89 void OnPaint(wxPaintEvent &evt);
90 void OnIdle(wxIdleEvent &evt);
91 void OnSize(wxSizeEvent &evt);
92
93private:
96
97 DECLARE_EVENT_TABLE()
98};
99
100BEGIN_EVENT_TABLE(LV2EffectMeter, wxWindow)
101 EVT_IDLE(LV2EffectMeter::OnIdle)
102 EVT_ERASE_BACKGROUND(LV2EffectMeter::OnErase)
103 EVT_PAINT(LV2EffectMeter::OnPaint)
104 EVT_SIZE(LV2EffectMeter::OnSize)
106
107LV2EffectMeter::LV2EffectMeter(wxWindow *parent, const LV2ControlPortPtr port)
108: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDEFAULT_CONTROL_BORDER),
109 mControlPort(port)
110{
111 mLastValue = -mControlPort->mVal;
112
113 SetBackgroundColour(*wxWHITE);
114}
115
117{
118}
119
120void LV2EffectMeter::OnIdle(wxIdleEvent &evt)
121{
122 evt.Skip();
123 if (mLastValue != mControlPort->mVal)
124 {
125 Refresh(false);
126 }
127}
128
129void LV2EffectMeter::OnErase(wxEraseEvent &WXUNUSED(evt))
130{
131 // Just ignore it to prevent flashing
132}
133
134void LV2EffectMeter::OnPaint(wxPaintEvent &WXUNUSED(evt))
135{
136 std::unique_ptr<wxDC> dc {wxAutoBufferedPaintDCFactory(this)};
137
138 // Cache some metrics
139 wxRect r = GetClientRect();
140 wxCoord x = r.GetLeft();
141 wxCoord y = r.GetTop();
142 wxCoord w = r.GetWidth();
143 wxCoord h = r.GetHeight();
144
145 // These use unscaled value, min, and max
146 float val = mControlPort->mVal;
147 if (val > mControlPort->mMax)
148 {
149 val = mControlPort->mMax;
150 }
151 if (val < mControlPort->mMin)
152 {
153 val = mControlPort->mMin;
154 }
155 val -= mControlPort->mMin;
156
157 // Setup for erasing the background
158 dc->SetPen(*wxTRANSPARENT_PEN);
159 dc->SetBrush(wxColour(100, 100, 220));
160
161 dc->Clear();
162 dc->DrawRectangle(x, y, (w * (val / fabs(mControlPort->mMax - mControlPort->mMin))), h);
163
164 mLastValue = mControlPort->mVal;
165}
166
167void LV2EffectMeter::OnSize(wxSizeEvent &WXUNUSED(evt))
168{
169 Refresh(false);
170}
171
173//
174// LV2EffectSettingsDialog
175//
177
179{
180public:
181 LV2EffectSettingsDialog(wxWindow *parent, LV2Effect &effect);
182 virtual ~LV2EffectSettingsDialog();
183
185
186 void OnOk(wxCommandEvent &evt);
187
188private:
193
194 DECLARE_EVENT_TABLE()
195};
196
200
202 wxWindow *parent, LV2Effect &effect)
203: wxDialogWrapper(parent, wxID_ANY, XO("LV2 Effect Settings"))
204, mEffect{ effect }
205{
206 GetConfig(mEffect, PluginSettings::Shared, wxT("Settings"),
207 wxT("BufferSize"), mBufferSize, 8192);
208 GetConfig(mEffect, PluginSettings::Shared, wxT("Settings"),
209 wxT("UseLatency"), mUseLatency, true);
210 GetConfig(mEffect, PluginSettings::Shared, wxT("Settings"),
211 wxT("UseGUI"), mUseGUI, true);
212
213 ShuttleGui S(this, eIsCreating);
214 PopulateOrExchange(S);
215}
216
218{
219}
220
222{
223 S.SetBorder(5);
224 S.StartHorizontalLay(wxEXPAND, 1);
225 {
226 S.StartVerticalLay(false);
227 {
228 // This really shouldn't be required for LV2 plugins because they have the ability
229 // to specify their exact requirements in the TTL file and/or to check the host
230 // supplied min/max values. However, I've run across one (Harrison Consoles XT-EQ)
231 // that crashed on sizes greater than 8192.
232 S.StartStatic(XO("Buffer Size"));
233 {
234 IntegerValidator<int> vld(&mBufferSize);
235 vld.SetRange(8, DEFAULT_BLOCKSIZE);
236
237 S.AddVariableText( XO(
238"The buffer size controls the number of samples sent to the effect "
239"on each iteration. Smaller values will cause slower processing and "
240"some effects require 8192 samples or less to work properly. However "
241"most effects can accept large buffers and using them will greatly "
242"reduce processing time."),
243 false, 0, 650);
244
245 S.StartHorizontalLay(wxALIGN_LEFT);
246 {
247 wxTextCtrl *t;
248 t = S.TieNumericTextBox(
249 XXO("&Buffer Size (8 to %d) samples:")
252 12);
253 t->SetMinSize(wxSize(100, -1));
254 t->SetValidator(vld);
255 }
256 S.EndHorizontalLay();
257 }
258 S.EndStatic();
259
260 S.StartStatic(XO("Latency Compensation"));
261 {
262 S.AddVariableText( XO(
263"As part of their processing, some LV2 effects must delay returning "
264"audio to Audacity. When not compensating for this delay, you will "
265"notice that small silences have been inserted into the audio. "
266"Enabling this setting will provide that compensation, but it may "
267"not work for all LV2 effects."),
268 false, 0, 650);
269
270 S.StartHorizontalLay(wxALIGN_LEFT);
271 {
272 S.TieCheckBox(XXO("Enable &compensation"),
274 }
275 S.EndHorizontalLay();
276 }
277 S.EndStatic();
278
279 S.StartStatic(XO("Graphical Mode"));
280 {
281 S.AddVariableText( XO(
282"LV2 effects can have a graphical interface for setting parameter values."
283" A basic text-only method is also available. "
284" Reopen the effect for this to take effect."),
285 false, 0, 650);
286 S.TieCheckBox(XXO("Enable &graphical interface"),
287 mUseGUI);
288 }
289 S.EndStatic();
290 }
291 S.EndVerticalLay();
292 }
293 S.EndHorizontalLay();
294
295 S.AddStandardButtons();
296
297 Layout();
298 Fit();
299 Center();
300}
301
302void LV2EffectSettingsDialog::OnOk(wxCommandEvent &WXUNUSED(evt))
303{
304 if (!Validate())
305 {
306 return;
307 }
308
311
312 SetConfig(mEffect, PluginSettings::Shared, wxT("Settings"),
313 wxT("BufferSize"), mBufferSize);
314 SetConfig(mEffect, PluginSettings::Shared, wxT("Settings"),
315 wxT("UseLatency"), mUseLatency);
316 SetConfig(mEffect, PluginSettings::Shared, wxT("Settings"),
317 wxT("UseGUI"), mUseGUI);
318
319 EndModal(wxID_OK);
320}
321
323//
324// LV2Effect
325//
327
328enum
329{
330 ID_Duration = 10000,
331 ID_Triggers = 11000,
332 ID_Toggles = 12000,
333 ID_Sliders = 13000,
334 ID_Choices = 14000,
335 ID_Texts = 15000,
336 ID_TIMER = 20000,
337};
338
339BEGIN_EVENT_TABLE(LV2Effect, wxEvtHandler)
341 EVT_COMMAND_RANGE(ID_Toggles, ID_Toggles + 999, wxEVT_COMMAND_CHECKBOX_CLICKED, LV2Effect::OnToggle)
342 EVT_COMMAND_RANGE(ID_Sliders, ID_Sliders + 999, wxEVT_COMMAND_SLIDER_UPDATED, LV2Effect::OnSlider)
343 EVT_COMMAND_RANGE(ID_Choices, ID_Choices + 999, wxEVT_COMMAND_CHOICE_SELECTED, LV2Effect::OnChoice)
345
346 EVT_TIMER(ID_TIMER, LV2Effect::OnTimer)
347 EVT_IDLE(LV2Effect::OnIdle)
349
350LV2Effect::LV2Effect(const LilvPlugin *plug)
351{
352 mPlug = plug;
353
354 mMaster = NULL;
355 mProcess = NULL;
356 mSuilInstance = NULL;
357
358 mSampleRate = 44100;
359 mBlockSize = DEFAULT_BLOCKSIZE;
360 mSeqSize = DEFAULT_SEQSIZE;
361
362 mMinBlockSize = 1;
363 mMaxBlockSize = mBlockSize;
364 mUserBlockSize = mBlockSize;
365
366 mLatencyPort = -1;
367 mLatencyDone = false;
368 mRolling = false;
369 mActivated = false;
370
371 mUIIdleInterface = NULL;
372 mUIShowInterface = NULL;
373
374 mAudioIn = 0;
375 mAudioOut = 0;
376 mMidiIn = 0;
377 mMidiOut = 0;
378
379 mControlIn.reset();
380 mControlOut.reset();
381
382 mPositionSpeed = 1.0;
383 mPositionFrame = 0.0;
384
385 mNativeWin = NULL;
386 mNativeWinInitialSize = wxDefaultSize;
387 mNativeWinLastSize = wxDefaultSize;
388 mResizing = false;
389#if defined(__WXGTK__)
390 mResized = false;
391#endif
392
393 mExternalUIHost.plugin_human_id = NULL;
394 mExternalWidget = NULL;
395 mExternalUIClosed = false;
396
397 mNoResize = false;
398
399 mSupportsNominalBlockLength = false;
400 mSupportsSampleRate = false;
401}
402
404{
405}
406
407// ============================================================================
408// ComponentInterface Implementation
409// ============================================================================
410
412{
413 return LilvString(lilv_plugin_get_uri(mPlug));
414}
415
417{
418 return LilvString(lilv_plugin_get_name(mPlug), true);
419}
420
422{
423 wxString vendor = LilvString(lilv_plugin_get_author_name(mPlug), true);
424
425 if (vendor.empty())
426 {
427 return XO("n/a");
428 }
429
430 return {vendor};
431}
432
433wxString LV2Effect::GetVersion() const
434{
435 return wxT("1.0");
436}
437
439{
440 return XO("n/a");
441}
442
443// ============================================================================
444// EffectDefinitionInterface Implementation
445// ============================================================================
446
448{
449 if (GetAudioInCount() == 0 && GetAudioOutCount() == 0)
450 {
451 return EffectTypeTool;
452 }
453
454 if (GetAudioInCount() == 0)
455 {
456 return EffectTypeGenerate;
457 }
458
459 if (GetAudioOutCount() == 0)
460 {
461 return EffectTypeAnalyze;
462 }
463
464 return EffectTypeProcess;
465}
466
468{
469 return LV2EFFECTS_FAMILY;
470}
471
473{
474 return mControlPorts.size() != 0;
475}
476
478{
479 return false;
480}
481
483{
484 // TODO reenable after achieving statelessness
485 return false;
486// return GetType() == EffectTypeProcess;
487}
488
490{
491 return true;
492}
493
495{
496 using namespace LV2Symbols;
497
498 AddOption(urid_SequenceSize, sizeof(mSeqSize), urid_Int, &mSeqSize);
499 AddOption(urid_MinBlockLength, sizeof(mMinBlockSize), urid_Int, &mMinBlockSize);
500 AddOption(urid_MaxBlockLength, sizeof(mMaxBlockSize), urid_Int, &mMaxBlockSize);
501
502 mBlockSizeOption = AddOption(urid_NominalBlockLength,
503 sizeof(mBlockSize),
504 urid_Int,
505 &mBlockSize);
506 mSampleRateOption = AddOption(urid_SampleRate,
507 sizeof(mSampleRate),
508 urid_Float,
509 &mSampleRate);
510 AddOption(0, 0, 0, NULL);
511
512 if (!ValidateOptions(lilv_plugin_get_uri(mPlug)))
513 {
514 return false;
515 }
516
517 mUriMapFeature.callback_data = this;
519
520 mURIDMapFeature.handle = this;
522
523 mURIDUnmapFeature.handle = this;
525
526 mUIResizeFeature.handle = this;
528
529 mLogFeature.handle = this;
532
534
535 LilvNode *pluginName = lilv_plugin_get_name(mPlug);
536 mExternalUIHost.plugin_human_id = lilv_node_as_string(pluginName);
537 lilv_node_free(pluginName);
538
539 AddFeature(LV2_UI__noUserResize, NULL);
540 AddFeature(LV2_UI__fixedSize, NULL);
541 AddFeature(LV2_UI__idleInterface, NULL);
543 AddFeature(LV2_BUF_SIZE__boundedBlockLength, NULL);
544 AddFeature(LV2_BUF_SIZE__fixedBlockLength, NULL);
545 AddFeature(LV2_OPTIONS__options, mOptions.data());
546 AddFeature(LV2_URI_MAP_URI, &mUriMapFeature);
547 AddFeature(LV2_URID__map, &mURIDMapFeature);
548 AddFeature(LV2_URID__unmap, &mURIDUnmapFeature);
549 AddFeature(LV2_UI__resize, &mUIResizeFeature);
550 AddFeature(LV2_DATA_ACCESS_URI, &mExtensionDataFeature);
551 AddFeature(LV2_LOG__log, &mLogFeature);
554 // Some plugins specify this as a feature
556
557 mInstanceAccessFeature = AddFeature(LV2_INSTANCE_ACCESS_URI, NULL);
558 mParentFeature = AddFeature(LV2_UI__parent, NULL);
559
560 AddFeature(NULL, NULL);
561
562 if (!ValidateFeatures(lilv_plugin_get_uri(mPlug)))
563 {
564 return false;
565 }
566
567 auto minLength = lilv_world_get(gWorld, lilv_plugin_get_uri(mPlug), node_MinBlockLength, NULL);
568 if (minLength)
569 {
570 if (lilv_node_is_int(minLength))
571 {
572 int val = lilv_node_as_int(minLength);
573 if (mMinBlockSize < val)
574 {
575 mMinBlockSize = val;
576 }
577 }
578 lilv_node_free(minLength);
579 }
580
581 auto maxLength = lilv_world_get(gWorld, lilv_plugin_get_uri(mPlug), node_MaxBlockLength, NULL);
582 if (maxLength)
583 {
584 if (lilv_node_is_int(maxLength))
585 {
586 int val = lilv_node_as_int(maxLength);
587 if (mMaxBlockSize > val)
588 {
589 mMaxBlockSize = val;
590 }
591 }
592 lilv_node_free(maxLength);
593 }
594
596 {
598 }
599
600 auto numPorts = lilv_plugin_get_num_ports(mPlug);
601
602 // Allocate buffers for the port indices and the default control values
603 Floats minimumVals {numPorts};
604 Floats maximumVals {numPorts};
605 Floats defaultVals {numPorts};
606
607 // Retrieve the port ranges for all ports (some values may be NaN)
608 lilv_plugin_get_port_ranges_float(mPlug,
609 minimumVals.get(),
610 maximumVals.get(),
611 defaultVals.get());
612
613 // Get info about all ports
614 for (size_t i = 0; i < numPorts; i++)
615 {
616 const LilvPort *port = lilv_plugin_get_port_by_index(mPlug, i);
617 int index = lilv_port_get_index(mPlug, port);
618
619 // It must be input or output, anything else is bogus
620 bool isInput;
621 if (lilv_port_is_a(mPlug, port, node_InputPort))
622 {
623 isInput = true;
624 }
625 else if (lilv_port_is_a(mPlug, port, node_OutputPort))
626 {
627 isInput = false;
628 }
629 else
630 {
631 assert(false);
632 return false;
633 }
634
635 // Get the port name and symbol
636 wxString symbol = LilvString(lilv_port_get_symbol(mPlug, port));
637 wxString name = LilvString(lilv_port_get_name(mPlug, port), true);
638
639 // Get the group to which this port belongs or default to the main group
640 TranslatableString groupName{};
641 if (auto group = lilv_port_get(mPlug, port, node_Group)) {
642 auto groupMsg = LilvString(lilv_world_get(
643 gWorld, group, node_Label, NULL), true);
644 if (groupMsg.empty())
645 groupMsg = LilvString(lilv_world_get(
646 gWorld, group, node_Name, NULL), true);
647 if (groupMsg.empty())
648 groupMsg = LilvString(group);
649 groupName = Verbatim(groupMsg);
650 lilv_node_free(group);
651 }
652 else
653 groupName = XO("Effect Settings");
654
655 // Get the latency port
656 uint32_t latencyIndex = lilv_plugin_get_latency_port_index(mPlug);
657
658 // Get the ports designation (must be freed)
659 LilvNode *designation = lilv_port_get(mPlug, port, node_Designation);
660
661 // Check for audio ports
662 if (lilv_port_is_a(mPlug, port, node_AudioPort))
663 {
664 mAudioPorts.push_back(std::make_shared<LV2AudioPort>(port, index, isInput, symbol, name, groupName));
665
666 isInput ? mAudioIn++ : mAudioOut++;
667 }
668 // Check for Control ports
669 else if (lilv_port_is_a(mPlug, port, node_ControlPort))
670 {
671 // Add group if not previously done
672 if (mGroupMap.find(groupName) == mGroupMap.end())
673 {
674 mGroups.push_back(groupName);
675 }
676 mGroupMap[groupName].push_back(mControlPorts.size());
677
678 mControlPorts.push_back(std::make_shared<LV2ControlPort>(port, index, isInput, symbol, name, groupName));
679 LV2ControlPortPtr controlPort = mControlPorts.back();
680
681 // Get any unit descriptor
682 LilvNode *unit = lilv_port_get(mPlug, port, node_Unit);
683 if (unit)
684 {
685 // Really should use lilv_world_get_symbol()
686 LilvNode *symbol = lilv_world_get_symbol(gWorld, unit);
687 if (symbol)
688 {
689 controlPort->mUnits = LilvString(symbol);
690 lilv_node_free(symbol);
691 }
692 lilv_node_free(unit);
693 }
694
695 // Get the scale points
696 LilvScalePoints *points = lilv_port_get_scale_points(mPlug, port);
697 LILV_FOREACH(scale_points, j, points)
698 {
699 const LilvScalePoint *point = lilv_scale_points_get(points, j);
700
701 controlPort->mScaleValues.push_back(lilv_node_as_float(lilv_scale_point_get_value(point)));
702 controlPort->mScaleLabels.push_back(LilvString(lilv_scale_point_get_label(point)));
703 }
704 lilv_scale_points_free(points);
705
706 // Collect the value and range info
707 controlPort->mHasLo = !std::isnan(minimumVals[i]);
708 controlPort->mHasHi = !std::isnan(maximumVals[i]);
709 controlPort->mMin = controlPort->mHasLo ? minimumVals[i] : 0.0;
710 controlPort->mMax = controlPort->mHasHi ? maximumVals[i] : 1.0;
711 controlPort->mLo = controlPort->mMin;
712 controlPort->mHi = controlPort->mMax;
713 controlPort->mDef = !std::isnan(defaultVals[i])
714 ? defaultVals[i]
715 : controlPort->mHasLo
716 ? controlPort->mLo
717 : controlPort->mHasHi
718 ? controlPort->mHi
719 : 0.0;
720 controlPort->mVal = controlPort->mDef;
721 controlPort->mLst = controlPort->mVal;
722
723 // Figure out the type of port we have
724 if (isInput)
725 {
726 if (lilv_port_has_property(mPlug, port, node_Toggled))
727 {
728 controlPort->mToggle = true;
729 }
730 else if (lilv_port_has_property(mPlug, port, node_Enumeration))
731 {
732 controlPort->mEnumeration = true;
733 }
734 else if (lilv_port_has_property(mPlug, port, node_Integer))
735 {
736 controlPort->mInteger = true;
737 }
738 else if (lilv_port_has_property(mPlug, port, node_SampleRate))
739 {
740 controlPort->mSampleRate = true;
741 }
742
743 // Trigger properties can be combined with other types, but it
744 // seems mostly to be combined with toggle. So, we turn the
745 // checkbox into a button.
746 if (lilv_port_has_property(mPlug, port, node_Trigger))
747 {
748 controlPort->mTrigger = true;
749 }
750
751 // We'll make the slider logarithmic
752 if (lilv_port_has_property(mPlug, port, node_Logarithmic))
753 {
754 controlPort->mLogarithmic = true;
755 }
756
757 if (lilv_port_has_property(mPlug, port, node_Enumeration))
758 {
759 controlPort->mEnumeration = true;
760 }
761
762 mControlPortMap[controlPort->mIndex] = controlPort;
763 }
764 else
765 {
766 if (controlPort->mIndex == latencyIndex)
767 {
768 mLatencyPort = i;
769 }
770 }
771 }
772 // Check for atom ports
773 else if (lilv_port_is_a(mPlug, port, node_AtomPort))
774 {
775 mAtomPorts.push_back(std::make_shared<LV2AtomPort>(port, index, isInput, symbol, name, groupName));
776 std::shared_ptr<LV2AtomPort> atomPort = mAtomPorts.back();
777
778 atomPort->mMinimumSize = 8192;
779 LilvNode *min = lilv_port_get(mPlug, port, node_MinimumSize);
780 if (min)
781 {
782 if (lilv_node_is_int(min))
783 {
784 uint32_t val = lilv_node_as_int(min);
785 if (atomPort->mMinimumSize < val)
786 {
787 atomPort->mMinimumSize = val;
788 }
789 }
790 lilv_node_free(min);
791 }
792
793 atomPort->mBuffer.resize(atomPort->mMinimumSize);
794 atomPort->mRing = zix_ring_new(atomPort->mMinimumSize);
795 zix_ring_mlock(atomPort->mRing);
796
797 if (lilv_port_supports_event(mPlug, port, node_Position))
798 {
799 atomPort->mWantsPosition = true;
800 }
801
802 if (lilv_port_supports_event(mPlug, port, node_MidiEvent))
803 {
804 atomPort->mIsMidi = true;
805 (isInput ? mMidiIn : mMidiOut) += 1;
806 }
807
808 bool isControl = lilv_node_equals(designation, node_Control);
809 if (isInput)
810 {
811 if (!mControlIn || isControl)
812 {
813 mControlIn = atomPort;
814 }
815 }
816 else
817 {
818 if (!mControlOut || isControl)
819 {
820 mControlOut = atomPort;
821 }
822 }
823 }
824 // Check for CV ports
825 else if (lilv_port_is_a(mPlug, port, node_CVPort))
826 {
827 mCVPorts.push_back(std::make_shared<LV2CVPort>(port, index, isInput, symbol, name, groupName));
828 std::shared_ptr<LV2CVPort> cvPort = mCVPorts.back();
829
830 // Collect the value and range info
831 if (!std::isnan(minimumVals[i]))
832 {
833 cvPort->mHasLo = true;
834 cvPort->mMin = minimumVals[i];
835 }
836
837 if (!std::isnan(maximumVals[i]))
838 {
839 cvPort->mHasHi = true;
840 cvPort->mMax = maximumVals[i];
841 }
842
843 if (!std::isnan(defaultVals[i]))
844 {
845 cvPort->mDef = defaultVals[i];
846 }
847 else if (cvPort->mHasLo)
848 {
849 cvPort->mDef = cvPort->mMin;
850 }
851 else if (cvPort->mHasHi)
852 {
853 cvPort->mDef = cvPort->mMax;
854 }
855 }
856
857 // Free the designation node
858 if (designation)
859 {
860 lilv_node_free(designation);
861 }
862 }
863
864 // Ignore control designation if one of them is missing
865 if ((mControlIn && !mControlOut) || (!mControlIn && mControlOut))
866 {
867 mControlIn.reset();
868 mControlOut.reset();
869 }
870
871 // Determine available extensions
873 mWantsWorkerInterface = false;
874 mWantsStateInterface = false;
875
876 LilvNodes *extdata = lilv_plugin_get_extension_data(mPlug);
877 if (extdata)
878 {
879 LILV_FOREACH(nodes, i, extdata)
880 {
881 const LilvNode *node = lilv_nodes_get(extdata, i);
882 const char *uri = lilv_node_as_string(node);
883
884 if (strcmp(uri, LV2_OPTIONS__interface) == 0)
885 {
887 }
888 else if (strcmp(uri, LV2_WORKER__interface) == 0)
889 {
891 }
892 else if (strcmp(uri, LV2_STATE__interface) == 0)
893 {
895 }
896 }
897 lilv_nodes_free(extdata);
898 }
899
900 return true;
901}
902
903std::shared_ptr<EffectInstance> LV2Effect::MakeInstance() const
904{
905 return const_cast<LV2Effect*>(this)->DoMakeInstance();
906}
907
908std::shared_ptr<EffectInstance> LV2Effect::DoMakeInstance()
909{
910 int userBlockSize;
911 GetConfig(*this, PluginSettings::Shared, wxT("Settings"),
912 wxT("BufferSize"), userBlockSize, 8192);
913 mUserBlockSize = std::max(1, userBlockSize);
914 GetConfig(*this, PluginSettings::Shared, wxT("Settings"),
915 wxT("UseLatency"), mUseLatency, true);
916 GetConfig(*this, PluginSettings::Shared, wxT("Settings"), wxT("UseGUI"),
917 mUseGUI, true);
918
920
921 lv2_atom_forge_init(&mForge, &mURIDMapFeature);
922
923 return std::make_shared<Instance>(*this);
924}
925
927{
928 return mAudioIn;
929}
930
932{
933 return mAudioOut;
934}
935
937{
938 return mMidiIn;
939}
940
942{
943 return mMidiOut;
944}
945
947{
948 mSampleRate = (float) rate;
949
950 if (mMaster)
951 {
953 }
954
955 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
956 {
957 mSlaves[i]->SetSampleRate();
958 }
959}
960
961size_t LV2Effect::SetBlockSize(size_t maxBlockSize)
962{
964
966 {
968 }
970 {
972 }
973
974 if (mMaster)
975 {
977 }
978
979 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; i++)
980 {
981 mSlaves[i]->SetBlockSize();
982 }
983
984 return mBlockSize;
985}
986
988{
989 return mBlockSize;
990}
991
993{
994 if (mUseLatency && mLatencyPort >= 0 && !mLatencyDone)
995 {
996 mLatencyDone = true;
997 return sampleCount(mMaster->GetLatency());
998 }
999
1000 return 0;
1001}
1002
1005{
1007 if (!mProcess)
1008 {
1009 return false;
1010 }
1011
1012 for (auto & port : mCVPorts)
1013 {
1014 port->mBuffer.reinit((unsigned) mBlockSize, port->mIsInput);
1015 }
1016
1017 lilv_instance_activate(mProcess->GetInstance());
1018 mActivated = true;
1019
1020 mLatencyDone = false;
1021
1022 return true;
1023}
1024
1026{
1027 if (mProcess)
1028 {
1030 mProcess = NULL;
1031 }
1032
1033 return true;
1034}
1035
1037 const float *const *inbuf, float *const *outbuf, size_t size)
1038{
1039 using namespace LV2Symbols;
1040 wxASSERT(size <= ( size_t) mBlockSize);
1041
1042 LilvInstance *instance = mProcess->GetInstance();
1043
1044 int i = 0;
1045 int o = 0;
1046 for (auto & port : mAudioPorts)
1047 {
1048 lilv_instance_connect_port(instance,
1049 port->mIndex,
1050 const_cast<float*>(port->mIsInput ? inbuf[i++] : outbuf[o++]));
1051 }
1052
1053 // Transfer incoming events from the ring buffer to the event buffer for each
1054 // atom input port. These will be made available to each slave in the chain and
1055 // to the master once all slaves have run.
1056 //
1057 // In addition, reset the output Atom ports.
1058 for (auto & port : mAtomPorts)
1059 {
1060 uint8_t *buf = port->mBuffer.data();
1061
1062 if (port->mIsInput)
1063 {
1064 lv2_atom_forge_set_buffer(&mForge,
1065 buf,
1066 port->mBuffer.size());
1067
1068 LV2_Atom_Forge_Frame seqFrame;
1069 LV2_Atom_Sequence *seq = ( LV2_Atom_Sequence *)
1070 lv2_atom_forge_sequence_head(&mForge, &seqFrame, 0);
1071
1072 if (port->mWantsPosition)
1073 {
1074 lv2_atom_forge_frame_time(&mForge, mPositionFrame);
1075
1076 LV2_Atom_Forge_Frame posFrame;
1077 lv2_atom_forge_object(&mForge, &posFrame, 0, urid_Position);
1078 lv2_atom_forge_key(&mForge, urid_Speed);
1079 lv2_atom_forge_float(&mForge, mPositionSpeed);
1080 lv2_atom_forge_key(&mForge, urid_Frame);
1081 lv2_atom_forge_long(&mForge, mPositionFrame);
1082 lv2_atom_forge_pop(&mForge, &posFrame);
1083 }
1084
1085 ZixRing *ring = port->mRing;
1086 LV2_Atom atom;
1087 while (zix_ring_read(ring, &atom, sizeof(atom)))
1088 {
1089 if (mForge.offset + sizeof(LV2_Atom_Event) + atom.size < mForge.size)
1090 {
1091 lv2_atom_forge_frame_time(&mForge, mPositionFrame);
1092
1093 lv2_atom_forge_write(&mForge, &atom, sizeof(atom));
1094 zix_ring_read(ring, &mForge.buf[mForge.offset], atom.size);
1095 mForge.offset += atom.size;
1096 seq->atom.size += atom.size;
1097 }
1098 else
1099 {
1100 zix_ring_skip(ring, atom.size);
1101 wxLogError(wxT("LV2 sequence buffer overflow"));
1102 }
1103 }
1104
1105 lv2_atom_forge_pop(&mForge, &seqFrame);
1106 }
1107 else
1108 {
1109 port->mBuffer.resize(port->mMinimumSize);
1110 *(( LV2_Atom *) buf) =
1111 {
1112 port->mMinimumSize,
1113 urid_Chunk
1114 };
1115 }
1116 }
1117
1118 lilv_instance_run(instance, size);
1119
1121
1122 for (auto & port : mAtomPorts)
1123 {
1124 if (!port->mIsInput)
1125 {
1126 port->mBuffer.resize(port->mMinimumSize);
1127
1128 LV2_Atom *chunk = ( LV2_Atom *) port->mBuffer.data();
1129 chunk->size = port->mMinimumSize;
1130 chunk->type = urid_Chunk;
1131 }
1132 }
1133
1134 return size;
1135}
1136
1138{
1139 mMasterIn.reinit(mAudioIn, (unsigned int) mBlockSize);
1140 for (auto & port : mCVPorts)
1141 {
1142 port->mBuffer.reinit((unsigned) mBlockSize, port->mIsInput);
1143 }
1144
1145 lilv_instance_activate(mMaster->GetInstance());
1146 mActivated = true;
1147
1148 return true;
1149}
1150
1152{
1153return GuardedCall<bool>([&]{
1154 for (auto & slave : mSlaves)
1155 {
1156 FreeInstance(slave);
1157 }
1158 mSlaves.clear();
1159
1160 if (mActivated)
1161 {
1162 lilv_instance_deactivate(mMaster->GetInstance());
1163 mActivated = false;
1164 }
1165
1166 for (auto & port : mCVPorts)
1167 {
1168 port->mBuffer.reset();
1169 }
1170
1171 mMasterIn.reset();
1172 return true;
1173});
1174}
1175
1177 EffectSettings &, unsigned, float sampleRate)
1178{
1179 LV2Wrapper *slave = InitInstance(sampleRate);
1180 if (!slave)
1181 {
1182 return false;
1183 }
1184
1185 mSlaves.push_back(slave);
1186
1187 lilv_instance_activate(slave->GetInstance());
1188 mActivated = true;
1189
1190 return true;
1191}
1192
1194{
1195 mPositionSpeed = 0.0;
1196 mPositionFrame = 0.0;
1197 mRolling = false;
1198
1199 return true;
1200}
1201
1203{
1204 mPositionSpeed = 1.0;
1205 mPositionFrame = 0.0;
1206 mRolling = true;
1207
1208 return true;
1209}
1210
1212{
1213 using namespace LV2Symbols;
1214 int i = 0;
1215 for (auto & port : mAudioPorts)
1216 {
1217 if (port->mIsInput)
1218 {
1219 memset(mMasterIn[i++].get(), 0, mBlockSize * sizeof(float));
1220 }
1221 }
1222
1223 mNumSamples = 0;
1224
1225 // Transfer incoming events from the ring buffer to the event buffer for each
1226 // atom input port. These will be made available to each slave in the chain and
1227 // to the master once all slaves have run.
1228 //
1229 // In addition, reset the output Atom ports.
1230 for (auto & port : mAtomPorts)
1231 {
1232 uint8_t *buf = port->mBuffer.data();
1233
1234 if (port->mIsInput)
1235 {
1236 lv2_atom_forge_set_buffer(&mForge,
1237 buf,
1238 port->mBuffer.size());
1239
1240 LV2_Atom_Forge_Frame seqFrame;
1241 LV2_Atom_Sequence *seq = (LV2_Atom_Sequence *)
1242 lv2_atom_forge_sequence_head(&mForge, &seqFrame, 0);
1243
1244 if (port->mWantsPosition)
1245 {
1246 lv2_atom_forge_frame_time(&mForge, mPositionFrame);
1247
1248 LV2_Atom_Forge_Frame posFrame;
1249 lv2_atom_forge_object(&mForge, &posFrame, 0, urid_Position);
1250 lv2_atom_forge_key(&mForge, urid_Speed);
1251 lv2_atom_forge_float(&mForge, mPositionSpeed);
1252 lv2_atom_forge_key(&mForge, urid_Frame);
1253 lv2_atom_forge_long(&mForge, mPositionFrame);
1254 lv2_atom_forge_pop(&mForge, &posFrame);
1255 }
1256
1257 ZixRing *ring = port->mRing;
1258 LV2_Atom atom;
1259 while (zix_ring_read(ring, &atom, sizeof(atom)))
1260 {
1261 if (mForge.offset + sizeof(LV2_Atom_Event) + atom.size < mForge.size)
1262 {
1263 lv2_atom_forge_frame_time(&mForge, mPositionFrame);
1264
1265 lv2_atom_forge_write(&mForge, &atom, sizeof(atom));
1266 zix_ring_read(ring, &mForge.buf[mForge.offset], atom.size);
1267 mForge.offset += atom.size;
1268 seq->atom.size += atom.size;
1269 }
1270 else
1271 {
1272 zix_ring_skip(ring, atom.size);
1273 wxLogError(wxT("LV2 sequence buffer overflow"));
1274 }
1275 }
1276 lv2_atom_forge_pop(&mForge, &seqFrame);
1277#if 0
1278 LV2_ATOM_SEQUENCE_FOREACH(seq, ev)
1279 {
1280 LV2_Atom_Object *o = (LV2_Atom_Object *) &ev->body;
1281 wxLogDebug(wxT("ev = %lld ev.size %d ev.type %d"), ev->time.frames, ev->body.size, ev->body.type);
1282 }
1283#endif
1284 }
1285 else
1286 {
1287 port->mBuffer.resize(port->mMinimumSize);
1288 *((LV2_Atom *) buf) =
1289 {
1290 port->mMinimumSize,
1291 urid_Chunk
1292 };
1293 }
1294 }
1295
1296 return true;
1297}
1298
1300 const float *const *inbuf, float *const *outbuf, size_t numSamples)
1301{
1302 wxASSERT(group >= 0 && group < (int) mSlaves.size());
1303 wxASSERT(numSamples <= (size_t) mBlockSize);
1304
1305 if (group < 0 || group >= (int) mSlaves.size())
1306 {
1307 return 0;
1308 }
1309
1310 LV2Wrapper *slave = mSlaves[group];
1311 LilvInstance *instance = slave->GetInstance();
1312
1313 int i = 0;
1314 int o = 0;
1315 for (auto & port : mAudioPorts)
1316 {
1317 if (port->mIsInput)
1318 {
1319 for (decltype(numSamples) s = 0; s < numSamples; s++)
1320 {
1321 mMasterIn[i][s] += inbuf[i][s];
1322 }
1323 }
1324
1325 lilv_instance_connect_port(instance,
1326 port->mIndex,
1327 const_cast<float*>(port->mIsInput ? inbuf[i++] : outbuf[o++]));
1328 }
1329
1330 mNumSamples = wxMax(numSamples, mNumSamples);
1331
1332 if (mRolling)
1333 {
1334 lilv_instance_run(instance, numSamples);
1335 }
1336 else
1337 {
1338 while (--i >= 0)
1339 {
1340 for (decltype(numSamples) s = 0; s < numSamples; s++)
1341 {
1342 outbuf[i][s] = inbuf[i][s];
1343 }
1344 }
1345 }
1346
1347 slave->SendResponses();
1348
1349 for (auto & port : mAtomPorts)
1350 {
1351 uint8_t *buf = port->mBuffer.data();
1352
1353 if (!port->mIsInput)
1354 {
1355 port->mBuffer.resize(port->mMinimumSize);
1356
1357 LV2_Atom *chunk = ( LV2_Atom *) buf;
1358 chunk->size = port->mMinimumSize;
1359 chunk->type = LV2Symbols::urid_Chunk;
1360 }
1361 }
1362
1363 if (group == 0)
1364 {
1365 mPositionFrame += numSamples;
1366 }
1367
1368 return numSamples;
1369}
1370
1372{
1373return GuardedCall<bool>([&]{
1374 // Nothing to do if we did process any samples
1375 if (mNumSamples == 0)
1376 {
1377 return true;
1378 }
1379
1380 for (auto & port : mAtomPorts)
1381 {
1382 if (!port->mIsInput)
1383 {
1384 ZixRing *ring = port->mRing;
1385
1386 LV2_ATOM_SEQUENCE_FOREACH((LV2_Atom_Sequence *) port->mBuffer.data(), ev)
1387 {
1388 zix_ring_write(ring, &ev->body, ev->body.size + sizeof(LV2_Atom));
1389 }
1390 }
1391 }
1392
1393 mNumSamples = 0;
1394
1395 return true;
1396});
1397}
1398
1400 wxWindow &parent, wxDialog &dialog, bool forceModal)
1401{
1402 // Remember the dialog with a weak pointer, but don't control its lifetime
1403 mDialog = &dialog;
1404
1405 // Try to give the window a sensible default/minimum size
1406 mDialog->Layout();
1407 mDialog->Fit();
1408 mDialog->SetMinSize(mDialog->GetSize());
1409 if (mNoResize)
1410 {
1411 mDialog->SetMaxSize(mDialog->GetSize());
1412 }
1413
1414 if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal)
1415 {
1416 mDialog->Show();
1417 return 0;
1418 }
1419
1420 return mDialog->ShowModal();
1421}
1422
1424 const EffectSettings &, CommandParameters & parms) const
1425{
1426 for (auto & port : mControlPorts)
1427 {
1428 if (port->mIsInput)
1429 {
1430 if (!parms.Write(port->mName, port->mVal))
1431 {
1432 return false;
1433 }
1434 }
1435 }
1436
1437 return true;
1438}
1439
1441 const CommandParameters & parms, EffectSettings &settings) const
1442{
1443 // First pass validates values
1444 for (auto & port : mControlPorts)
1445 {
1446 if (port->mIsInput)
1447 {
1448 double d = 0.0;
1449 if (!parms.Read(port->mName, &d))
1450 {
1451 return false;
1452 }
1453
1454 // Use unscaled range here
1455 if (d < port->mMin || d > port->mMax)
1456 {
1457 return false;
1458 }
1459 }
1460 }
1461
1462 // Second pass actually sets the values
1463 for (auto & port : mControlPorts)
1464 {
1465 if (port->mIsInput)
1466 {
1467 double d = 0.0;
1468 if (!parms.Read(port->mName, &d))
1469 {
1470 return false;
1471 }
1472
1473 port->mVal = d;
1474 port->mTmp = port->mVal * (port->mSampleRate ? mSampleRate : 1.0);
1475 }
1476 }
1477
1478 return true;
1479}
1480
1481// ============================================================================
1482// EffectUIClientInterface Implementation
1483// ============================================================================
1484
1485std::unique_ptr<EffectUIValidator> LV2Effect::PopulateUI(ShuttleGui &S,
1487{
1488 auto parent = S.GetParent();
1489 mParent = parent;
1490
1491 mParent->PushEventHandler(this);
1492
1493 mSuilHost = NULL;
1494 mSuilInstance = NULL;
1495
1497 if (mMaster == NULL)
1498 {
1499 AudacityMessageBox( XO("Couldn't instantiate effect") );
1500 return nullptr;
1501 }
1502
1503 // Determine if the GUI editor is supposed to be used or not
1504 GetConfig(*this, PluginSettings::Shared, wxT("Settings"),
1505 wxT("UseGUI"),
1506 mUseGUI,
1507 true);
1508
1509 // Until I figure out where to put the "Duration" control in the
1510 // graphical editor, force usage of plain editor.
1511 if (GetType() == EffectTypeGenerate)
1512 {
1513 mUseGUI = false;
1514 }
1515
1516 if (mUseGUI)
1517 {
1518 mUseGUI = BuildFancy();
1519 }
1520
1521 if (!mUseGUI)
1522 {
1523 if (!BuildPlain(access))
1524 return nullptr;
1525 }
1526
1527 return std::make_unique<DefaultEffectUIValidator>(*this, access);
1528}
1529
1531{
1532 return mUseGUI;
1533}
1534
1536{
1537 if (GetType() == EffectTypeGenerate)
1538 settings.extra.SetDuration(mDuration->GetValue());
1539
1540 return true;
1541}
1542
1544{
1545#ifdef __WXMAC__
1546#ifdef __WX_EVTLOOP_BUSY_WAITING__
1547 wxEventLoop::SetBusyWaiting(false);
1548#endif
1549#endif
1550
1551 mParent->RemoveEventHandler(this);
1552
1553 if (mSuilInstance)
1554 {
1555 if (mNativeWin)
1556 {
1557 mNativeWin->Destroy();
1558 mNativeWin = NULL;
1559 }
1560
1561 mUIIdleInterface = NULL;
1562 mUIShowInterface = NULL;
1563 mExternalWidget = NULL;
1564
1565 suil_instance_free(mSuilInstance);
1566 mSuilInstance = NULL;
1567 }
1568
1569 if (mSuilHost)
1570 {
1571 suil_host_free(mSuilHost);
1572 mSuilHost = NULL;
1573 }
1574
1575 if (mMaster)
1576 {
1578 mMaster = NULL;
1579 }
1580
1581 mParent = NULL;
1582 mDialog = NULL;
1583
1584 return true;
1585}
1586
1589{
1590 // To do: externalize state so const_cast isn't needed
1591 return const_cast<LV2Effect*>(this)->DoLoadUserPreset(name, settings);
1592}
1593
1596{
1598 {
1599 return false;
1600 }
1601
1602 return TransferDataToWindow();
1603}
1604
1606 const RegistryPath &name, const EffectSettings &settings) const
1607{
1608 return SaveParameters(name, settings);
1609}
1610
1612{
1613 using namespace LV2Symbols;
1615 {
1616 return mFactoryPresetNames;
1617 }
1618
1619 LilvNodes *presets = lilv_plugin_get_related(mPlug, node_Preset);
1620 if (presets)
1621 {
1622 LILV_FOREACH(nodes, i, presets)
1623 {
1624 const LilvNode *preset = lilv_nodes_get(presets, i);
1625
1627
1628 lilv_world_load_resource(gWorld, preset);
1629
1630 LilvNodes *labels = lilv_world_find_nodes(gWorld, preset, node_Label, NULL);
1631 if (labels)
1632 {
1633 const LilvNode *label = lilv_nodes_get_first(labels);
1634
1636
1637 lilv_nodes_free(labels);
1638 }
1639 else
1640 {
1641 mFactoryPresetNames.push_back(LilvString(preset).AfterLast(wxT('#')));
1642 }
1643 }
1644
1645 lilv_nodes_free(presets);
1646 }
1647
1648 mFactoryPresetsLoaded = true;
1649
1650 return mFactoryPresetNames;
1651}
1652
1654{
1655 // To do: externalize state so const_cast isn't needed
1656 return const_cast<LV2Effect*>(this)->DoLoadFactoryPreset(id);
1657}
1658
1660{
1661 using namespace LV2Symbols;
1662 if (id < 0 || id >= (int) mFactoryPresetUris.size())
1663 {
1664 return false;
1665 }
1666
1667 LilvNode *preset = lilv_new_uri(gWorld, mFactoryPresetUris[id].ToUTF8());
1668 if (!preset)
1669 {
1670 return false;
1671 }
1672
1673 LilvState *state = lilv_state_new_from_world(gWorld, &mURIDMapFeature, preset);
1674 if (state)
1675 {
1676 lilv_state_restore(state, mMaster->GetInstance(), set_value_func, this, 0, NULL);
1677
1678 lilv_state_free(state);
1679
1681 }
1682
1683 lilv_node_free(preset);
1684
1685 return state != NULL;
1686}
1687
1689{
1690 return false;
1691}
1692
1694{
1695}
1696
1698{
1699}
1700
1702{
1703 return true;
1704}
1705
1707{
1708 LV2EffectSettingsDialog dlg(mParent, *this);
1709 if (dlg.ShowModal() == wxID_OK)
1710 {
1711 // Reinitialize configuration settings
1712 int userBlockSize;
1713 GetConfig(*this, PluginSettings::Shared, wxT("Settings"),
1714 wxT("BufferSize"), userBlockSize, DEFAULT_BLOCKSIZE);
1715 mUserBlockSize = std::max(1, userBlockSize);
1716 GetConfig(*this, PluginSettings::Shared, wxT("Settings"),
1717 wxT("UseLatency"), mUseLatency, true);
1718 }
1719}
1720
1721// ============================================================================
1722// LV2Effect Implementation
1723// ============================================================================
1724
1726 const RegistryPath &group, EffectSettings &settings)
1727{
1728 wxString parms;
1729 if (!GetConfig(*this,
1730 PluginSettings::Private, group, wxT("Parameters"), parms, wxEmptyString))
1731 {
1732 return false;
1733 }
1734
1736 if (!eap.SetParameters(parms))
1737 {
1738 return false;
1739 }
1740
1741 return LoadSettings(eap, settings);
1742}
1743
1745 const RegistryPath &group, const EffectSettings &settings) const
1746{
1748 if (!SaveSettings(settings, eap))
1749 return false;
1750
1751 wxString parms;
1752 if (!eap.GetParameters(parms))
1753 return false;
1754
1755 return SetConfig(*this,
1756 PluginSettings::Private, group, wxT("Parameters"), parms);
1757}
1758
1759size_t LV2Effect::AddOption(LV2_URID key, uint32_t size, LV2_URID type, const void *value)
1760{
1761 int ndx = mOptions.size();
1762 mOptions.resize(1 + ndx);
1763
1764 memset(&mOptions[ndx], 0, sizeof(mOptions[ndx]));
1765
1766 if (key != 0)
1767 {
1768 mOptions[ndx].context = LV2_OPTIONS_INSTANCE;
1769 mOptions[ndx].subject = 0;
1770 mOptions[ndx].key = key;
1771 mOptions[ndx].size = size;
1772 mOptions[ndx].type = type;
1773 mOptions[ndx].value = value;
1774 }
1775
1776 return ndx;
1777}
1778
1779LV2_Feature *LV2Effect::AddFeature(const char *uri, void *data)
1780{
1781 size_t ndx = mFeatures.size();
1782 mFeatures.resize(1 + ndx);
1783
1784 if (uri)
1785 {
1786 mFeatures[ndx].reset(safenew LV2_Feature);
1787 mFeatures[ndx]->URI = uri;
1788 mFeatures[ndx]->data = data;
1789 }
1790
1791 return mFeatures[ndx].get();
1792}
1793
1794bool LV2Effect::ValidateFeatures(const LilvNode *subject)
1795{
1796 if (CheckFeatures(subject, LV2Symbols::node_RequiredFeature, true))
1797 {
1798 return CheckFeatures(subject, LV2Symbols::node_OptionalFeature, false);
1799 }
1800
1801 return false;
1802}
1803
1804bool LV2Effect::CheckFeatures(const LilvNode *subject, const LilvNode *predicate, bool required)
1805{
1806 bool supported = true;
1807
1808 LilvNodes *nodes =
1809 lilv_world_find_nodes(LV2Symbols::gWorld, subject, predicate, nullptr);
1810 if (nodes)
1811 {
1812 LILV_FOREACH(nodes, i, nodes)
1813 {
1814 const LilvNode *node = lilv_nodes_get(nodes, i);
1815 const char *uri = lilv_node_as_string(node);
1816
1817 if ((strcmp(uri, LV2_UI__noUserResize) == 0) ||
1818 (strcmp(uri, LV2_UI__fixedSize) == 0))
1819 {
1820 mNoResize = true;
1821 }
1822 else if (strcmp(uri, LV2_WORKER__schedule) == 0)
1823 {
1824 /* Supported but handled in LV2Wrapper */
1825 }
1826 else
1827 {
1828 supported = false;
1829
1830 for (auto & feature : mFeatures)
1831 {
1832 if (feature && strcmp(feature->URI, uri) == 0)
1833 {
1834 supported = true;
1835 break;
1836 }
1837 }
1838
1839 if (!supported)
1840 {
1841 if (required)
1842 {
1843 wxLogError(wxT("%s requires unsupported feature %s"), lilv_node_as_string(lilv_plugin_get_uri(mPlug)), uri);
1844 break;
1845 }
1846 supported = true;
1847 }
1848 }
1849 }
1850
1851 lilv_nodes_free(nodes);
1852 }
1853
1854
1855 return supported;
1856}
1857
1858bool LV2Effect::ValidateOptions(const LilvNode *subject)
1859{
1860 if (CheckOptions(subject, LV2Symbols::node_RequiredOption, true))
1861 {
1862 return CheckOptions(subject, LV2Symbols::node_SupportedOption, false);
1863 }
1864
1865 return false;
1866}
1867
1868bool LV2Effect::CheckOptions(const LilvNode *subject, const LilvNode *predicate, bool required)
1869{
1870 using namespace LV2Symbols;
1871 bool supported = true;
1872
1873 LilvNodes *nodes = lilv_world_find_nodes(gWorld, subject, predicate, NULL);
1874 if (nodes)
1875 {
1876 LILV_FOREACH(nodes, i, nodes)
1877 {
1878 const LilvNode *node = lilv_nodes_get(nodes, i);
1879 const char *uri = lilv_node_as_string(node);
1880 LV2_URID urid = URID_Map(uri);
1881
1882 if (urid == urid_NominalBlockLength)
1883 {
1885 }
1886 else if (urid == urid_SampleRate)
1887 {
1888 mSupportsSampleRate = true;
1889 }
1890 else
1891 {
1892 supported = false;
1893
1894 for (auto & option : mOptions)
1895 {
1896 if (option.key == urid)
1897 {
1898 supported = true;
1899 break;
1900 }
1901 }
1902
1903 if (!supported)
1904 {
1905 if (required)
1906 {
1907 wxLogError(wxT("%s requires unsupported option %s"), lilv_node_as_string(lilv_plugin_get_uri(mPlug)), uri);
1908 break;
1909 }
1910 supported = true;
1911 }
1912 }
1913 }
1914
1915 lilv_nodes_free(nodes);
1916 }
1917
1918 return supported;
1919}
1920
1922{
1923 LV2Wrapper *wrapper = new LV2Wrapper(this);
1924 if (wrapper == NULL)
1925 {
1926 return NULL;
1927 }
1928
1929 LilvInstance *instance = wrapper->Instantiate(mPlug, sampleRate, mFeatures);
1930 if (!instance)
1931 {
1932 delete wrapper;
1933 return NULL;
1934 }
1935
1936 wrapper->SetBlockSize();
1937 wrapper->SetSampleRate();
1938
1939 // Connect all control ports
1940 for (auto & port : mControlPorts)
1941 {
1942 // If it's not an input port and master has already been created
1943 // then connect the port to a dummy field since slave output port
1944 // values are unwanted as the master values will be used.
1945 //
1946 // Otherwise, connect it to the real value field.
1947 lilv_instance_connect_port(instance,
1948 port->mIndex,
1949 !port->mIsInput && mMaster
1950 ? &port->mDmy
1951 : &port->mVal);
1952 }
1953
1954 // Connect all atom ports
1955 for (auto & port : mAtomPorts)
1956 {
1957 lilv_instance_connect_port(instance, port->mIndex, port->mBuffer.data());
1958 }
1959
1960 // We don't fully support CV ports, so connect them to dummy buffers for now.
1961 for (auto & port : mCVPorts)
1962 {
1963 lilv_instance_connect_port(instance, port->mIndex, port->mBuffer.get());
1964 }
1965
1966 // Give plugin a chance to initialize. The SWH plugins (like AllPass) need
1967 // this before it can be safely deleted.
1968 lilv_instance_activate(instance);
1969 lilv_instance_deactivate(instance);
1970
1971 for (auto & port : mAtomPorts)
1972 {
1973 if (!port->mIsInput)
1974 {
1975 ZixRing *ring = port->mRing;
1976
1977 LV2_ATOM_SEQUENCE_FOREACH(( LV2_Atom_Sequence *) port->mBuffer.data(), ev)
1978 {
1979 zix_ring_write(ring, &ev->body, ev->body.size + sizeof(LV2_Atom));
1980 }
1981 }
1982 }
1983
1984 return wrapper;
1985}
1986
1988{
1989 delete wrapper;
1990}
1991
1993{
1994 using namespace LV2Symbols;
1995 // Set the native UI type
1996 const char *nativeType =
1997#if defined(__WXGTK3__)
1998 LV2_UI__Gtk3UI;
1999#elif defined(__WXGTK__)
2000 LV2_UI__GtkUI;
2001#elif defined(__WXMSW__)
2002 LV2_UI__WindowsUI;
2003#elif defined(__WXMAC__)
2004 LV2_UI__CocoaUI;
2005#endif
2006
2007 // Determine if the plugin has a supported UI
2008 const LilvUI *ui = NULL;
2009 const LilvNode *uiType = NULL;
2010 LilvUIs *uis = lilv_plugin_get_uis(mPlug);
2011 if (uis)
2012 {
2013 LilvNode *containerType = lilv_new_uri(gWorld, nativeType);
2014 if (containerType)
2015 {
2016 LILV_FOREACH(uis, iter, uis)
2017 {
2018 ui = lilv_uis_get(uis, iter);
2019 if (lilv_ui_is_supported(ui, suil_ui_supported, containerType, &uiType))
2020 {
2021 break;
2022 }
2023 if (lilv_ui_is_a(ui, node_Gtk) || lilv_ui_is_a(ui, node_Gtk3))
2024 {
2025 uiType = node_Gtk;
2026 break;
2027 }
2028
2029 ui = NULL;
2030 }
2031
2032 lilv_node_free(containerType);
2033 }
2034 }
2035
2036 // Check for other supported UIs
2037 if (ui == NULL)
2038 {
2039 LILV_FOREACH(uis, iter, uis)
2040 {
2041 ui = lilv_uis_get(uis, iter);
2042 if (lilv_ui_is_a(ui, node_ExternalUI) || lilv_ui_is_a(ui, node_ExternalUIOld))
2043 {
2044 uiType = node_ExternalUI;
2045 break;
2046 }
2047 ui = NULL;
2048 }
2049 }
2050
2051 // No usable UI found
2052 if (ui == NULL)
2053 {
2054 lilv_uis_free(uis);
2055 return false;
2056 }
2057
2058 const LilvNode *uinode = lilv_ui_get_uri(ui);
2059 lilv_world_load_resource(gWorld, uinode);
2060 if (!ValidateFeatures(uinode))
2061 {
2062 lilv_uis_free(uis);
2063 return false;
2064 }
2065
2066 const char *containerType;
2067
2068 if (uiType == node_ExternalUI)
2069 {
2070 containerType = LV2_EXTERNAL_UI__Widget;
2071 }
2072 else
2073 {
2074 containerType = nativeType;
2075 mParentFeature->data = mParent->GetHandle();
2076
2077#if defined(__WXGTK__)
2078 // Make sure the parent has a window
2079 if (!gtk_widget_get_window(GTK_WIDGET(mParent->m_wxwindow)))
2080 {
2081 gtk_widget_realize(GTK_WIDGET(mParent->m_wxwindow));
2082 }
2083#endif
2084 }
2085
2086 LilvInstance *instance = mMaster->GetInstance();
2087 mInstanceAccessFeature->data = lilv_instance_get_handle(instance);
2088 mExtensionDataFeature.data_access = lilv_instance_get_descriptor(instance)->extension_data;
2089
2090 // Set before creating the UI instance so the initial size (if any) can be captured
2091 mNativeWinInitialSize = wxDefaultSize;
2092 mNativeWinLastSize = wxDefaultSize;
2093
2094 // Create the suil host
2097 NULL,
2098 NULL);
2099 if (!mSuilHost)
2100 {
2101 lilv_uis_free(uis);
2102 return false;
2103 }
2104
2105#if defined(__WXMSW__)
2106 // Plugins may have dependencies that need to be loaded from the same path
2107 // as the main DLL, so add this plugin's path to the DLL search order.
2108 char *libPath = lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_binary_uri(ui)), NULL);
2109 wxString path = wxPathOnly(libPath);
2110 SetDllDirectory(path.c_str());
2111 lilv_free(libPath);
2112#endif
2113
2114 char *bundlePath = lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)), NULL);
2115 char *binaryPath = lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_binary_uri(ui)), NULL);
2116
2117 mSuilInstance = suil_instance_new(mSuilHost,
2118 this,
2119 containerType,
2120 lilv_node_as_uri(lilv_plugin_get_uri(mPlug)),
2121 lilv_node_as_uri(lilv_ui_get_uri(ui)),
2122 lilv_node_as_uri(uiType),
2123 bundlePath,
2124 binaryPath,
2125 reinterpret_cast<const LV2_Feature * const *>(mFeatures.data()));
2126
2127 lilv_free(binaryPath);
2128 lilv_free(bundlePath);
2129 lilv_uis_free(uis);
2130
2131 // Bail if the instance (no compatible UI) couldn't be created
2132 if (!mSuilInstance)
2133 {
2134#if defined(__WXMSW__)
2135 SetDllDirectory(NULL);
2136#endif
2137
2138 suil_host_free(mSuilHost);
2139 mSuilHost = NULL;
2140
2141 return false;
2142 }
2143
2144 if (uiType == node_ExternalUI)
2145 {
2146 mParent->SetMinSize(wxDefaultSize);
2147
2148 mExternalWidget = (LV2_External_UI_Widget *) suil_instance_get_widget(mSuilInstance);
2149 mTimer.SetOwner(this, ID_TIMER);
2150 mTimer.Start(20);
2151
2153 }
2154 else
2155 {
2156 WXWidget widget = (WXWidget) suil_instance_get_widget(mSuilInstance);
2157
2158#if defined(__WXGTK__)
2159 // Needed by some plugins (e.g., Invada) to ensure the display is fully
2160 // populated.
2161 gtk_widget_show_all(widget);
2162
2163 // See note at size_request()
2164 g_signal_connect(widget, "size-request", G_CALLBACK(LV2Effect::size_request), this);
2165#endif
2166
2168 if ( !uNativeWin->Create(mParent, widget) )
2169 return false;
2170 mNativeWin = uNativeWin.release();
2171
2172 mNativeWin->Bind(wxEVT_SIZE, &LV2Effect::OnSize, this);
2173
2174 // The plugin called the LV2UI_Resize::ui_resize function to set the size before
2175 // the native window was created, so set the size now.
2176 if (mNativeWinInitialSize != wxDefaultSize)
2177 {
2178 mNativeWin->SetMinSize(mNativeWinInitialSize);
2179 }
2180
2181 wxSizerItem *si = NULL;
2182 auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
2183 if (vs)
2184 {
2185 auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
2186 if (hs)
2187 {
2188 if (mNoResize)
2189 {
2190 si = hs->Add(mNativeWin, 0, wxCENTER);
2191 vs->Add(hs.release(), 1, wxCENTER);
2192 }
2193 else
2194 {
2195 si = hs->Add(mNativeWin, 1, wxEXPAND);
2196 vs->Add(hs.release(), 1, wxEXPAND);
2197 }
2198 }
2199 }
2200
2201 if (!si)
2202 {
2203 lilv_uis_free(uis);
2204 return false;
2205 }
2206
2207 mParent->SetSizerAndFit(vs.release());
2208 }
2209
2210 mUIIdleInterface = (LV2UI_Idle_Interface *)
2211 suil_instance_extension_data(mSuilInstance, LV2_UI__idleInterface);
2212
2213 mUIShowInterface = (LV2UI_Show_Interface *)
2214 suil_instance_extension_data(mSuilInstance, LV2_UI__showInterface);
2215
2216 if (mUIShowInterface)
2217 {
2218// mUIShowInterface->show(suil_instance_get_handle(mSuilInstance));
2219 }
2220
2222
2223#ifdef __WXMAC__
2224#ifdef __WX_EVTLOOP_BUSY_WAITING__
2225 wxEventLoop::SetBusyWaiting(true);
2226#endif
2227#endif
2228
2229#if defined(__WXMSW__)
2230 SetDllDirectory(NULL);
2231#endif
2232
2233 return true;
2234}
2235
2237{
2238 int numCols = 5;
2239 wxSizer *innerSizer;
2240
2241 wxASSERT(mParent); // To justify safenew
2242 wxScrolledWindow *const w = safenew
2243 wxScrolledWindow(mParent,
2244 wxID_ANY,
2245 wxDefaultPosition,
2246 wxDefaultSize,
2247 wxVSCROLL | wxTAB_TRAVERSAL);
2248
2249 {
2250 auto outerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
2251 w->SetScrollRate(0, 20);
2252
2253 // This fools NVDA into not saying "Panel" when the dialog gets focus
2254 w->SetName(wxT("\a"));
2255 w->SetLabel(wxT("\a"));
2256
2257 outerSizer->Add(w, 1, wxEXPAND);
2258
2259 {
2260 auto uInnerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
2261 innerSizer = uInnerSizer.get();
2262
2263 if (GetType() == EffectTypeGenerate)
2264 {
2265 // Add the length control
2266 auto groupSizer = std::make_unique<wxStaticBoxSizer>(wxVERTICAL, w, _("Generator"));
2267
2268 auto sizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
2269
2270 wxWindow *item = safenew wxStaticText(w, 0, _("&Duration:"));
2271 sizer->Add(item, 0, wxALIGN_CENTER | wxALL, 5);
2272 auto &extra = access.Get().extra;
2276 extra.GetDurationFormat(),
2277 extra.GetDuration(),
2280 .AutoPos(true));
2281 mDuration->SetName( XO("Duration") );
2282 sizer->Add(mDuration, 0, wxALIGN_CENTER | wxALL, 5);
2283
2284 groupSizer->Add(sizer.release(), 0, wxALIGN_CENTER | wxALL, 5);
2285 innerSizer->Add(groupSizer.release(), 0, wxEXPAND | wxALL, 5);
2286 }
2287
2288 std::sort(mGroups.begin(), mGroups.end(),
2289 [](const TranslatableString &a, const TranslatableString &b){
2290 return a.Translation() < b.Translation(); });
2291
2292 for (size_t i = 0, groupCount = mGroups.size(); i < groupCount; i++)
2293 {
2294 const auto &label = mGroups[i];
2295 auto groupSizer = std::make_unique<wxStaticBoxSizer>(
2296 wxVERTICAL, w, label.Translation());
2297
2298 auto gridSizer = std::make_unique<wxFlexGridSizer>(numCols, 5, 5);
2299 gridSizer->AddGrowableCol(3);
2300
2301 for (auto & p : mGroupMap[mGroups[i]])
2302 {
2303 auto & port = mControlPorts[p];
2304
2305 if (port->mNotOnGui)
2306 {
2307 continue;
2308 }
2309
2310 wxString labelText = port->mName;
2311 if (!port->mUnits.empty())
2312 {
2313 labelText += wxT(" (") + port->mUnits + wxT(")");
2314 }
2315
2316 if (port->mTrigger)
2317 {
2318 gridSizer->Add(1, 1, 0);
2319
2320 wxASSERT(w); // To justify safenew
2321 wxButton *b = safenew wxButton(w, ID_Triggers + p, labelText);
2322 gridSizer->Add(b, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
2323 port->mCtrl.button = b;
2324
2325 gridSizer->Add(1, 1, 0);
2326 gridSizer->Add(1, 1, 0);
2327 gridSizer->Add(1, 1, 0);
2328 continue;
2329 }
2330
2331 wxWindow *item = safenew wxStaticText(w, wxID_ANY, labelText + wxT(":"),
2332 wxDefaultPosition, wxDefaultSize,
2333 wxALIGN_RIGHT);
2334 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
2335
2336 if (port->mToggle)
2337 {
2338 wxCheckBox *c = safenew wxCheckBox(w, ID_Toggles + p, wxT(""));
2339 c->SetName(labelText);
2340 c->SetValue(port->mVal > 0);
2341 gridSizer->Add(c, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
2342 port->mCtrl.checkbox = c;
2343
2344 gridSizer->Add(1, 1, 0);
2345 gridSizer->Add(1, 1, 0);
2346 gridSizer->Add(1, 1, 0);
2347 }
2348 else if (port->mEnumeration) // Check before integer
2349 {
2350 int s;
2351 for (s = (int) port->mScaleValues.size() - 1; s >= 0; s--)
2352 {
2353 if (port->mVal >= port->mScaleValues[s])
2354 {
2355 break;
2356 }
2357 }
2358
2359 if (s < 0)
2360 {
2361 s = 0;
2362 }
2363
2364 wxChoice *c = safenew wxChoice(w, ID_Choices + p);
2365 c->SetName(labelText);
2366 c->Append(port->mScaleLabels);
2367 c->SetSelection(s);
2368 gridSizer->Add(c, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
2369 port->mCtrl.choice = c;
2370
2371 gridSizer->Add(1, 1, 0);
2372 gridSizer->Add(1, 1, 0);
2373 gridSizer->Add(1, 1, 0);
2374 }
2375 else if (!port->mIsInput)
2376 {
2377 gridSizer->Add(1, 1, 0);
2378 gridSizer->Add(1, 1, 0);
2379
2381 gridSizer->Add(m, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
2382 port->mCtrl.meter = m;
2383
2384 gridSizer->Add(1, 1, 0);
2385 }
2386 else
2387 {
2388 wxTextCtrl *t = safenew wxTextCtrl(w, ID_Texts + p, wxT(""));
2389 t->SetName(labelText);
2390 gridSizer->Add(t, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
2391 port->mText = t;
2392
2393 float rate = port->mSampleRate ? mSampleRate : 1.0;
2394
2395 port->mLo = port->mMin * rate;
2396 port->mHi = port->mMax * rate;
2397 port->mTmp = port->mVal * rate;
2398
2399 if (port->mInteger)
2400 {
2401 IntegerValidator<float> vld(&port->mTmp);
2402 vld.SetRange(port->mLo, port->mHi);
2403 t->SetValidator(vld);
2404 }
2405 else
2406 {
2407 FloatingPointValidator<float> vld(6, &port->mTmp);
2408 vld.SetRange(port->mLo, port->mHi);
2409
2410 // Set number of decimal places
2411 float range = port->mHi - port->mLo;
2412 auto style = range < 10
2413 ? NumValidatorStyle::THREE_TRAILING_ZEROES
2414 : range < 100
2415 ? NumValidatorStyle::TWO_TRAILING_ZEROES
2416 : NumValidatorStyle::ONE_TRAILING_ZERO;
2417 vld.SetStyle(style);
2418
2419 t->SetValidator(vld);
2420 }
2421
2422 if (port->mHasLo)
2423 {
2424 wxString str;
2425 if (port->mInteger || port->mSampleRate)
2426 {
2427 str.Printf(wxT("%d"), (int) lrintf(port->mLo));
2428 }
2429 else
2430 {
2431 str = Internat::ToDisplayString(port->mLo);
2432 }
2433 item = safenew wxStaticText(w, wxID_ANY, str);
2434 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
2435 }
2436 else
2437 {
2438 gridSizer->Add(1, 1, 0);
2439 }
2440
2441 wxSlider *s = safenew wxSliderWrapper(w, ID_Sliders + p,
2442 0, 0, 1000,
2443 wxDefaultPosition,
2444 wxSize(150, -1));
2445 s->SetName(labelText);
2446 gridSizer->Add(s, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
2447 port->mCtrl.slider = s;
2448
2449 if (port->mHasHi)
2450 {
2451 wxString str;
2452 if (port->mInteger || port->mSampleRate)
2453 {
2454 str.Printf(wxT("%d"), (int) lrintf(port->mHi));
2455 }
2456 else
2457 {
2458 str = Internat::ToDisplayString(port->mHi);
2459 }
2460 item = safenew wxStaticText(w, wxID_ANY, str);
2461 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
2462 }
2463 else
2464 {
2465 gridSizer->Add(1, 1, 0);
2466 }
2467 }
2468 }
2469
2470 groupSizer->Add(gridSizer.release(), 1, wxEXPAND | wxALL, 5);
2471 innerSizer->Add(groupSizer.release(), 0, wxEXPAND | wxALL, 5);
2472 }
2473
2474 innerSizer->Layout();
2475
2476 // Calculate the maximum width of all columns (bypass Generator sizer)
2477 std::vector<int> widths(numCols);
2478
2479 size_t cnt = innerSizer->GetChildren().GetCount();
2480 for (size_t i = (GetType() == EffectTypeGenerate); i < cnt; i++)
2481 {
2482 wxSizer *groupSizer = innerSizer->GetItem(i)->GetSizer();
2483 wxFlexGridSizer *gridSizer = (wxFlexGridSizer *) groupSizer->GetItem((size_t) 0)->GetSizer();
2484
2485 size_t items = gridSizer->GetChildren().GetCount();
2486 int cols = gridSizer->GetCols();
2487
2488 for (size_t j = 0; j < items; j++)
2489 {
2490 wxSizerItem *item = gridSizer->GetItem(j);
2491 widths[j % cols] = wxMax(widths[j % cols], item->GetSize().GetWidth());
2492 }
2493 }
2494
2495 // Set each column in all of the groups to the same width.
2496 for (size_t i = (GetType() == EffectTypeGenerate); i < cnt; i++)
2497 {
2498 wxSizer *groupSizer = innerSizer->GetItem(i)->GetSizer();
2499 wxFlexGridSizer *gridSizer = (wxFlexGridSizer *) groupSizer->GetItem((size_t) 0)->GetSizer();
2500
2501 size_t items = gridSizer->GetChildren().GetCount();
2502 int cols = gridSizer->GetCols();
2503
2504 for (size_t j = 0; j < items; j++)
2505 {
2506 wxSizerItem *item = gridSizer->GetItem(j);
2507
2508 int flags = item->GetFlag();
2509 if (flags & wxEXPAND)
2510 {
2511 continue;
2512 }
2513
2514 if (flags & wxALIGN_RIGHT)
2515 {
2516 flags = (flags & ~wxALL) | wxLEFT;
2517 }
2518 else
2519 {
2520 flags = (flags & ~wxALL) | wxRIGHT;
2521 }
2522 item->SetFlag(flags);
2523
2524 item->SetBorder(widths[j % cols] - item->GetMinSize().GetWidth());
2525 }
2526 }
2527
2528 w->SetSizer(uInnerSizer.release());
2529 }
2530
2531 mParent->SetSizer(outerSizer.release());
2532 }
2533
2534 // Try to give the window a sensible default/minimum size
2535 wxSize sz1 = innerSizer->GetMinSize();
2536 wxSize sz2 = mParent->GetMinSize();
2537 w->SetMinSize( { -1, std::min(sz1.y, sz2.y) } );
2538
2539 // And let the parent reduce to the NEW minimum if possible
2540 mParent->SetMinSize(w->GetMinSize());
2541
2543
2544 return true;
2545}
2546
2548{
2549 if (mUseGUI)
2550 {
2551 if (mSuilInstance)
2552 {
2553 for (auto & port : mControlPorts)
2554 {
2555 if (port->mIsInput)
2556 {
2557 suil_instance_port_event(mSuilInstance,
2558 port->mIndex,
2559 sizeof(float),
2560 0,
2561 &port->mVal);
2562 }
2563 }
2564 }
2565
2566 return true;
2567 }
2568
2569 for (auto & group : mGroups)
2570 {
2571 const auto & params = mGroupMap[group];
2572 for (auto & param : params)
2573 {
2574 auto & port = mControlPorts[param];
2575
2576 if (port->mTrigger)
2577 {
2578 continue;
2579 }
2580
2581 if (port->mToggle)
2582 {
2583 port->mCtrl.checkbox->SetValue(port->mVal > 0);
2584 }
2585 else if (port->mEnumeration) // Check before integer
2586 {
2587 int s;
2588 for (s = (int) port->mScaleValues.size() - 1; s >= 0; s--)
2589 {
2590 if (port->mVal >= port->mScaleValues[s])
2591 {
2592 break;
2593 }
2594 }
2595
2596 if (s < 0)
2597 {
2598 s = 0;
2599 }
2600
2601 port->mCtrl.choice->SetSelection(s);
2602 }
2603 else if (port->mIsInput)
2604 {
2605 port->mTmp = port->mVal * (port->mSampleRate ? mSampleRate : 1.0);
2606 SetSlider(port);
2607 }
2608 }
2609 }
2610
2611 if (mParent && !mParent->TransferDataToWindow())
2612 {
2613 return false;
2614 }
2615
2616 return true;
2617}
2618
2620{
2621 float lo = port->mLo;
2622 float hi = port->mHi;
2623 float val = port->mTmp;
2624
2625 if (port->mLogarithmic)
2626 {
2627 lo = logf(lo);
2628 hi = logf(hi);
2629 val = logf(val);
2630 }
2631
2632 port->mCtrl.slider->SetValue(lrintf((val - lo) / (hi - lo) * 1000.0));
2633}
2634
2635void LV2Effect::OnTrigger(wxCommandEvent &evt)
2636{
2637 auto & port = mControlPorts[evt.GetId() - ID_Triggers];
2638
2639 port->mVal = port->mDef;
2640}
2641
2642void LV2Effect::OnToggle(wxCommandEvent &evt)
2643{
2644 auto & port = mControlPorts[evt.GetId() - ID_Toggles];
2645
2646 port->mVal = evt.GetInt() ? 1.0 : 0.0;
2647}
2648
2649void LV2Effect::OnChoice(wxCommandEvent &evt)
2650{
2651 auto & port = mControlPorts[evt.GetId() - ID_Choices];
2652
2653 port->mVal = port->mScaleValues[evt.GetInt()];
2654}
2655
2656void LV2Effect::OnText(wxCommandEvent &evt)
2657{
2658 auto & port = mControlPorts[evt.GetId() - ID_Texts];
2659
2660 if (port->mText->GetValidator()->TransferFromWindow())
2661 {
2662 port->mVal = port->mSampleRate ? port->mTmp / mSampleRate : port->mTmp;
2663
2664 SetSlider(port);
2665 }
2666}
2667
2668void LV2Effect::OnSlider(wxCommandEvent &evt)
2669{
2670 auto & port = mControlPorts[evt.GetId() - ID_Sliders];
2671
2672 float lo = port->mLo;
2673 float hi = port->mHi;
2674
2675 if (port->mLogarithmic)
2676 {
2677 lo = logf(lo);
2678 hi = logf(hi);
2679 }
2680
2681 port->mTmp = (((float) evt.GetInt()) / 1000.0) * (hi - lo) + lo;
2682 port->mTmp = port->mLogarithmic ? expf(port->mTmp) : port->mTmp;
2683
2684 port->mTmp = port->mTmp < port->mLo ? port->mLo : port->mTmp;
2685 port->mTmp = port->mTmp > port->mHi ? port->mHi : port->mTmp;
2686
2687 port->mVal = port->mSampleRate ? port->mTmp / mSampleRate : port->mTmp;
2688
2689 port->mText->GetValidator()->TransferToWindow();
2690}
2691
2692void LV2Effect::OnTimer(wxTimerEvent &evt)
2693{
2694 evt.Skip();
2695
2696 if (mExternalWidget)
2697 {
2699 }
2700}
2701
2702void LV2Effect::OnIdle(wxIdleEvent &evt)
2703{
2704 evt.Skip();
2705
2706 if (!mSuilInstance)
2707 {
2708 return;
2709 }
2710
2712 {
2713 mExternalUIClosed = false;
2714 mDialog->Close();
2715 return;
2716 }
2717
2718 if (mUIIdleInterface)
2719 {
2720 SuilHandle handle = suil_instance_get_handle(mSuilInstance);
2721 if (mUIIdleInterface->idle(handle))
2722 {
2723 if (mUIShowInterface)
2724 {
2725 mUIShowInterface->hide(handle);
2726 }
2727 mDialog->Close();
2728 return;
2729 }
2730 }
2731
2732 if (mControlOut)
2733 {
2734 ZixRing *ring = mControlOut->mRing;
2735
2736 LV2_Atom *atom = (LV2_Atom *) malloc(mControlOut->mMinimumSize);
2737 if (atom)
2738 {
2739 while (zix_ring_read(ring, atom, sizeof(LV2_Atom)))
2740 {
2741 uint32_t size = lv2_atom_total_size(atom);
2742
2743 if (size < mControlOut->mMinimumSize)
2744 {
2745 zix_ring_read(ring, LV2_ATOM_CONTENTS(LV2_Atom, atom), atom->size);
2746 suil_instance_port_event(mSuilInstance,
2747 mControlOut->mIndex,
2748 size,
2749 LV2Symbols::urid_EventTransfer,
2750 atom);
2751 }
2752 else
2753 {
2754 zix_ring_skip(ring, atom->size);
2755 wxLogError(wxT("LV2 sequence buffer overflow"));
2756 }
2757 }
2758 free(atom);
2759 }
2760 }
2761
2762 for (auto & port : mControlPorts)
2763 {
2764 // Let UI know that a port's value has changed
2765 if (port->mVal != port->mLst)
2766 {
2767 suil_instance_port_event(mSuilInstance,
2768 port->mIndex,
2769 sizeof(port->mVal),
2770 0,
2771 &port->mVal);
2772 port->mLst = port->mVal;
2773 }
2774 }
2775}
2776
2777void LV2Effect::OnSize(wxSizeEvent & evt)
2778{
2779 evt.Skip();
2780
2781 // Don't do anything here if we're recursing
2782 if (mResizing)
2783 {
2784 return;
2785 }
2786
2787 // Indicate resizing is occurring
2788 mResizing = true;
2789
2790 // Can only resize AFTER the dialog has been completely created and
2791 // there's no need to resize if we're already at the desired size.
2792 if (mDialog && evt.GetSize() != mNativeWinLastSize)
2793 {
2794 // Save the desired size and set the native window to match
2795 mNativeWinLastSize = evt.GetSize();
2796 mNativeWin->SetMinSize(mNativeWinLastSize);
2797
2798 // Clear the minimum size of the parent window to allow the following
2799 // Fit() to make proper adjustments
2800 mParent->SetMinSize(wxDefaultSize);
2801
2802#if defined(__WXGTK__)
2803 // If the user resized the native window, then we need to also
2804 // clear the dialogs minimum size. If this isn't done, the dialog
2805 // will not resize properly when going from a larger size to a smaller
2806 // size (due to the minimum size constraint).
2807 //
2808 // In this case, mResized has been set by the "size_request()" function
2809 // to indicate that this is a plugin generated resize request.
2810 if (mResized)
2811 {
2812 mDialog->SetMinSize(wxDefaultSize);
2813 }
2814
2815 // Resize dialog
2816 mDialog->Fit();
2817
2818 // Reestablish the minimum (and maximum) now that the dialog
2819 // has is desired size.
2820 if (mResized)
2821 {
2822 mDialog->SetMinSize(mDialog->GetSize());
2823 if (mNoResize)
2824 {
2825 mDialog->SetMaxSize(mDialog->GetSize());
2826 }
2827 }
2828
2829 // Tell size_request() that the native window was just resized.
2830 mResized = true;
2831#else
2832 // Resize the dialog to fit its content.
2833 mDialog->Fit();
2834#endif
2835 }
2836
2837 // No longer resizing
2838 mResizing = false;
2839}
2840
2841// ============================================================================
2842// Feature handlers
2843// ============================================================================
2844
2845// static callback
2846uint32_t LV2Effect::uri_to_id(LV2_URI_Map_Callback_Data callback_data,
2847 const char *WXUNUSED(map),
2848 const char *uri)
2849{
2850 return ((LV2Effect *) callback_data)->URID_Map(uri);
2851}
2852
2853// static callback
2854LV2_URID LV2Effect::urid_map(LV2_URID_Map_Handle handle, const char *uri)
2855{
2856 return ((LV2Effect *) handle)->URID_Map(uri);
2857}
2858
2859LV2_URID LV2Effect::URID_Map(const char *uri)
2860{
2861 using namespace LV2Symbols;
2862 LV2_URID urid;
2863
2864 urid = Lookup_URI(gURIDMap, uri, false);
2865 if (urid > 0)
2866 {
2867 return urid;
2868 }
2869
2870 urid = Lookup_URI(mURIDMap, uri);
2871 if (urid > 0)
2872 {
2873 return urid + gURIDMap.size();
2874 }
2875
2876 return 0;
2877}
2878
2879// static callback
2880const char *LV2Effect::urid_unmap(LV2_URID_Unmap_Handle handle, LV2_URID urid)
2881{
2882 return ((LV2Effect *) handle)->URID_Unmap(urid);
2883}
2884
2885const char *LV2Effect::URID_Unmap(LV2_URID urid)
2886{
2887 using namespace LV2Symbols;
2888 if (urid > 0)
2889 {
2890 if (urid <= (LV2_URID) gURIDMap.size())
2891 {
2892 return mURIDMap[urid - 1].get();
2893 }
2894
2895 urid -= gURIDMap.size();
2896
2897 if (urid <= (LV2_URID) mURIDMap.size())
2898 {
2899 return mURIDMap[urid - 1].get();
2900 }
2901 }
2902
2903 return NULL;
2904}
2905
2906// static callback
2907int LV2Effect::log_printf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, ...)
2908{
2909 va_list ap;
2910 int len;
2911
2912 va_start(ap, fmt);
2913 len = ((LV2Effect *) handle)->LogVPrintf(type, fmt, ap);
2914 va_end(ap);
2915
2916 return len;
2917}
2918
2919// static callback
2920int LV2Effect::log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list ap)
2921{
2922 return ((LV2Effect *) handle)->LogVPrintf(type, fmt, ap);
2923}
2924
2925int LV2Effect::LogVPrintf(LV2_URID type, const char *fmt, va_list ap)
2926{
2927 using namespace LV2Symbols;
2928 long level = wxLOG_Error;
2929
2930 if (type == urid_Error)
2931 {
2932 level = wxLOG_Error;
2933 }
2934 else if (type == urid_Note)
2935 {
2936 level = wxLOG_Info;
2937 }
2938 else if (type == urid_Trace)
2939 {
2940 level = wxLOG_Trace;
2941 }
2942 else if (type == urid_Warning)
2943 {
2944 level = wxLOG_Warning;
2945 }
2946 else
2947 {
2948 level = wxLOG_Message;
2949 }
2950
2951 char *msg = NULL;
2952 int len = wxCRT_VsnprintfA(msg, 0, fmt, ap);
2953
2954 msg = (char *) malloc(len + 1);
2955 if (msg)
2956 {
2957 wxCRT_VsnprintfA(msg, len, fmt, ap);
2958
2959 wxString text(msg);
2960
2961 wxLogGeneric(level, wxT("%s: %s"), GetSymbol().Msgid().Translation(), text);
2962
2963 free(msg);
2964 }
2965
2966 return len;
2967}
2968
2969// static callback
2970int LV2Effect::ui_resize(LV2UI_Feature_Handle handle, int width, int height)
2971{
2972 return ((LV2Effect *) handle)->UIResize(width, height);
2973}
2974
2975int LV2Effect::UIResize(int width, int height)
2976{
2977 // Queue a wxSizeEvent to resize the plugins UI
2978 if (mNativeWin)
2979 {
2980 wxSizeEvent sw(wxSize(width, height));
2981 sw.SetEventObject(mNativeWin);
2982 mNativeWin->GetEventHandler()->AddPendingEvent(sw);
2983 }
2984 // The window hasn't been created yet, so record the desired size
2985 else
2986 {
2987 mNativeWinInitialSize = wxSize(width, height);
2988 }
2989
2990 return 0;
2991}
2992
2993// static callback
2994void LV2Effect::ui_closed(LV2UI_Controller controller)
2995{
2996 return ((LV2Effect *) controller)->UIClosed();
2997}
2998
3000{
3001 mExternalUIClosed = true;
3002
3003 return;
3004}
3005
3006// static callback
3007void LV2Effect::suil_port_write_func(SuilController controller,
3008 uint32_t port_index,
3009 uint32_t buffer_size,
3010 uint32_t protocol,
3011 const void *buffer)
3012{
3013 ((LV2Effect *) controller)->SuilPortWrite(port_index, buffer_size, protocol, buffer);
3014}
3015
3016void LV2Effect::SuilPortWrite(uint32_t port_index,
3017 uint32_t buffer_size,
3018 uint32_t protocol,
3019 const void *buffer)
3020{
3021 // Handle implicit floats
3022 if (protocol == 0 && buffer_size == sizeof(float))
3023 {
3024 auto it = mControlPortMap.find(port_index);
3025 if (it != mControlPortMap.end())
3026 {
3027 it->second->mVal = *((const float *) buffer);
3028 }
3029 }
3030 // Handle event transfers
3031 else if (protocol == LV2Symbols::urid_EventTransfer)
3032 {
3033 if (mControlIn && port_index == mControlIn->mIndex)
3034 {
3035 zix_ring_write(mControlIn->mRing, buffer, buffer_size);
3036 }
3037 }
3038
3039 return;
3040}
3041
3042// static callback
3043uint32_t LV2Effect::suil_port_index_func(SuilController controller,
3044 const char *port_symbol)
3045{
3046 return ((LV2Effect *) controller)->SuilPortIndex(port_symbol);
3047}
3048
3049uint32_t LV2Effect::SuilPortIndex(const char *port_symbol)
3050{
3051 for (size_t i = 0, cnt = lilv_plugin_get_num_ports(mPlug); i < cnt; i++)
3052 {
3053 const LilvPort *port = lilv_plugin_get_port_by_index(mPlug, i);
3054 if (strcmp(port_symbol, lilv_node_as_string(lilv_port_get_symbol(mPlug, port))) == 0)
3055 {
3056 return lilv_port_get_index(mPlug, port);
3057 }
3058 }
3059
3060 return LV2UI_INVALID_PORT_INDEX;
3061}
3062
3063// static callback
3064const void *LV2Effect::get_value_func(const char *port_symbol,
3065 void *user_data,
3066 uint32_t *size,
3067 uint32_t *type)
3068{
3069 return ((LV2Effect *) user_data)->GetPortValue(port_symbol, size, type);
3070}
3071
3072const void *LV2Effect::GetPortValue(const char *port_symbol,
3073 uint32_t *size,
3074 uint32_t *type)
3075{
3076 wxString symbol = wxString::FromUTF8(port_symbol);
3077
3078 for (auto & port : mControlPorts)
3079 {
3080 if (port->mSymbol == symbol)
3081 {
3082 *size = sizeof(float);
3083 *type = LV2Symbols::urid_Float;
3084 return (void *) &port->mVal;
3085 }
3086 }
3087
3088 *size = 0;
3089 *type = 0;
3090
3091 return NULL;
3092}
3093
3094// static callback
3095void LV2Effect::set_value_func(const char *port_symbol,
3096 void *user_data,
3097 const void *value,
3098 uint32_t size,
3099 uint32_t type)
3100{
3101 ((LV2Effect *) user_data)->SetPortValue(port_symbol, value, size, type);
3102}
3103
3104void LV2Effect::SetPortValue(const char *port_symbol,
3105 const void *value,
3106 uint32_t size,
3107 uint32_t type)
3108{
3109 wxString symbol = wxString::FromUTF8(port_symbol);
3110
3111 for (auto & port : mControlPorts)
3112 {
3113 using namespace LV2Symbols;
3114 if (port->mSymbol == symbol)
3115 {
3116 if (type == urid_Bool && size == sizeof(bool))
3117 {
3118 port->mVal = (float) (*((const bool *) value)) ? 1.0f : 0.0f;
3119 }
3120 else if (type == urid_Double && size == sizeof(double))
3121 {
3122 port->mVal = (float) (*((const double *) value));
3123 }
3124 else if (type == urid_Float && size == sizeof(float))
3125 {
3126 port->mVal = (float) (*((const float *) value));
3127 }
3128 else if (type == urid_Int && size == sizeof(int32_t))
3129 {
3130 port->mVal = (float) (*((const int32_t *) value));
3131 }
3132 else if (type == urid_Long && size == sizeof(int64_t))
3133 {
3134 port->mVal = (float) (*((const int64_t *) value));
3135 }
3136
3137 break;
3138 }
3139 }
3140}
3141
3142#if defined(__WXGTK__)
3143// static callback
3144//
3145// Need to queue a wxSizeEvent when the native window gets resized outside of
3146// WX control. Many of the x42 LV2 plugins can resize themselves when changing
3147// the scale factor. (e.g., open "x42-dpl" effect and right click to change scaling)
3148void LV2Effect::size_request(GtkWidget *widget, GtkRequisition *requisition, LV2Effect *effect)
3149{
3150 effect->SizeRequest(widget, requisition);
3151}
3152
3153void LV2Effect::SizeRequest(GtkWidget *widget, GtkRequisition *requisition)
3154{
3155 // Don't do anything if the OnSize() method is active
3156 if (!mResizing)
3157 {
3158 // If the OnSize() routine has processed an event, mResized will be true,
3159 // so just set the widgets size.
3160 if (mResized)
3161 {
3162 gtk_widget_set_size_request(widget, mNativeWinLastSize.x, mNativeWinLastSize.y);
3163 mResized = false;
3164 }
3165 // Otherwise, the plugin has resized the widget and we need to let WX know
3166 // about it.
3167 else if (mNativeWin)
3168 {
3169 mResized = true;
3170 wxSizeEvent se(wxSize(requisition->width, requisition->height));
3171 se.SetEventObject(mNativeWin);
3172 mNativeWin->GetEventHandler()->AddPendingEvent(se);
3173 }
3174 }
3175}
3176#endif
3177
3179: mEffect(effect)
3180{
3181 mInstance = NULL;
3182 mHandle = NULL;
3183 mOptionsInterface = NULL;
3184 mStateInterface = NULL;
3185 mWorkerInterface = NULL;
3186 mWorkerSchedule = {};
3187 mFreeWheeling = false;
3188 mLatency = 0.0;
3189 mStopWorker = false;
3190}
3191
3193{
3194 if (mInstance)
3195 {
3196 wxThread *thread = GetThread();
3197 if (thread && thread->IsAlive())
3198 {
3199 mStopWorker = true;
3200
3201 LV2Work work = {0, NULL};
3202 mRequests.Post(work);
3203
3204 thread->Wait();
3205 }
3206
3207 if (mEffect->mActivated)
3208 {
3209 lilv_instance_deactivate(mInstance);
3210 mEffect->mActivated = false;
3211 }
3212
3213 lilv_instance_free(mInstance);
3214 mInstance = NULL;
3215 }
3216}
3217
3218LilvInstance *LV2Wrapper::Instantiate(const LilvPlugin *plugin,
3219 double sampleRate,
3220 std::vector<std::unique_ptr<LV2_Feature>> & features)
3221{
3223 {
3224 // Remove terminator
3225 features.pop_back();
3226
3227 mWorkerSchedule.handle = this;
3229 mEffect->AddFeature(LV2_WORKER__schedule, &mWorkerSchedule);
3230
3231 mEffect->AddFeature(NULL, NULL);
3232 }
3233
3234#if defined(__WXMSW__)
3235 // Plugins may have dependencies that need to be loaded from the same path
3236 // as the main DLL, so add this plugin's path to the DLL search order.
3237 const LilvNode *const libNode = lilv_plugin_get_library_uri(plugin);
3238 const char *const libUri = lilv_node_as_uri(libNode);
3239 char *libPath = lilv_file_uri_parse(libUri, NULL);
3240 wxString path = wxPathOnly(libPath);
3241 SetDllDirectory(path.c_str());
3242 lilv_free(libPath);
3243#endif
3244
3245 mInstance = lilv_plugin_instantiate(plugin,
3246 sampleRate,
3247 reinterpret_cast<LV2_Feature **>(features.data()));
3248
3249#if defined(__WXMSW__)
3250 SetDllDirectory(NULL);
3251#endif
3252
3254 {
3255 // Remove terminator
3256 features.pop_back();
3257
3258 // Remove the worker interface feature
3259 features.pop_back();
3260
3261 // Re-add terminator
3262 mEffect->AddFeature(NULL, NULL);
3263 }
3264
3265 if (!mInstance)
3266 {
3267 return NULL;
3268 }
3269
3270 mHandle = lilv_instance_get_handle(mInstance);
3271
3272 mOptionsInterface = (LV2_Options_Interface *)
3273 lilv_instance_get_extension_data(mInstance, LV2_OPTIONS__interface);
3274
3275 mStateInterface = (LV2_State_Interface *)
3276 lilv_instance_get_extension_data(mInstance, LV2_STATE__interface);
3277
3278 mWorkerInterface = (LV2_Worker_Interface *)
3279 lilv_instance_get_extension_data(mInstance, LV2_WORKER__interface);
3280
3281 if (mEffect->mLatencyPort >= 0)
3282 {
3283 lilv_instance_connect_port(mInstance, mEffect->mLatencyPort, &mLatency);
3284 }
3285
3286 if (mWorkerInterface)
3287 {
3288 if (CreateThread() == wxTHREAD_NO_ERROR)
3289 {
3290 GetThread()->Run();
3291 }
3292
3293 }
3294
3295 return mInstance;
3296}
3297
3299{
3300 return mInstance;
3301}
3302
3304{
3305 return mHandle;
3306}
3307
3309{
3310 return mLatency;
3311}
3312
3314{
3315 mFreeWheeling = enable;
3316}
3317
3319{
3321 {
3322 LV2_Options_Option options[2] = {};
3323
3324 memcpy(&options,
3326 sizeof(mEffect->mOptions[0]));
3327
3328 mOptionsInterface->set(mHandle, options);
3329 }
3330}
3331
3333{
3335 {
3336 LV2_Options_Option options[2] = {};
3337 memcpy(&options,
3339 sizeof(mEffect->mOptions[0]));
3340
3341 mOptionsInterface->set(mHandle, options);
3342 }
3343}
3344
3345void LV2Wrapper::ConnectPorts(float **inbuf, float **outbuf)
3346{
3347}
3348
3350{
3351 LV2Work work;
3352
3353 while (mRequests.Receive(work) == wxMSGQUEUE_NO_ERROR)
3354 {
3355 if (mStopWorker)
3356 {
3357 break;
3358 }
3359
3361 respond,
3362 this,
3363 work.size,
3364 work.data);
3365 }
3366
3367 return (void *) 0;
3368}
3369
3371{
3372 if (mWorkerInterface)
3373 {
3374 LV2Work work;
3375
3376 while (mResponses.ReceiveTimeout(0, work) == wxMSGQUEUE_NO_ERROR)
3377 {
3378 mWorkerInterface->work_response(mHandle, work.size, work.data);
3379 }
3380
3381 if (mWorkerInterface->end_run)
3382 {
3383 mWorkerInterface->end_run(mHandle);
3384 }
3385 }
3386}
3387
3388// static callback
3389LV2_Worker_Status LV2Wrapper::schedule_work(LV2_Worker_Schedule_Handle handle,
3390 uint32_t size,
3391 const void *data)
3392{
3393 return ((LV2Wrapper *) handle)->ScheduleWork(size, data);
3394}
3395
3396LV2_Worker_Status LV2Wrapper::ScheduleWork(uint32_t size, const void *data)
3397{
3398 if (mFreeWheeling)
3399 {
3400 return mWorkerInterface->work(mHandle,
3401 respond,
3402 this,
3403 size,
3404 data);
3405 }
3406
3407 LV2Work work = {size, data};
3408
3409 mRequests.Post(work);
3410
3411 return LV2_WORKER_SUCCESS;
3412}
3413
3414// static callback
3415LV2_Worker_Status LV2Wrapper::respond(LV2_Worker_Respond_Handle handle,
3416 uint32_t size,
3417 const void *data)
3418{
3419 return ((LV2Wrapper *) handle)->Respond(size, data);
3420}
3421
3422LV2_Worker_Status LV2Wrapper::Respond(uint32_t size, const void *data)
3423{
3424 LV2Work work = {size, data};
3425
3426 mResponses.Post(work);
3427
3428 return LV2_WORKER_SUCCESS;
3429}
3430
3431#endif
3432
wxEVT_COMMAND_BUTTON_CLICKED
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
static const AudacityProject::AttachedObjects::RegisteredFactory key
int min(int a, int b)
#define str(a)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
EffectDistortion::Params params
Definition: Distortion.cpp:83
const TranslatableString name
Definition: Distortion.cpp:82
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeTool
@ EffectTypeProcess
enum ChannelName * ChannelNames
EVT_COMMAND_RANGE(ID_Slider, ID_Slider+NUMBER_OF_BANDS - 1, wxEVT_COMMAND_SLIDER_UPDATED, EffectEqualization::OnSlider) EffectEqualization
wxString RegistryPath
Definition: Identifier.h:218
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define DEFAULT_BLOCKSIZE
Definition: LV2Effect.cpp:70
@ ID_Triggers
Definition: LV2Effect.cpp:331
@ ID_Texts
Definition: LV2Effect.cpp:335
@ ID_Duration
Definition: LV2Effect.cpp:330
@ ID_Choices
Definition: LV2Effect.cpp:334
@ ID_TIMER
Definition: LV2Effect.cpp:336
@ ID_Sliders
Definition: LV2Effect.cpp:333
@ ID_Toggles
Definition: LV2Effect.cpp:332
#define DEFAULT_SEQSIZE
Definition: LV2Effect.cpp:73
wxString LilvString(const LilvNode *node)
Definition: LV2Effect.h:560
#define LV2EFFECTS_FAMILY
Definition: LV2Effect.h:60
std::shared_ptr< LV2ControlPort > LV2ControlPortPtr
Definition: LV2Effect.h:245
#define LV2_UI__makeResident
Definition: LV2Symbols.h:42
#define safenew
Definition: MemoryX.h:10
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:162
wxEVT_COMMAND_TEXT_UPDATED
Definition: Nyquist.cpp:133
EffectReverbSettings preset
Definition: Reverb.cpp:46
@ eIsCreating
Definition: ShuttleGui.h:39
@ eIsGettingFromDialog
Definition: ShuttleGui.h:40
TranslatableString label
Definition: TagsEditor.cpp:163
#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)
Definition: MemoryX.h:109
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,...
Base class for many of the effects in Audacity.
Definition: Effect.h:148
Performs effect computation.
virtual const EffectSettings & Get()=0
Abstract base class used in importing a file.
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
virtual ~LV2Effect()
Definition: LV2Effect.cpp:403
VendorSymbol GetVendor() const override
Definition: LV2Effect.cpp:421
std::unique_ptr< EffectUIValidator > PopulateUI(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Adds controls to a panel that is given as the parent window of S
Definition: LV2Effect.cpp:1485
LV2_Feature * mParentFeature
Definition: LV2Effect.h:527
LV2AudioPortArray mAudioPorts
Definition: LV2Effect.h:452
bool RealtimeProcessStart(EffectSettings &settings) override
Definition: LV2Effect.cpp:1211
void OnTimer(wxTimerEvent &evt)
Definition: LV2Effect.cpp:2692
bool mFactoryPresetsLoaded
Definition: LV2Effect.h:549
static void ui_closed(LV2UI_Controller controller)
Definition: LV2Effect.cpp:2994
size_t mSampleRateOption
Definition: LV2Effect.h:520
wxSize mNativeWinInitialSize
Definition: LV2Effect.h:536
LV2AtomPortArray mAtomPorts
Definition: LV2Effect.h:456
LV2_Extension_Data_Feature mExtensionDataFeature
Definition: LV2Effect.h:510
void UIClosed()
Definition: LV2Effect.cpp:2999
bool ValidateOptions(const LilvNode *subject)
Definition: LV2Effect.cpp:1858
PluginPath GetPath() const override
Definition: LV2Effect.cpp:411
void SuilPortWrite(uint32_t port_index, uint32_t buffer_size, uint32_t protocol, const void *buffer)
Definition: LV2Effect.cpp:3016
bool mUseGUI
Definition: LV2Effect.h:502
size_t RealtimeProcess(int group, EffectSettings &settings, const float *const *inbuf, float *const *outbuf, size_t numSamples) override
Definition: LV2Effect.cpp:1299
void SetSlider(const LV2ControlPortPtr &port)
Definition: LV2Effect.cpp:2619
void FreeInstance(LV2Wrapper *wrapper)
Definition: LV2Effect.cpp:1987
LV2ControlPortArray mControlPorts
Definition: LV2Effect.h:450
size_t AddOption(LV2_URID, uint32_t size, LV2_URID, const void *value)
Definition: LV2Effect.cpp:1759
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
Definition: LV2Effect.cpp:1611
size_t GetBlockSize() const override
Definition: LV2Effect.cpp:987
wxTimer mTimer
Definition: LV2Effect.h:497
LV2Wrapper * InitInstance(float sampleRate)
Definition: LV2Effect.cpp:1921
int mMinBlockSize
Definition: LV2Effect.h:445
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
Definition: LV2Effect.cpp:926
bool SupportsAutomation() const override
Whether the effect has any automatable controls.
Definition: LV2Effect.cpp:489
LV2AtomPortPtr mControlOut
Definition: LV2Effect.h:458
SuilInstance * mSuilInstance
Definition: LV2Effect.h:533
EffectFamilySymbol GetFamily() const override
Report identifier and user-visible name of the effect protocol.
Definition: LV2Effect.cpp:467
bool ValidateUI(EffectSettings &) override
Definition: LV2Effect.cpp:1535
void ExportPresets(const EffectSettings &settings) const override
Definition: LV2Effect.cpp:1693
bool DoLoadFactoryPreset(int id)
Definition: LV2Effect.cpp:1659
bool RealtimeProcessEnd(EffectSettings &settings) noexcept override
Definition: LV2Effect.cpp:1371
bool mExternalUIClosed
Definition: LV2Effect.h:514
void ShowOptions() override
Definition: LV2Effect.cpp:1706
bool RealtimeSuspend() override
Definition: LV2Effect.cpp:1193
std::vector< LV2Wrapper * > mSlaves
Definition: LV2Effect.h:482
bool HasOptions() override
Definition: LV2Effect.cpp:1701
void SizeRequest(GtkWidget *widget, GtkRequisition *requisition)
Definition: LV2Effect.cpp:3153
bool mResized
Definition: LV2Effect.h:540
wxWeakRef< wxDialog > mDialog
Definition: LV2Effect.h:499
LV2_URID_Unmap mURIDUnmapFeature
Definition: LV2Effect.h:507
void SetPortValue(const char *port_symbol, const void *value, uint32_t size, uint32_t type)
Definition: LV2Effect.cpp:3104
bool SaveParameters(const RegistryPath &group, const EffectSettings &settings) const
Definition: LV2Effect.cpp:1744
static LV2_URID urid_map(LV2_URID_Map_Handle handle, const char *uri)
Definition: LV2Effect.cpp:2854
std::unordered_map< TranslatableString, std::vector< int > > mGroupMap
Definition: LV2Effect.h:466
int mMaxBlockSize
Definition: LV2Effect.h:446
int LogVPrintf(LV2_URID type, const char *fmt, va_list ap)
Definition: LV2Effect.cpp:2925
bool InitializePlugin()
Definition: LV2Effect.cpp:494
size_t mNumSamples
Definition: LV2Effect.h:485
bool CheckFeatures(const LilvNode *subject, const LilvNode *predicate, bool required)
Definition: LV2Effect.cpp:1804
size_t SetBlockSize(size_t maxBlockSize) override
Definition: LV2Effect.cpp:961
bool BuildFancy()
Definition: LV2Effect.cpp:1992
bool DoLoadUserPreset(const RegistryPath &name, EffectSettings &settings)
Definition: LV2Effect.cpp:1594
LV2CVPortArray mCVPorts
Definition: LV2Effect.h:462
bool RealtimeAddProcessor(EffectSettings &settings, unsigned numChannels, float sampleRate) override
Definition: LV2Effect.cpp:1176
bool mRolling
Definition: LV2Effect.h:477
RegistryPaths mFactoryPresetNames
Definition: LV2Effect.h:550
bool TransferDataToWindow()
Definition: LV2Effect.cpp:2547
void OnTrigger(wxCommandEvent &evt)
Definition: LV2Effect.cpp:2635
bool mLatencyDone
Definition: LV2Effect.h:476
bool mNoResize
Definition: LV2Effect.h:472
static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, const char *map, const char *uri)
Definition: LV2Effect.cpp:2846
int UIResize(int width, int height)
Definition: LV2Effect.cpp:2975
bool mWantsStateInterface
Definition: LV2Effect.h:470
bool mActivated
Definition: LV2Effect.h:478
void SetSampleRate(double rate) override
Definition: LV2Effect.cpp:946
LV2_External_UI_Widget * mExternalWidget
Definition: LV2Effect.h:513
bool mSupportsNominalBlockLength
Definition: LV2Effect.h:521
bool LoadParameters(const RegistryPath &group, EffectSettings &settings)
Definition: LV2Effect.cpp:1725
void ImportPresets(EffectSettings &settings) override
Definition: LV2Effect.cpp:1697
const LilvPlugin * mPlug
Definition: LV2Effect.h:439
LV2_URI_Map_Feature mUriMapFeature
Definition: LV2Effect.h:505
sampleCount GetLatency() override
Definition: LV2Effect.cpp:992
LV2Symbols::URIDMap mURIDMap
Definition: LV2Effect.h:437
bool LoadFactoryPreset(int id, EffectSettings &settings) const override
Change settings to the preset whose name is GetFactoryPresets()[id]
Definition: LV2Effect.cpp:1653
bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const override
Store settings as keys and values.
Definition: LV2Effect.cpp:1423
bool RealtimeResume() noexcept override
Definition: LV2Effect.cpp:1202
int mSeqSize
Definition: LV2Effect.h:443
bool ProcessFinalize() override
Definition: LV2Effect.cpp:1025
const char * URID_Unmap(LV2_URID urid)
Definition: LV2Effect.cpp:2885
LV2Wrapper * mMaster
Definition: LV2Effect.h:480
bool mUseLatency
Definition: LV2Effect.h:474
unsigned mAudioOut
Definition: LV2Effect.h:454
bool ProcessInitialize(EffectSettings &settings, sampleCount totalLen, ChannelNames chanMap) override
Definition: LV2Effect.cpp:1003
LV2_URID_Map mURIDMapFeature
Definition: LV2Effect.h:506
static void size_request(GtkWidget *widget, GtkRequisition *requisition, LV2Effect *win)
Definition: LV2Effect.cpp:3148
LV2_URID URID_Map(const char *uri)
Definition: LV2Effect.cpp:2859
bool CloseUI() override
Definition: LV2Effect.cpp:1543
int mBlockSize
Definition: LV2Effect.h:442
uint32_t SuilPortIndex(const char *port_symbol)
Definition: LV2Effect.cpp:3049
EffectType GetType() const override
Type determines how it behaves.
Definition: LV2Effect.cpp:447
bool mResizing
Definition: LV2Effect.h:538
bool SupportsRealtime() const override
Whether the effect supports realtime previewing (while audio is playing).
Definition: LV2Effect.cpp:482
static const char * urid_unmap(LV2_URID_Unmap_Handle handle, LV2_URID urid)
Definition: LV2Effect.cpp:2880
bool RealtimeFinalize(EffectSettings &settings) noexcept override
Definition: LV2Effect.cpp:1151
TranslatableStrings mGroups
Definition: LV2Effect.h:467
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: LV2Effect.cpp:931
wxString GetVersion() const override
Definition: LV2Effect.cpp:433
std::vector< LV2_Options_Option > mOptions
Definition: LV2Effect.h:518
FloatBuffers mMasterIn
Definition: LV2Effect.h:484
NativeWindow * mNativeWin
Definition: LV2Effect.h:535
bool CheckOptions(const LilvNode *subject, const LilvNode *predicate, bool required)
Definition: LV2Effect.cpp:1868
LV2UI_Show_Interface * mUIShowInterface
Definition: LV2Effect.h:544
void OnSlider(wxCommandEvent &evt)
Definition: LV2Effect.cpp:2668
NumericTextCtrl * mDuration
Definition: LV2Effect.h:546
LV2UI_Resize mUIResizeFeature
Definition: LV2Effect.h:508
static int ui_resize(LV2UI_Feature_Handle handle, int width, int height)
Definition: LV2Effect.cpp:2970
SuilHost * mSuilHost
Definition: LV2Effect.h:532
friend class LV2Wrapper
Definition: LV2Effect.h:555
wxArrayString mFactoryPresetUris
Definition: LV2Effect.h:551
wxSize mNativeWinLastSize
Definition: LV2Effect.h:537
const void * GetPortValue(const char *port_symbol, uint32_t *size, uint32_t *type)
Definition: LV2Effect.cpp:3072
bool mWantsOptionsInterface
Definition: LV2Effect.h:469
bool mSupportsSampleRate
Definition: LV2Effect.h:522
bool ValidateFeatures(const LilvNode *subject)
Definition: LV2Effect.cpp:1794
float mPositionFrame
Definition: LV2Effect.h:493
ComponentInterfaceSymbol GetSymbol() const override
Definition: LV2Effect.cpp:416
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: LV2Effect.cpp:1036
static void set_value_func(const char *port_symbol, void *user_data, const void *value, uint32_t size, uint32_t type)
Definition: LV2Effect.cpp:3095
void OnText(wxCommandEvent &evt)
Definition: LV2Effect.cpp:2656
static int log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list ap)
Definition: LV2Effect.cpp:2920
std::unordered_map< uint32_t, LV2ControlPortPtr > mControlPortMap
Definition: LV2Effect.h:449
LV2_Feature * AddFeature(const char *uri, void *data)
Definition: LV2Effect.cpp:1779
int GetMidiOutCount() const override
Function that has not yet found a use.
Definition: LV2Effect.cpp:941
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
Definition: LV2Effect.cpp:1440
LV2AtomPortPtr mControlIn
Definition: LV2Effect.h:457
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
Definition: LV2Effect.cpp:903
float mSampleRate
Definition: LV2Effect.h:441
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
Definition: LV2Effect.cpp:472
bool CanExportPresets() override
Definition: LV2Effect.cpp:1688
bool LoadUserPreset(const RegistryPath &name, EffectSettings &settings) const override
Change settings to a user-named preset.
Definition: LV2Effect.cpp:1587
void OnChoice(wxCommandEvent &evt)
Definition: LV2Effect.cpp:2649
bool mWantsWorkerInterface
Definition: LV2Effect.h:471
void OnIdle(wxIdleEvent &evt)
Definition: LV2Effect.cpp:2702
std::shared_ptr< EffectInstance > DoMakeInstance()
Definition: LV2Effect.cpp:908
int mLatencyPort
Definition: LV2Effect.h:475
LV2_External_UI_Host mExternalUIHost
Definition: LV2Effect.h:512
void OnSize(wxSizeEvent &evt)
Definition: LV2Effect.cpp:2777
LV2_Feature * mInstanceAccessFeature
Definition: LV2Effect.h:526
TranslatableString GetDescription() const override
Definition: LV2Effect.cpp:438
bool SaveUserPreset(const RegistryPath &name, const EffectSettings &settings) const override
Save settings in the configuration file as a user-named preset.
Definition: LV2Effect.cpp:1605
LV2_Atom_Forge mForge
Definition: LV2Effect.h:516
size_t mBlockSizeOption
Definition: LV2Effect.h:519
bool RealtimeInitialize(EffectSettings &settings) override
Definition: LV2Effect.cpp:1137
unsigned mMidiIn
Definition: LV2Effect.h:459
wxWindow * mParent
Definition: LV2Effect.h:500
static const void * get_value_func(const char *port_symbol, void *user_data, uint32_t *size, uint32_t *type)
Definition: LV2Effect.cpp:3064
unsigned mAudioIn
Definition: LV2Effect.h:453
float mPositionSpeed
Definition: LV2Effect.h:492
LV2Wrapper * mProcess
Definition: LV2Effect.h:481
bool IsGraphicalUI() override
Definition: LV2Effect.cpp:1530
std::vector< std::unique_ptr< LV2_Feature > > mFeatures
Definition: LV2Effect.h:524
static void suil_port_write_func(SuilController controller, uint32_t port_index, uint32_t buffer_size, uint32_t protocol, const void *buffer)
Definition: LV2Effect.cpp:3007
void OnToggle(wxCommandEvent &evt)
Definition: LV2Effect.cpp:2642
LV2_Log_Log mLogFeature
Definition: LV2Effect.h:509
static int log_printf(LV2_Log_Handle handle, LV2_URID type, const char *fmt,...)
Definition: LV2Effect.cpp:2907
LV2UI_Idle_Interface * mUIIdleInterface
Definition: LV2Effect.h:543
static uint32_t suil_port_index_func(SuilController controller, const char *port_symbol)
Definition: LV2Effect.cpp:3043
int ShowClientInterface(wxWindow &parent, wxDialog &dialog, bool forceModal) override
Definition: LV2Effect.cpp:1399
int mUserBlockSize
Definition: LV2Effect.h:447
int GetMidiInCount() const override
Function that has not yet found a use.
Definition: LV2Effect.cpp:936
unsigned mMidiOut
Definition: LV2Effect.h:460
bool IsDefault() const override
Whether the effect sorts "above the line" in the menus.
Definition: LV2Effect.cpp:477
bool BuildPlain(EffectSettingsAccess &access)
Definition: LV2Effect.cpp:2236
float mLastValue
Definition: LV2Effect.cpp:95
void OnErase(wxEraseEvent &evt)
Definition: LV2Effect.cpp:129
LV2EffectMeter(wxWindow *parent, const LV2ControlPortPtr ctrl)
Definition: LV2Effect.cpp:107
const LV2ControlPortPtr mControlPort
Definition: LV2Effect.cpp:94
void OnPaint(wxPaintEvent &evt)
Definition: LV2Effect.cpp:134
void OnSize(wxSizeEvent &evt)
Definition: LV2Effect.cpp:167
void OnIdle(wxIdleEvent &evt)
Definition: LV2Effect.cpp:120
virtual ~LV2EffectMeter()
Definition: LV2Effect.cpp:116
void PopulateOrExchange(ShuttleGui &S)
Definition: LV2Effect.cpp:221
LV2EffectSettingsDialog(wxWindow *parent, LV2Effect &effect)
Definition: LV2Effect.cpp:201
virtual ~LV2EffectSettingsDialog()
Definition: LV2Effect.cpp:217
void OnOk(wxCommandEvent &evt)
Definition: LV2Effect.cpp:302
LV2_Worker_Interface * mWorkerInterface
Definition: LV2Effect.h:637
LV2Wrapper(LV2Effect *effect)
Definition: LV2Effect.cpp:3178
static LV2_Worker_Status respond(LV2_Worker_Respond_Handle handle, uint32_t size, const void *data)
Definition: LV2Effect.cpp:3415
void SetSampleRate()
Definition: LV2Effect.cpp:3318
LV2_Handle GetHandle()
Definition: LV2Effect.cpp:3303
LV2_Worker_Status ScheduleWork(uint32_t size, const void *data)
Definition: LV2Effect.cpp:3396
void SetBlockSize()
Definition: LV2Effect.cpp:3332
LV2_Worker_Status Respond(uint32_t size, const void *data)
Definition: LV2Effect.cpp:3422
wxMessageQueue< LV2Work > mRequests
Definition: LV2Effect.h:627
float GetLatency()
Definition: LV2Effect.cpp:3308
LV2Effect * mEffect
Definition: LV2Effect.h:623
bool mStopWorker
Definition: LV2Effect.h:642
LV2_State_Interface * mStateInterface
Definition: LV2Effect.h:634
virtual ~LV2Wrapper()
Definition: LV2Effect.cpp:3192
LilvInstance * Instantiate(const LilvPlugin *plugin, double sampleRrate, std::vector< std::unique_ptr< LV2_Feature > > &features)
Definition: LV2Effect.cpp:3218
void ConnectPorts(float **inbuf, float **outbuf)
Definition: LV2Effect.cpp:3345
void SetFreeWheeling(bool enable)
Definition: LV2Effect.cpp:3313
LV2_Worker_Schedule mWorkerSchedule
Definition: LV2Effect.h:638
static LV2_Worker_Status schedule_work(LV2_Worker_Schedule_Handle handle, uint32_t size, const void *data)
Definition: LV2Effect.cpp:3389
LV2_Options_Interface * mOptionsInterface
Definition: LV2Effect.h:631
LilvInstance * GetInstance()
Definition: LV2Effect.cpp:3298
LV2_Handle mHandle
Definition: LV2Effect.h:625
void * Entry()
Definition: LV2Effect.cpp:3349
float mLatency
Definition: LV2Effect.h:640
bool mFreeWheeling
Definition: LV2Effect.h:641
LilvInstance * mInstance
Definition: LV2Effect.h:624
void SendResponses()
Definition: LV2Effect.cpp:3370
wxMessageQueue< LV2Work > mResponses
Definition: LV2Effect.h:628
void SetName(const TranslatableString &name)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
#define lrintf(flt)
Definition: float_cast.h:170
uint32_t zix_ring_read(ZixRing *ring, void *dst, uint32_t size)
Definition: ring.cpp:172
ZixRing * zix_ring_new(uint32_t size)
Definition: ring.cpp:74
uint32_t zix_ring_write(ZixRing *ring, const void *src, uint32_t size)
Definition: ring.cpp:201
uint32_t zix_ring_skip(ZixRing *ring, uint32_t size)
Definition: ring.cpp:187
void zix_ring_mlock(ZixRing *ring)
Definition: ring.cpp:93
#define LV2_EXTERNAL_UI_SHOW(ptr)
#define LV2_EXTERNAL_UI_DEPRECATED_URI
#define LV2_EXTERNAL_UI_RUN(ptr)
#define LV2_EXTERNAL_UI__Widget
#define LV2_EXTERNAL_UI__Host
LilvWorld * gWorld
Definition: LV2Symbols.cpp:31
LV2_URID Lookup_URI(URIDMap &map, const char *uri, bool add)
Definition: LV2Symbols.cpp:76
URIDMap gURIDMap
Declare the global map of positive integers to URIs.
Definition: LV2Symbols.cpp:34
bool SetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, const Value &value)
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
std::string ToUTF8(const std::wstring &wstr)
const char * plugin_human_id
void(* ui_closed)(LV2UI_Controller controller)
Externalized state of a plug-in.
EffectSettingsExtra extra
const void * data
Definition: LV2Effect.h:582
Options & AutoPos(bool enable)
uint32_t size
Size (capacity) in bytes.
Definition: ring.cpp:54