Skip to content

Commit

Permalink
Refactor supported Lv2 features
Browse files Browse the repository at this point in the history
... from multiple places in Lv2Proc into Lv2Manager.
  • Loading branch information
JohannesLorenz committed Jul 31, 2020
1 parent 2f7d0b5 commit 1cfa713
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 11 deletions.
81 changes: 81 additions & 0 deletions include/Lv2Features.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Lv2Features.h - Lv2Features class
*
* Copyright (c) 2020-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 LV2FEATURES_H
#define LV2FEATURES_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <lv2.h>
#include <map>
#include <vector>
#include "Lv2Manager.h"

/**
Feature container
References all available features for a plugin and maps them to their URIs.
The public member functions should be called in descending order:
1. initCommon: map plugin-common features
2. operator[]: map plugin-specific features
3. createFeatureVectors: create the feature vectors required for
lilv_plugin_instantiate
4. access the latter
*/
class Lv2Features
{
public:
//! Return if a feature is supported by LMMS
static bool isFeatureSupported(const char *featName);

Lv2Features();

//! Register only plugin-common features
void initCommon();
//! Return reference to feature data with given URI featName
void*& operator[](const char* featName);
//! Fill m_features and m_featurePointers with all features
void createFeatureVectors();
//! Return LV2_Feature pointer vector, suited for lilv_plugin_instantiate
const std::vector<const LV2_Feature*>& featurePointers() const
{
return m_featurePointers;
}

private:
//! feature storage
std::vector<LV2_Feature> m_features;
//! pointers to m_features, required for lilv_plugin_instantiate
std::vector<const LV2_Feature*> m_featurePointers;
//! features + data, ordered by URI
std::map<const char*, void*, Lv2Manager::CmpStr> m_featureByUri;
};

#endif // LMMS_HAVE_LV2

#endif // LV2FEATURES_H
19 changes: 19 additions & 0 deletions include/Lv2Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#ifdef LMMS_HAVE_LV2

#include <map>
#include <set>
#include <lilv/lilv.h>

#include "Lv2Basics.h"
Expand Down Expand Up @@ -115,13 +116,31 @@ class Lv2Manager
Iterator begin() { return m_lv2InfoMap.begin(); }
Iterator end() { return m_lv2InfoMap.end(); }

//! strcmp based key comparator for std::set and std::map
struct CmpStr
{
bool operator()(char const *a, char const *b) const;
};

UridMap& uridMap() { return m_uridMap; }
//! Return all
const std::set<const char*, CmpStr>& supportedFeatureURIs() const
{
return m_supportedFeatureURIs;
}
bool isFeatureSupported(const char* featName) const;

private:
// general data
bool m_debug; //!< if set, debug output will be printed
LilvWorld* m_world;
Lv2InfoMap m_lv2InfoMap;
std::set<const char*, CmpStr> m_supportedFeatureURIs;

// feature data that are common for all Lv2Proc
UridMap m_uridMap;

// functions
bool isSubclassOf(const LilvPluginClass *clvss, const char *uriStr);
};

Expand Down
5 changes: 4 additions & 1 deletion include/Lv2Proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <QObject>

#include "Lv2Basics.h"
#include "Lv2Features.h"
#include "LinkedModelGroups.h"
#include "Plugin.h"
#include "PluginIssue.h"
Expand Down Expand Up @@ -156,14 +157,16 @@ class Lv2Proc : public LinkedModelGroup

const LilvPlugin* m_plugin;
LilvInstance* m_instance;
std::vector<LV2_Feature*> m_features;
Lv2Features m_features;

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;

void initPluginSpecificFeatures();

//! 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
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ set(LMMS_SRCS

core/lv2/Lv2Basics.cpp
core/lv2/Lv2ControlBase.cpp
core/lv2/Lv2Features.cpp
core/lv2/Lv2Ports.cpp
core/lv2/Lv2Proc.cpp
core/lv2/Lv2Manager.cpp
Expand Down
95 changes: 95 additions & 0 deletions src/core/lv2/Lv2Features.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Lv2Features.cpp - Lv2Features implementation
*
* Copyright (c) 2020-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.
*
*/

#include "Lv2Features.h"

#ifdef LMMS_HAVE_LV2

#include "Engine.h"
#include "Lv2Manager.h"


bool Lv2Features::isFeatureSupported(const char* featName)
{
return Engine::getLv2Manager()->isFeatureSupported(featName);
}




Lv2Features::Lv2Features()
{
const Lv2Manager* man = Engine::getLv2Manager();
// create (yet empty) map feature URI -> feature
for(const char* uri : man->supportedFeatureURIs())
{
m_featureByUri.emplace(uri, nullptr);
}
}




void Lv2Features::initCommon()
{
Lv2Manager* man = Engine::getLv2Manager();
// init m_featureByUri with the plugin-common features
operator[](LV2_URID__map) = man->uridMap().mapFeature();
operator[](LV2_URID__unmap) = man->uridMap().unmapFeature();
}




void Lv2Features::createFeatureVectors()
{
// create vector of features
for(std::pair<const char* const, void*>& pr : m_featureByUri)
{
assert(pr.second != nullptr);
m_features.push_back(LV2_Feature { pr.first, pr.second });
}

// create pointer vector (for lilv_plugin_instantiate)
m_featurePointers.reserve(m_features.size() + 1);
for(std::size_t i = 0; i < m_features.size(); ++i)
{
m_featurePointers.push_back(&m_features[i]);
}
m_featurePointers.push_back(nullptr);
}




void *&Lv2Features::operator[](const char *featName)
{
auto itr = m_featureByUri.find(featName);
assert (itr != m_featureByUri.end());
return itr->second;
}


#endif // LMMS_HAVE_LV2

26 changes: 26 additions & 0 deletions src/core/lv2/Lv2Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#ifdef LMMS_HAVE_LV2

#include <cstdlib>
#include <cstring>
#include <lilv/lilv.h>
#include <lv2.h>
#include <QDebug>
Expand All @@ -50,6 +51,9 @@ Lv2Manager::Lv2Manager()

m_world = lilv_world_new();
lilv_world_load_all(m_world);

m_supportedFeatureURIs.insert(LV2_URID__map);
m_supportedFeatureURIs.insert(LV2_URID__unmap);
}


Expand Down Expand Up @@ -133,6 +137,28 @@ void Lv2Manager::initPlugins()



bool Lv2Manager::CmpStr::operator()(const char *a, const char *b) const
{
return std::strcmp(a, b) < 0;
}




bool Lv2Manager::isFeatureSupported(const char *featName) const
{
bool found = false;
for(const char* supportedFeatName : supportedFeatureURIs())
if(!strcmp(featName, supportedFeatName))
{
found = true; break;
}
return found;
}




// unused + untested yet
bool Lv2Manager::isSubclassOf(const LilvPluginClass* clvss, const char* uriStr)
{
Expand Down
30 changes: 20 additions & 10 deletions src/core/lv2/Lv2Proc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "AutomatableModel.h"
#include "ComboBoxModel.h"
#include "Engine.h"
#include "Lv2Features.h"
#include "Lv2Manager.h"
#include "Lv2Ports.h"
#include "Mixer.h"
Expand Down Expand Up @@ -74,11 +75,12 @@ Plugin::PluginTypes Lv2Proc::check(const LilvPlugin *plugin,
AutoLilvNodes reqFeats(lilv_plugin_get_required_features(plugin));
LILV_FOREACH (nodes, itr, reqFeats.get())
{
const char* featName = lilv_node_as_string(
const char* reqFeatName = lilv_node_as_string(
lilv_nodes_get(reqFeats.get(), itr));
if( strcmp(featName, LV2_URID__map)
&& strcmp(featName, LV2_URID__unmap))
issues.emplace_back(featureNotSupported, featName);
if(!Lv2Features::isFeatureSupported(reqFeatName))
{
issues.emplace_back(featureNotSupported, reqFeatName);
}
}

if (printIssues && issues.size())
Expand Down Expand Up @@ -243,15 +245,15 @@ AutomatableModel *Lv2Proc::modelAtPort(const QString &uri)

void Lv2Proc::initPlugin()
{
Lv2Manager* man = Engine::getLv2Manager();
m_features.push_back(new LV2_Feature { LV2_URID__map, man->uridMap().mapFeature() });
m_features.push_back(new LV2_Feature { LV2_URID__unmap, man->uridMap().unmapFeature() });
m_features.push_back(nullptr);
m_features.initCommon();
initPluginSpecificFeatures();
m_features.createFeatureVectors();

createPorts();

m_instance = lilv_plugin_instantiate(m_plugin,
Engine::mixer()->processingSampleRate(),
m_features.data());
m_features.featurePointers().data());

if (m_instance)
{
Expand All @@ -278,8 +280,16 @@ void Lv2Proc::shutdownPlugin()
lilv_instance_deactivate(m_instance);
lilv_instance_free(m_instance);
m_instance = nullptr;
}

for(LV2_Feature* feat : m_features) { delete feat; }



void Lv2Proc::initPluginSpecificFeatures()
{
// nothing yet
// it would look like this:
// m_features[LV2_URID__map] = m_uridMapFeature
}


Expand Down

0 comments on commit 1cfa713

Please sign in to comment.