audacia/src/effects/lv2/LV2Effect.h

653 lines
16 KiB
C++
Executable File

/**********************************************************************
Audacity: A Digital Audio Editor
LV2Effect.h
Audacity(R) is copyright (c) 1999-2013 Audacity Team.
License: GPL v2. See License.txt.
*********************************************************************/
#include "../../Audacity.h" // for USE_* macros
#if USE_LV2
class wxArrayString;
#include <vector>
#include <wx/event.h> // to inherit
#include <wx/msgqueue.h>
#include <wx/thread.h>
#include <wx/timer.h>
#include "lv2/atom/forge.h"
#include "lv2/data-access/data-access.h"
#include "lv2/log/log.h"
#include "lv2/midi/midi.h"
#include "lv2/options/options.h"
#include "lv2/state/state.h"
#include "lv2/time/time.h"
#include "lv2/uri-map/uri-map.h"
#include "lv2/urid/urid.h"
#include "lv2/worker/worker.h"
#include "lv2/ui/ui.h"
#include <lilv/lilv.h>
#include <suil/suil.h>
#include "../../ShuttleGui.h"
#include "../../SampleFormat.h"
#include "LoadLV2.h"
#include "NativeWindow.h"
#include "lv2_external_ui.h"
#include "zix/ring.h"
#include <unordered_map>
class wxSlider;
class wxTextCtrl;
class NumericTextCtrl;
#define LV2EFFECTS_VERSION wxT("1.0.0.0")
/* i18n-hint: abbreviates
"Linux Audio Developer's Simple Plugin API (LADSPA) version 2" */
#define LV2EFFECTS_FAMILY XO("LV2")
// DECLARE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW, -1);
class LV2Port
{
public:
LV2Port(const LilvPort *port,
int index,
bool isInput,
const wxString & symbol,
const wxString & name,
const wxString & group)
: mPort(port),
mIndex(index),
mIsInput(isInput),
mSymbol(symbol),
mName(name),
mGroup(group)
{
};
LV2Port(const LV2Port &) = default;
LV2Port &operator = (const LV2Port &) = default;
const LilvPort *mPort;
uint32_t mIndex;
bool mIsInput;
wxString mSymbol;
wxString mName;
wxString mGroup;
};
class LV2AudioPort : public LV2Port
{
public:
LV2AudioPort(const LilvPort *port,
int index,
bool isInput,
const wxString & symbol,
const wxString & name,
const wxString & group)
: LV2Port(port, index, isInput, symbol, name, group)
{
}
};
using LV2AudioPortPtr = std::shared_ptr<LV2AudioPort>;
using LV2AudioPortArray = std::vector<LV2AudioPortPtr>;
class LV2AtomPort : public LV2Port
{
public:
LV2AtomPort(const LilvPort *port,
int index,
bool isInput,
const wxString & symbol,
const wxString & name,
const wxString & group)
: LV2Port(port, index, isInput, symbol, name, group)
{
mIsMidi = false;
mWantsPosition = false;
mMinimumSize = 1024;
mRing = NULL;
}
virtual ~LV2AtomPort()
{
if (mRing)
{
zix_ring_free(mRing);
}
}
uint32_t mMinimumSize;
bool mIsMidi;
bool mWantsPosition;
std::vector<uint8_t> mBuffer;
ZixRing *mRing;
};
using LV2AtomPortPtr = std::shared_ptr<LV2AtomPort>;
using LV2AtomPortArray = std::vector<LV2AtomPortPtr>;
class LV2CVPort : public LV2Port
{
public:
LV2CVPort(const LilvPort *port,
int index,
bool isInput,
const wxString & symbol,
const wxString & name,
const wxString & group)
: LV2Port(port, index, isInput, symbol, name, group)
{
mMin = 0.0;
mMax = 1.0;
mDef = 0.0;
mHasLo = false;
mHasHi = false;
};
float mMin;
float mMax;
float mDef;
bool mHasLo;
bool mHasHi;
Floats mBuffer;
};
using LV2CVPortPtr = std::shared_ptr<LV2CVPort>;
using LV2CVPortArray = std::vector<LV2CVPortPtr>;
class LV2EffectMeter;
/** A structure that contains information about a single LV2 plugin port. */
class LV2ControlPort : public LV2Port
{
public:
LV2ControlPort(const LilvPort *port,
int index,
bool isInput,
const wxString & symbol,
const wxString & name,
const wxString & group)
: LV2Port(port, index, isInput, symbol, name, group)
{
mMin = 0.0;
mMax = 0.0;
mDef = 0.0;
mVal = 0.0;
mLst = 0.0;
mTmp = 0.0;
mDmy = 0.0;
mLo = 0.0;
mHi = 0.0;
mHasLo = false;
mHasHi = false;
mToggle = false;
mTrigger = false;
mInteger = false;
mSampleRate = false;
mEnumeration = false;
mLogarithmic = false;
mNotOnGui = false;
mCtrl.button = NULL;
mText = NULL;
};
wxString mUnits;
float mMin;
float mMax;
float mDef;
float mVal;
float mLst;
float mTmp;
float mDmy;
float mLo;
float mHi;
bool mHasLo;
bool mHasHi;
bool mToggle;
bool mTrigger;
bool mInteger;
bool mSampleRate;
bool mEnumeration;
bool mLogarithmic;
bool mNotOnGui;
// ScalePoints
std::vector<double> mScaleValues;
wxArrayString mScaleLabels;
// UI
wxTextCtrl *mText;
union
{
wxButton *button;
wxCheckBox *checkbox;
wxChoice *choice;
LV2EffectMeter *meter;
wxSlider *slider;
} mCtrl;
};
using LV2ControlPortPtr = std::shared_ptr<LV2ControlPort>;
using LV2ControlPortArray = std::vector<LV2ControlPortPtr>;
class LV2EffectSettingsDialog;
class LV2Wrapper;
using URIDMap = std::vector<MallocString<>>;
class LV2Effect final : public wxEvtHandler,
public EffectClientInterface,
public EffectUIClientInterface
{
public:
LV2Effect(const LilvPlugin *plug);
virtual ~LV2Effect();
// ComponentInterface implementation
PluginPath GetPath() override;
ComponentInterfaceSymbol GetSymbol() override;
VendorSymbol GetVendor() override;
wxString GetVersion() override;
TranslatableString GetDescription() override;
// EffectDefinitionInterface implementation
EffectType GetType() override;
EffectFamilySymbol GetFamily() override;
bool IsInteractive() override;
bool IsDefault() override;
bool IsLegacy() override;
bool SupportsRealtime() override;
bool SupportsAutomation() override;
// EffectClientInterface implementation
bool SetHost(EffectHostInterface *host) override;
unsigned GetAudioInCount() override;
unsigned GetAudioOutCount() override;
int GetMidiInCount() override;
int GetMidiOutCount() override;
void SetSampleRate(double rate) override;
size_t SetBlockSize(size_t maxBlockSize) override;
size_t GetBlockSize() const override;
sampleCount GetLatency() override;
size_t GetTailSize() override;
bool IsReady() override;
bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL) override;
bool ProcessFinalize() override;
size_t ProcessBlock(float **inbuf, float **outbuf, size_t size) override;
bool RealtimeInitialize() override;
bool RealtimeAddProcessor(unsigned numChannels, float sampleRate) override;
bool RealtimeFinalize() override;
bool RealtimeSuspend() override;
bool RealtimeResume() override;
bool RealtimeProcessStart() override;
size_t RealtimeProcess(int group, float **inbuf, float **outbuf, size_t numSamples) override;
bool RealtimeProcessEnd() override;
bool ShowInterface(wxWindow *parent, bool forceModal = false) override;
bool GetAutomationParameters(CommandParameters & parms) override;
bool SetAutomationParameters(CommandParameters & parms) override;
// EffectUIClientInterface implementation
void SetHostUI(EffectUIHostInterface *host) override;
bool PopulateUI(wxWindow *parent) override;
bool IsGraphicalUI() override;
bool ValidateUI() override;
bool HideUI() override;
bool CloseUI() override;
bool LoadUserPreset(const RegistryPath & name) override;
bool SaveUserPreset(const RegistryPath & name) override;
RegistryPaths GetFactoryPresets() override;
bool LoadFactoryPreset(int id) override;
bool LoadFactoryDefaults() override;
bool CanExportPresets() override;
void ExportPresets() override;
void ImportPresets() override;
bool HasOptions() override;
void ShowOptions() override;
// LV2Effect implementation
private:
bool LoadParameters(const RegistryPath & group);
bool SaveParameters(const RegistryPath & group);
LV2Wrapper *InitInstance(float sampleRate);
void FreeInstance(LV2Wrapper *wrapper);
static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data,
const char *map,
const char *uri);
static LV2_URID urid_map(LV2_URID_Map_Handle handle, const char *uri);
LV2_URID URID_Map(const char *uri);
static LV2_URID Lookup_URI(URIDMap & map, const char *uri, bool add = true);
static const char *urid_unmap(LV2_URID_Unmap_Handle handle, LV2_URID urid);
const char *URID_Unmap(LV2_URID urid);
static int ui_resize(LV2UI_Feature_Handle handle, int width, int height);
int UIResize(int width, int height);
static void ui_closed(LV2UI_Controller controller);
void UIClosed();
static int log_printf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, ...);
static int log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list ap);
int LogVPrintf(LV2_URID type, const char *fmt, va_list ap);
#if defined(__WXGTK__)
static void size_request(GtkWidget *widget, GtkRequisition *requisition, LV2Effect *win);
void SizeRequest(GtkWidget *widget, GtkRequisition *requisition);
#endif
size_t AddOption(LV2_URID, uint32_t size, LV2_URID, const void *value);
bool ValidateOptions(const LilvNode *subject);
bool CheckOptions(const LilvNode *subject, const LilvNode *predicate, bool required);
LV2_Feature *AddFeature(const char *uri, void *data);
bool ValidateFeatures(const LilvNode *subject);
bool CheckFeatures(const LilvNode *subject, const LilvNode *predicate, bool required);
bool BuildFancy();
bool BuildPlain();
bool TransferDataToWindow() /* not override */;
bool TransferDataFromWindow() /* not override */;
void SetSlider(const LV2ControlPortPtr & port);
void OnTrigger(wxCommandEvent & evt);
void OnToggle(wxCommandEvent & evt);
void OnChoice(wxCommandEvent & evt);
void OnText(wxCommandEvent & evt);
void OnSlider(wxCommandEvent & evt);
void OnTimer(wxTimerEvent & evt);
void OnIdle(wxIdleEvent & evt);
void OnSize(wxSizeEvent & evt);
void OnSizeWindow(wxCommandEvent & evt);
static void suil_port_write_func(SuilController controller,
uint32_t port_index,
uint32_t buffer_size,
uint32_t protocol,
const void *buffer);
void SuilPortWrite(uint32_t port_index,
uint32_t buffer_size,
uint32_t protocol,
const void *buffer);
static uint32_t suil_port_index_func(SuilController controller,
const char *port_symbol);
uint32_t SuilPortIndex(const char *port_symbol);
static const void *get_value_func(const char *port_symbol,
void *user_data,
uint32_t *size,
uint32_t *type);
const void *GetPortValue(const char *port_symbol,
uint32_t *size,
uint32_t *type);
static void set_value_func(const char *port_symbol,
void *user_data,
const void *value,
uint32_t size,
uint32_t type);
void SetPortValue(const char *port_symbol,
const void *value,
uint32_t size,
uint32_t type);
private:
// Declare the global and local URI maps
static URIDMap gURIDMap;
URIDMap mURIDMap;
// Declare the static LILV URI nodes
#undef NODE
#define NODE(n, u) static LilvNode *node_##n;
NODELIST
// Declare the static URIDs
#undef URID
#define URID(n, u) static LV2_URID urid_##n;
URIDLIST
const LilvPlugin *mPlug;
EffectHostInterface *mHost;
float mSampleRate;
int mBlockSize;
int mSeqSize;
int mMinBlockSize;
int mMaxBlockSize;
int mUserBlockSize;
std::unordered_map<uint32_t, LV2ControlPortPtr> mControlPortMap;
LV2ControlPortArray mControlPorts;
LV2AudioPortArray mAudioPorts;
unsigned mAudioIn;
unsigned mAudioOut;
LV2AtomPortArray mAtomPorts;
LV2AtomPortPtr mControlIn;
LV2AtomPortPtr mControlOut;
unsigned mMidiIn;
unsigned mMidiOut;
LV2CVPortArray mCVPorts;
unsigned mCVIn;
unsigned mCVOut;
std::unordered_map<wxString, std::vector<int>> mGroupMap;
wxArrayString mGroups;
bool mWantsOptionsInterface;
bool mWantsStateInterface;
bool mWantsWorkerInterface;
bool mNoResize;
bool mUseLatency;
int mLatencyPort;
bool mLatencyDone;
bool mRolling;
bool mActivated;
LV2Wrapper *mMaster;
LV2Wrapper *mProcess;
std::vector<LV2Wrapper *> mSlaves;
FloatBuffers mMasterIn, mMasterOut;
size_t mNumSamples;
size_t mFramePos;
FloatBuffers mCVInBuffers;
FloatBuffers mCVOutBuffers;
// Position info
float mPositionSpeed;
float mPositionFrame;
double mLength;
wxTimer mTimer;
wxDialog *mDialog;
wxWindow *mParent;
EffectUIHostInterface *mUIHost;
bool mUseGUI;
// Features we support
LV2_URI_Map_Feature mUriMapFeature;
LV2_URID_Map mURIDMapFeature;
LV2_URID_Unmap mURIDUnmapFeature;
LV2UI_Resize mUIResizeFeature;
LV2_Log_Log mLogFeature;
LV2_Extension_Data_Feature mExtensionDataFeature;
LV2_External_UI_Host mExternalUIHost;
LV2_External_UI_Widget* mExternalWidget;
bool mExternalUIClosed;
LV2_Atom_Forge mForge;
std::vector<LV2_Options_Option> mOptions;
size_t mBlockSizeOption;
size_t mSampleRateOption;
bool mSupportsNominalBlockLength;
bool mSupportsSampleRate;
std::vector<std::unique_ptr<LV2_Feature>> mFeatures;
LV2_Feature *mInstanceAccessFeature;
LV2_Feature *mParentFeature;
LV2_Feature *mWorkerScheduleFeature;
bool mFreewheeling;
SuilHost *mSuilHost;
SuilInstance *mSuilInstance;
NativeWindow *mNativeWin;
wxSize mNativeWinInitialSize;
wxSize mNativeWinLastSize;
bool mResizing;
#if defined(__WXGTK__)
bool mResized;
#endif
LV2UI_Idle_Interface *mUIIdleInterface;
LV2UI_Show_Interface *mUIShowInterface;
NumericTextCtrl *mDuration;
bool mFactoryPresetsLoaded;
RegistryPaths mFactoryPresetNames;
wxArrayString mFactoryPresetUris;
DECLARE_EVENT_TABLE()
friend class LV2Wrapper;
friend class LV2EffectSettingsDialog;
friend class LV2EffectsModule;
};
inline wxString LilvString(const LilvNode *node)
{
return wxString::FromUTF8(lilv_node_as_string(node));
};
inline wxString LilvString(LilvNode *node, bool free)
{
wxString str = LilvString(node);
if (free)
{
lilv_node_free(node);
}
return str;
};
class LV2Wrapper : public wxThreadHelper
{
public:
typedef struct LV2Work
{
uint32_t size;
const void *data;
} LV2Work;
public:
LV2Wrapper(LV2Effect *effect);
virtual ~LV2Wrapper();
LilvInstance *Instantiate(const LilvPlugin *plugin,
double sampleRrate,
std::vector<std::unique_ptr<LV2_Feature>> & features);
void *Entry();
LilvInstance *GetInstance();
LV2_Handle GetHandle();
float GetLatency();
void SetFreeWheeling(bool enable);
void SetSampleRate();
void SetBlockSize();
void ConnectPorts(float **inbuf, float **outbuf);
void SendResponses();
static LV2_Worker_Status schedule_work(LV2_Worker_Schedule_Handle handle,
uint32_t size,
const void *data);
LV2_Worker_Status ScheduleWork(uint32_t size, const void *data);
static LV2_Worker_Status respond(LV2_Worker_Respond_Handle handle,
uint32_t size,
const void *data);
LV2_Worker_Status Respond(uint32_t size, const void *data);
private:
LV2Effect *mEffect;
LilvInstance *mInstance;
LV2_Handle mHandle;
wxMessageQueue<LV2Work> mRequests;
wxMessageQueue<LV2Work> mResponses;
// Options extension
LV2_Options_Interface *mOptionsInterface;
// State extension
LV2_State_Interface *mStateInterface;
// Worker extension
LV2_Worker_Interface *mWorkerInterface;
LV2_Worker_Schedule mWorkerSchedule;
float mLatency;
bool mFreeWheeling;
bool mStopWorker;
};
#endif