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:
Johannes Lorenz
2020-05-24 12:50:50 +02:00
parent 7aef23d209
commit 2a66e83f53
39 changed files with 3536 additions and 3 deletions

View File

@@ -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
View 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
View 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
View 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
View 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
View 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

View 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
View 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