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