Lv2 core implementation
Implementation of the Lv2 core, except for CV ports. No features or extensions are supported yet. You can now generate sound using Lv2 instruments (restricted to non-piano) or effects. For an explenation about the new classes, see Lv2Manager.h
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include <QtCore/QObject>
|
||||
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
#include "lmms_export.h"
|
||||
#include "lmms_basics.h"
|
||||
|
||||
@@ -87,6 +88,13 @@ public:
|
||||
return s_projectJournal;
|
||||
}
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
static class Lv2Manager * getLv2Manager()
|
||||
{
|
||||
return s_lv2Manager;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Ladspa2LMMS * getLADSPAManager()
|
||||
{
|
||||
return s_ladspaManager;
|
||||
@@ -143,6 +151,9 @@ private:
|
||||
static ProjectJournal * s_projectJournal;
|
||||
static DummyTrackContainer * s_dummyTC;
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
static class Lv2Manager* s_lv2Manager;
|
||||
#endif
|
||||
static Ladspa2LMMS * s_ladspaManager;
|
||||
static void* s_dndPluginKey;
|
||||
|
||||
|
||||
67
include/Lv2Basics.h
Normal file
67
include/Lv2Basics.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Lv2Basics.h - basic Lv2 utils
|
||||
*
|
||||
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LV2BASICS_H
|
||||
#define LV2BASICS_H
|
||||
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
#include <memory>
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
struct LilvNodeDeleter
|
||||
{
|
||||
void operator()(LilvNode* n) { lilv_node_free(n); }
|
||||
};
|
||||
|
||||
struct LilvNodesDeleter
|
||||
{
|
||||
void operator()(LilvNodes* n) { lilv_nodes_free(n); }
|
||||
};
|
||||
|
||||
using AutoLilvNode = std::unique_ptr<LilvNode, LilvNodeDeleter>;
|
||||
using AutoLilvNodes = std::unique_ptr<LilvNodes, LilvNodesDeleter>;
|
||||
|
||||
/**
|
||||
Return QString from a plugin's node, everything will be freed automatically
|
||||
@param plug The plugin where the node is
|
||||
@param getFunc The function to return the node from the plugin
|
||||
*/
|
||||
QString qStringFromPluginNode(const LilvPlugin* plug,
|
||||
LilvNode * (*getFunc)(const LilvPlugin*));
|
||||
|
||||
//! Return port name as QString, everything will be freed automatically
|
||||
QString qStringFromPortName(const LilvPlugin* plug, const LilvPort* port);
|
||||
|
||||
//! Return port name as std::string, everything will be freed automatically
|
||||
std::string stdStringFromPortName(const LilvPlugin* plug, const LilvPort* port);
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
#endif // LV2BASICS_H
|
||||
146
include/Lv2ControlBase.h
Normal file
146
include/Lv2ControlBase.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Lv2ControlBase.h - Lv2 control base class
|
||||
*
|
||||
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV2_CONTROL_BASE_H
|
||||
#define LV2_CONTROL_BASE_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
|
||||
#include "DataFile.h"
|
||||
#include "LinkedModelGroups.h"
|
||||
#include "Plugin.h"
|
||||
|
||||
class Lv2Proc;
|
||||
class PluginIssue;
|
||||
|
||||
/**
|
||||
Common base class for Lv2 plugins
|
||||
|
||||
This class contains a vector of Lv2Proc, usually 1 (for stereo plugins) or
|
||||
2 (for mono plugins). Most of the logic is done there, this class primarily
|
||||
forwards work to the Lv2Proc and collects the results.
|
||||
|
||||
This class provides everything Lv2 plugins have in common. It's not
|
||||
named Lv2Plugin, because
|
||||
* it does not inherit Instrument
|
||||
* the Plugin subclass Effect does not inherit this class
|
||||
|
||||
This class would usually be a Model subclass. However, Qt doesn't allow
|
||||
this:
|
||||
* inhertiting only from Model will cause diamond inheritance for QObject,
|
||||
which will cause errors with Q_OBJECT
|
||||
* making this a direct subclass of Instrument resp. EffectControls would
|
||||
require CRTP, which would make this class a template class, which would
|
||||
conflict with Q_OBJECT
|
||||
|
||||
The consequence is that this class can neither inherit QObject or Model, nor
|
||||
Instrument or EffectControls, which means in fact:
|
||||
* this class contains no signals or slots, but it offers stubs for slots
|
||||
that shall be called by child classes
|
||||
* this class can not override virtuals of Instrument or EffectControls, so
|
||||
it will offer functions that must be called by virtuals in its child class
|
||||
*/
|
||||
class Lv2ControlBase : public LinkedModelGroups
|
||||
{
|
||||
public:
|
||||
static Plugin::PluginTypes check(const LilvPlugin* m_plugin,
|
||||
std::vector<PluginIssue> &issues, bool printIssues = false);
|
||||
|
||||
const LilvPlugin* getPlugin() const { return m_plugin; }
|
||||
|
||||
Lv2Proc *control(std::size_t idx) { return m_procs[idx].get(); }
|
||||
const Lv2Proc *control(std::size_t idx) const { return m_procs[idx].get(); }
|
||||
|
||||
bool hasGui() const { return m_hasGUI; }
|
||||
void setHasGui(bool val) { m_hasGUI = val; }
|
||||
|
||||
protected:
|
||||
/*
|
||||
ctor/dtor
|
||||
*/
|
||||
//! @param that the class inheriting this class and inheriting Model;
|
||||
//! this is the same pointer as this, but a different type
|
||||
//! @param uri the Lv2 URI telling this class what plugin to construct
|
||||
Lv2ControlBase(class Model *that, const QString& uri);
|
||||
~Lv2ControlBase() override;
|
||||
//! Must be checked after ctor or reload
|
||||
bool isValid() const { return m_valid; }
|
||||
|
||||
/*
|
||||
overrides
|
||||
*/
|
||||
LinkedModelGroup* getGroup(std::size_t idx) override;
|
||||
const LinkedModelGroup* getGroup(std::size_t idx) const override;
|
||||
|
||||
/*
|
||||
utils for the run thread
|
||||
*/
|
||||
//! Copy values from all connected models into the respective ports
|
||||
void copyModelsFromLmms();
|
||||
//! Copy buffer passed by LMMS into our ports
|
||||
void copyBuffersFromLmms(const sampleFrame *buf, fpp_t frames);
|
||||
//! Copy our ports into buffers passed by LMMS
|
||||
void copyBuffersToLmms(sampleFrame *buf, fpp_t frames) const;
|
||||
//! Run the Lv2 plugin instance for @param frames frames
|
||||
void run(fpp_t frames);
|
||||
|
||||
/*
|
||||
load/save, must be called from virtuals
|
||||
*/
|
||||
void saveSettings(QDomDocument &doc, QDomElement &that);
|
||||
void loadSettings(const QDomElement &that);
|
||||
void loadFile(const QString &file);
|
||||
//! TODO: not implemented
|
||||
void reloadPlugin();
|
||||
|
||||
/*
|
||||
more functions that must be called from virtuals
|
||||
*/
|
||||
std::size_t controlCount() const;
|
||||
QString nodeName() const { return "lv2controls"; }
|
||||
|
||||
private:
|
||||
//! Return the DataFile settings type
|
||||
virtual DataFile::Types settingsType() = 0;
|
||||
//! Inform the plugin about a file name change
|
||||
virtual void setNameFromFile(const QString &fname) = 0;
|
||||
|
||||
//! Independent processors
|
||||
//! If this is a mono effect, the vector will have size 2 in order to
|
||||
//! fulfill LMMS' requirement of having stereo input and output
|
||||
std::vector<std::unique_ptr<Lv2Proc>> m_procs;
|
||||
|
||||
bool m_valid = true;
|
||||
bool m_hasGUI = false;
|
||||
unsigned m_channelsPerProc;
|
||||
|
||||
const LilvPlugin* m_plugin;
|
||||
};
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
#endif // LV2_CONTROL_BASE_H
|
||||
126
include/Lv2Manager.h
Normal file
126
include/Lv2Manager.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Lv2Manager.h - Implementation of Lv2Manager class
|
||||
*
|
||||
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV2MANAGER_H
|
||||
#define LV2MANAGER_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <map>
|
||||
#include <lilv/lilv.h>
|
||||
|
||||
#include "Lv2Basics.h"
|
||||
#include "Plugin.h"
|
||||
|
||||
|
||||
/*
|
||||
all Lv2 classes in relation (use our "4 spaces per tab rule" to view):
|
||||
|
||||
explanation:
|
||||
"x = {y z}" means class "x" consists of classes "y" and "z"
|
||||
(and probably other classes not mentioned)
|
||||
"x = {y*}" means class "x" references/uses class "y"
|
||||
|
||||
core:
|
||||
Lv2Proc = {LilvInstance}
|
||||
Lv2ControlBase = {Lv2Proc, Lv2Proc... (2 for mono, 1 for stereo)}
|
||||
Lv2Manager = {LilvPlugin*, LilvPlugin* ...}
|
||||
(creates Lv2ControlBase, Lv2ControlBase...)
|
||||
|
||||
Lv2FxControls = {Lv2ControlBase}
|
||||
Lv2Effect = {Effect + Lv2FxControls}
|
||||
(takes Lv2SubPluginFeatures in ctor)
|
||||
Lv2Instrument = {Instrument + Lv2ControlBase}
|
||||
(takes Lv2SubPluginFeatures in ctor)
|
||||
|
||||
gui:
|
||||
Lv2ViewProc = {Lv2Proc*}
|
||||
Lv2ViewBase = {Lv2ViewProc, Lv2ViewProc...
|
||||
(2 for mono, 1 for stereo)}
|
||||
Lv2FxControlDialog = {EffectControlDialog + Lv2ViewBase}
|
||||
Lv2InsView = {InstrumentView + Lv2ViewBase}
|
||||
|
||||
Lv2SubPluginFeatures:
|
||||
Lv2SubPluginFeatures = {Lv2Manager*}
|
||||
Lv2Effect::Descriptor = {Lv2SubPluginFeatures}
|
||||
Lv2Instrument::Descriptor = {Lv2SubPluginFeatures}
|
||||
*/
|
||||
|
||||
|
||||
//! Class to keep track of all LV2 plugins
|
||||
class Lv2Manager
|
||||
{
|
||||
public:
|
||||
void initPlugins();
|
||||
|
||||
Lv2Manager();
|
||||
~Lv2Manager();
|
||||
|
||||
|
||||
AutoLilvNode uri(const char* uriStr);
|
||||
|
||||
//! Class representing info for one plugin
|
||||
struct Lv2Info
|
||||
{
|
||||
public:
|
||||
//! use only for std::map internals
|
||||
Lv2Info() : m_plugin(nullptr) {}
|
||||
//! ctor used inside Lv2Manager
|
||||
Lv2Info(const LilvPlugin* plug, Plugin::PluginTypes type, bool valid) :
|
||||
m_plugin(plug), m_type(type), m_valid(valid) {}
|
||||
Lv2Info(Lv2Info&& other) = default;
|
||||
Lv2Info& operator=(Lv2Info&& other) = default;
|
||||
|
||||
const LilvPlugin* plugin() const { return m_plugin; }
|
||||
Plugin::PluginTypes type() const { return m_type; }
|
||||
bool isValid() const { return m_valid; }
|
||||
|
||||
private:
|
||||
const LilvPlugin* m_plugin;
|
||||
Plugin::PluginTypes m_type;
|
||||
bool m_valid = false;
|
||||
};
|
||||
|
||||
//! Return descriptor with URI @p uri or nullptr if none exists
|
||||
const LilvPlugin *getPlugin(const std::string &uri);
|
||||
//! Return descriptor with URI @p uri or nullptr if none exists
|
||||
const LilvPlugin *getPlugin(const QString& uri);
|
||||
|
||||
using Lv2InfoMap = std::map<std::string, Lv2Info>;
|
||||
using Iterator = Lv2InfoMap::iterator;
|
||||
Iterator begin() { return m_lv2InfoMap.begin(); }
|
||||
Iterator end() { return m_lv2InfoMap.end(); }
|
||||
|
||||
private:
|
||||
bool m_debug; //!< if set, debug output will be printed
|
||||
LilvWorld* m_world;
|
||||
Lv2InfoMap m_lv2InfoMap;
|
||||
bool isSubclassOf(const LilvPluginClass *clvss, const char *uriStr);
|
||||
};
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
|
||||
#endif // LV2MANAGER_H
|
||||
237
include/Lv2Ports.h
Normal file
237
include/Lv2Ports.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Lv2Ports.h - Lv2 port classes definitions
|
||||
*
|
||||
* Copyright (c) 2019-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV2PORTS_H
|
||||
#define LV2PORTS_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "lmms_basics.h"
|
||||
#include "PluginIssue.h"
|
||||
|
||||
struct ConnectPortVisitor;
|
||||
|
||||
namespace Lv2Ports {
|
||||
|
||||
/*
|
||||
port structs
|
||||
*/
|
||||
enum class Flow {
|
||||
Unknown,
|
||||
Input,
|
||||
Output
|
||||
};
|
||||
|
||||
enum class Type {
|
||||
Unknown,
|
||||
Control,
|
||||
Audio,
|
||||
Event, //!< TODO: unused, describe
|
||||
Cv //!< TODO: unused, describe
|
||||
};
|
||||
|
||||
//! Port visualization
|
||||
//! @note All Lv2 audio ports are float, this is only the visualisation
|
||||
enum class Vis {
|
||||
None,
|
||||
Integer,
|
||||
Enumeration,
|
||||
Toggled
|
||||
};
|
||||
|
||||
const char* toStr(Lv2Ports::Flow pf);
|
||||
const char* toStr(Lv2Ports::Type pt);
|
||||
const char* toStr(Lv2Ports::Vis pv);
|
||||
|
||||
struct ControlPortBase;
|
||||
struct Control;
|
||||
struct Audio;
|
||||
struct Cv;
|
||||
struct Unknown;
|
||||
|
||||
struct ConstVisitor
|
||||
{
|
||||
virtual void visit(const Lv2Ports::ControlPortBase& ) {}
|
||||
virtual void visit(const Lv2Ports::Control& ) {}
|
||||
virtual void visit(const Lv2Ports::Audio& ) {}
|
||||
virtual void visit(const Lv2Ports::Cv& ) {}
|
||||
virtual void visit(const Lv2Ports::Unknown& ) {}
|
||||
|
||||
virtual ~ConstVisitor();
|
||||
};
|
||||
|
||||
struct Visitor
|
||||
{
|
||||
virtual void visit(Lv2Ports::ControlPortBase& ) {}
|
||||
virtual void visit(Lv2Ports::Control& ) {}
|
||||
virtual void visit(Lv2Ports::Audio& ) {}
|
||||
virtual void visit(Lv2Ports::Cv& ) {}
|
||||
virtual void visit(Lv2Ports::Unknown& ) {}
|
||||
|
||||
virtual ~Visitor();
|
||||
};
|
||||
|
||||
struct Meta
|
||||
{
|
||||
Type m_type = Type::Unknown;
|
||||
Flow m_flow = Flow::Unknown;
|
||||
Vis m_vis = Vis::None;
|
||||
|
||||
float m_def = .0f, m_min = .0f, m_max = .0f;
|
||||
bool m_optional = false;
|
||||
bool m_used = true;
|
||||
|
||||
std::vector<PluginIssue> get(const LilvPlugin* plugin, std::size_t portNum);
|
||||
};
|
||||
|
||||
struct PortBase : public Meta
|
||||
{
|
||||
const LilvPort* m_port = nullptr;
|
||||
const LilvPlugin* m_plugin = nullptr;
|
||||
|
||||
virtual void accept(Visitor& v) = 0;
|
||||
virtual void accept(ConstVisitor& v) const = 0;
|
||||
|
||||
QString name() const;
|
||||
QString uri() const;
|
||||
|
||||
virtual ~PortBase();
|
||||
};
|
||||
|
||||
template<typename Derived, typename Base>
|
||||
struct VisitablePort : public Base
|
||||
{
|
||||
void accept(Visitor& v) override { v.visit(static_cast<Derived&>(*this)); }
|
||||
void accept(ConstVisitor& v) const override { v.visit(static_cast<const Derived&>(*this)); }
|
||||
};
|
||||
|
||||
struct ControlPortBase : public VisitablePort<ControlPortBase, PortBase>
|
||||
{
|
||||
//! LMMS models
|
||||
//! Always up-to-date, except during runs
|
||||
std::unique_ptr<class AutomatableModel> m_connectedModel;
|
||||
|
||||
//! Enumerate float values
|
||||
//! lv2 defines scale points as
|
||||
//! "single float Points (for control inputs)"
|
||||
std::vector<float> m_scalePointMap;
|
||||
};
|
||||
|
||||
struct Control : public VisitablePort<Control, ControlPortBase>
|
||||
{
|
||||
//! Data location which Lv2 plugins see
|
||||
//! Model values are being copied here every run
|
||||
//! Between runs, this data is not up-to-date
|
||||
float m_val;
|
||||
};
|
||||
|
||||
struct Cv : public VisitablePort<Cv, ControlPortBase>
|
||||
{
|
||||
//! Data location which Lv2 plugins see
|
||||
//! Model values are being copied here every run
|
||||
//! Between runs, this data is not up-to-date
|
||||
std::vector<float> m_buffer;
|
||||
};
|
||||
|
||||
struct Audio : public VisitablePort<Audio, PortBase>
|
||||
{
|
||||
Audio(std::size_t bufferSize, bool isSidechain, bool isOptional);
|
||||
|
||||
//! Copy buffer passed by LMMS into our ports
|
||||
//! @param channel channel index into each sample frame
|
||||
void copyBuffersFromCore(const sampleFrame *lmmsBuf,
|
||||
unsigned channel, fpp_t frames);
|
||||
//! Add buffer passed by LMMS into our ports, and halve the result
|
||||
//! @param channel channel index into each sample frame
|
||||
void averageWithBuffersFromCore(const sampleFrame *lmmsBuf,
|
||||
unsigned channel, fpp_t frames);
|
||||
//! Copy our ports into buffers passed by LMMS
|
||||
//! @param channel channel index into each sample frame
|
||||
void copyBuffersToCore(sampleFrame *lmmsBuf,
|
||||
unsigned channel, fpp_t frames) const;
|
||||
|
||||
bool isSideChain() const { return m_sidechain; }
|
||||
bool isOptional() const { return m_optional; }
|
||||
bool mustBeUsed() const { return !isSideChain() && !isOptional(); }
|
||||
std::size_t bufferSize() const { return m_buffer.size(); }
|
||||
|
||||
private:
|
||||
//! the buffer where Lv2 reads/writes the data from/to
|
||||
std::vector<float> m_buffer;
|
||||
bool m_sidechain;
|
||||
bool m_optional;
|
||||
|
||||
// the only case when data of m_buffer may be referenced:
|
||||
friend struct ::ConnectPortVisitor;
|
||||
};
|
||||
|
||||
struct Unknown : public VisitablePort<Unknown, PortBase>
|
||||
{
|
||||
};
|
||||
|
||||
/*
|
||||
port casts
|
||||
*/
|
||||
template<class Target>
|
||||
struct DCastVisitor : public Visitor
|
||||
{
|
||||
Target* m_result = nullptr;
|
||||
void visit(Target& tar) { m_result = &tar; }
|
||||
};
|
||||
|
||||
template<class Target>
|
||||
struct ConstDCastVisitor : public ConstVisitor
|
||||
{
|
||||
const Target* m_result = nullptr;
|
||||
void visit(const Target& tar) { m_result = &tar; }
|
||||
};
|
||||
|
||||
//! If you don't want to use a whole visitor, you can use dcast
|
||||
template<class Target>
|
||||
Target* dcast(PortBase* base)
|
||||
{
|
||||
DCastVisitor<Target> vis;
|
||||
base->accept(vis);
|
||||
return vis.m_result;
|
||||
}
|
||||
|
||||
//! const overload
|
||||
template<class Target>
|
||||
const Target* dcast(const PortBase* base)
|
||||
{
|
||||
ConstDCastVisitor<Target> vis;
|
||||
base->accept(vis);
|
||||
return vis.m_result;
|
||||
}
|
||||
|
||||
} // namespace Lv2Ports
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
#endif // LV2PORTS_H
|
||||
183
include/Lv2Proc.h
Normal file
183
include/Lv2Proc.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Lv2Proc.h - Lv2 processor class
|
||||
*
|
||||
* Copyright (c) 2019-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV2PROC_H
|
||||
#define LV2PROC_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
#include <memory>
|
||||
#include <QObject>
|
||||
|
||||
#include "Lv2Basics.h"
|
||||
#include "LinkedModelGroups.h"
|
||||
#include "Plugin.h"
|
||||
#include "PluginIssue.h"
|
||||
|
||||
|
||||
// forward declare port structs/enums
|
||||
namespace Lv2Ports
|
||||
{
|
||||
struct Audio;
|
||||
struct PortBase;
|
||||
|
||||
enum class Type;
|
||||
enum class Flow;
|
||||
enum class Vis;
|
||||
}
|
||||
|
||||
|
||||
//! Class representing one Lv2 processor, i.e. one Lv2 handle
|
||||
//! For Mono effects, 1 Lv2ControlBase references 2 Lv2Proc
|
||||
class Lv2Proc : public LinkedModelGroup
|
||||
{
|
||||
public:
|
||||
static Plugin::PluginTypes check(const LilvPlugin* plugin,
|
||||
std::vector<PluginIssue> &issues, bool printIssues = false);
|
||||
|
||||
/*
|
||||
ctor/dtor
|
||||
*/
|
||||
Lv2Proc(const LilvPlugin* plugin, Model *parent);
|
||||
~Lv2Proc() override;
|
||||
//! Must be checked after ctor or reload
|
||||
bool isValid() const { return m_valid; }
|
||||
|
||||
/*
|
||||
port access
|
||||
*/
|
||||
struct StereoPortRef
|
||||
{
|
||||
//! mono port or left port in case of stereo
|
||||
Lv2Ports::Audio* m_left = nullptr;
|
||||
//! unused, or right port in case of stereo
|
||||
Lv2Ports::Audio* m_right = nullptr;
|
||||
};
|
||||
|
||||
StereoPortRef& inPorts() { return m_inPorts; }
|
||||
const StereoPortRef& inPorts() const { return m_inPorts; }
|
||||
StereoPortRef& outPorts() { return m_outPorts; }
|
||||
const StereoPortRef& outPorts() const { return m_outPorts; }
|
||||
template<class Functor>
|
||||
void foreach_port(const Functor& ftor)
|
||||
{
|
||||
for (std::unique_ptr<Lv2Ports::PortBase>& port : m_ports)
|
||||
{
|
||||
ftor(port.get());
|
||||
}
|
||||
}
|
||||
template<class Functor>
|
||||
void foreach_port(const Functor& ftor) const
|
||||
{
|
||||
for (const std::unique_ptr<Lv2Ports::PortBase>& port : m_ports)
|
||||
{
|
||||
ftor(port.get());
|
||||
}
|
||||
}
|
||||
|
||||
//! Debug function to print ports to stdout
|
||||
void dumpPorts();
|
||||
|
||||
/*
|
||||
utils for the run thread
|
||||
*/
|
||||
//! Copy values from all connected models into the respective ports
|
||||
void copyModelsFromCore();
|
||||
/**
|
||||
* Copy buffer passed by the core into our ports
|
||||
* @param buf buffer of sample frames, each sample frame is something like
|
||||
* a `float[<number-of-procs> * <channels per proc>]` array.
|
||||
* @param firstChan The offset for @p buf where we have to read our
|
||||
* first channel.
|
||||
* This marks the first sample in each sample frame where we read from.
|
||||
* If we are the 2nd of 2 mono procs, this can be greater than 0.
|
||||
* @param num Number of channels we must read from @param buf (starting at
|
||||
* @p offset)
|
||||
*/
|
||||
void copyBuffersFromCore(const sampleFrame *buf,
|
||||
unsigned firstChan, unsigned num, fpp_t frames);
|
||||
/**
|
||||
* Copy our ports into buffers passed by the core
|
||||
* @param buf buffer of sample frames, each sample frame is something like
|
||||
* a `float[<number-of-procs> * <channels per proc>]` array.
|
||||
* @param firstChan The offset for @p buf where we have to write our
|
||||
* first channel.
|
||||
* This marks the first sample in each sample frame where we write to.
|
||||
* If we are the 2nd of 2 mono procs, this can be greater than 0.
|
||||
* @param num Number of channels we must write to @param buf (starting at
|
||||
* @p offset)
|
||||
*/
|
||||
void copyBuffersToCore(sampleFrame *buf, unsigned firstChan, unsigned num,
|
||||
fpp_t frames) const;
|
||||
//! Run the Lv2 plugin instance for @param frames frames
|
||||
void run(fpp_t frames);
|
||||
|
||||
/*
|
||||
misc
|
||||
*/
|
||||
class AutomatableModel *modelAtPort(const QString &uri); // unused currently
|
||||
std::size_t controlCount() const { return LinkedModelGroup::modelNum(); }
|
||||
|
||||
protected:
|
||||
/*
|
||||
load and save
|
||||
*/
|
||||
//! Create ports and instance, connect ports, activate plugin
|
||||
void initPlugin();
|
||||
//! Deactivate instance
|
||||
void shutdownPlugin();
|
||||
|
||||
private:
|
||||
bool m_valid = true;
|
||||
|
||||
const LilvPlugin* m_plugin;
|
||||
LilvInstance* m_instance;
|
||||
|
||||
std::vector<std::unique_ptr<Lv2Ports::PortBase>> m_ports;
|
||||
StereoPortRef m_inPorts, m_outPorts;
|
||||
|
||||
//! models for the controls, sorted by port symbols
|
||||
std::map<std::string, AutomatableModel *> m_connectedModels;
|
||||
|
||||
//! load a file in the plugin, but don't do anything in LMMS
|
||||
void loadFileInternal(const QString &file);
|
||||
//! allocate m_ports, fill all with metadata, and assign meaning of ports
|
||||
void createPorts();
|
||||
//! fill m_ports[portNum] with metadata
|
||||
void createPort(std::size_t portNum);
|
||||
//! connect m_ports[portNum] with Lv2
|
||||
void connectPort(std::size_t num);
|
||||
|
||||
void dumpPort(std::size_t num);
|
||||
|
||||
static bool portIsSideChain(const LilvPlugin* plugin, const LilvPort *port);
|
||||
static bool portIsOptional(const LilvPlugin* plugin, const LilvPort *port);
|
||||
static AutoLilvNode uri(const char* uriStr);
|
||||
};
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
#endif // LV2PROC_H
|
||||
61
include/Lv2SubPluginFeatures.h
Normal file
61
include/Lv2SubPluginFeatures.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Lv2SubPluginFeatures.h - derivation from
|
||||
* Plugin::Descriptor::SubPluginFeatures for
|
||||
* hosting LV2 plugins
|
||||
*
|
||||
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV2_SUBPLUGIN_FEATURES_H
|
||||
#define LV2_SUBPLUGIN_FEATURES_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
|
||||
#include "Plugin.h"
|
||||
|
||||
class Lv2SubPluginFeatures : public Plugin::Descriptor::SubPluginFeatures
|
||||
{
|
||||
private:
|
||||
static const LilvPlugin *getPlugin(const Key &k);
|
||||
static QString pluginName(const LilvPlugin *plug);
|
||||
|
||||
public:
|
||||
Lv2SubPluginFeatures(Plugin::PluginTypes type);
|
||||
|
||||
void fillDescriptionWidget(
|
||||
QWidget *parent, const Key *k) const override;
|
||||
|
||||
QString additionalFileExtensions(const Key &k) const override;
|
||||
QString displayName(const Key &k) const override;
|
||||
QString description(const Key &k) const override;
|
||||
const PixmapLoader *logo(const Key &k) const override;
|
||||
|
||||
void listSubPluginKeys(
|
||||
const Plugin::Descriptor *desc, KeyList &kl) const override;
|
||||
};
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
|
||||
#endif
|
||||
97
include/Lv2ViewBase.h
Normal file
97
include/Lv2ViewBase.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Lv2ViewBase.h - base class for Lv2 plugin views
|
||||
*
|
||||
* Copyright (c) 2018-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV2VIEWBASE_H
|
||||
#define LV2VIEWBASE_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "LinkedModelGroupViews.h"
|
||||
#include "Lv2Basics.h"
|
||||
|
||||
class Lv2Proc;
|
||||
class Lv2ControlBase;
|
||||
|
||||
|
||||
//! View for one processor, Lv2ViewBase contains 2 of those for mono plugins
|
||||
class Lv2ViewProc : public LinkedModelGroupView
|
||||
{
|
||||
public:
|
||||
//! @param colNum numbers of columns for the controls
|
||||
Lv2ViewProc(QWidget *parent, Lv2Proc *ctrlBase, int colNum);
|
||||
~Lv2ViewProc();
|
||||
|
||||
private:
|
||||
static AutoLilvNode uri(const char *uriStr);
|
||||
};
|
||||
|
||||
|
||||
//! Base class for view for one Lv2 plugin
|
||||
class Lv2ViewBase : public LinkedModelGroupsView
|
||||
{
|
||||
protected:
|
||||
//! @param pluginWidget A child class which inherits QWidget
|
||||
Lv2ViewBase(class QWidget *pluginWidget, Lv2ControlBase *ctrlBase);
|
||||
~Lv2ViewBase();
|
||||
|
||||
// these widgets must be connected by child widgets
|
||||
class QPushButton *m_reloadPluginButton = nullptr;
|
||||
class QPushButton *m_toggleUIButton = nullptr;
|
||||
class QPushButton *m_helpButton = nullptr;
|
||||
|
||||
void toggleUI();
|
||||
void toggleHelp(bool visible);
|
||||
|
||||
// to be called by child virtuals
|
||||
//! Reconnect models if model changed
|
||||
void modelChanged(Lv2ControlBase* ctrlBase);
|
||||
|
||||
private:
|
||||
enum Rows
|
||||
{
|
||||
ButtonRow,
|
||||
ProcRow,
|
||||
LinkChannelsRow
|
||||
};
|
||||
|
||||
static AutoLilvNode uri(const char *uriStr);
|
||||
LinkedModelGroupView* getGroupView() override { return m_procView; }
|
||||
|
||||
Lv2ViewProc* m_procView;
|
||||
|
||||
//! Numbers of controls per row; must be multiple of 2 for mono effects
|
||||
const int m_colNum = 6;
|
||||
class QMdiSubWindow* m_helpWindow = nullptr;
|
||||
class LedCheckBox *m_multiChannelLink;
|
||||
};
|
||||
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
#endif // LV2VIEWBASE_H
|
||||
Reference in New Issue
Block a user