Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Lv2 Options #5761

Merged
merged 13 commits into from
Dec 7, 2020
2 changes: 2 additions & 0 deletions include/Lv2Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ class Lv2Manager
return m_supportedFeatureURIs;
}
bool isFeatureSupported(const char* featName) const;
AutoLilvNodes findNodes(const LilvNode *subject,
const LilvNode *predicate, const LilvNode *object);

static const std::set<const char*, Lv2Manager::CmpStr>& getPluginBlacklist()
{
Expand Down
104 changes: 104 additions & 0 deletions include/Lv2Options.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Lv2Options.h - Lv2Options 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 LV2OPTIONS_H
#define LV2OPTIONS_H

#include "lmmsconfig.h"

#ifdef LMMS_HAVE_LV2

#include <cstdint>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include <map>
#include <memory>
#include <set>
#include <vector>

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

/**
Option container

References all available options for a plugin and maps them to their URIDs.
This class is used per Lv2 processor (justification in Lv2Proc::initMOptions())

The public member functions should be called in descending order:

1. supportOption: set all supported option URIDs
2. initOption: initialize options with values
3. createOptionVectors: create the option vectors required for
the feature
4. access the latter using feature()
*/
class Lv2Options
{
public:
//! Return if an option is supported by LMMS
static bool isOptionSupported(LV2_URID key);
//! Mark option as supported
static void supportOption(LV2_URID key);

//! Initialize an option
template<typename Opt, typename Arg>
void initOption(Lv2UridCache::Id key, Arg&& value,
LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
std::uint32_t subject = 0)
{
const Lv2UridCache& cache = Engine::getLv2Manager()->uridCache();
initOption(cache[key], sizeof(Opt), cache[Lv2UridCache::IdForType<Opt>::value],
std::make_shared<Opt>(std::forward<Arg>(value)), context, subject);
}
//! Fill m_options and m_optionPointers with all options
void createOptionVectors();
//! Return the feature
const LV2_Options_Option* feature() const
{
return m_options.data();
}

private:
//! Initialize an option internally
void initOption(LV2_URID key,
uint32_t size,
LV2_URID type,
std::shared_ptr<void> value,
LV2_Options_Context context = LV2_OPTIONS_INSTANCE,
uint32_t subject = 0);
//! options that are supported by every processor
static std::set<LV2_URID> s_supportedOptions;
//! options + data, ordered by URID
std::map<LV2_URID, LV2_Options_Option> m_optionByUrid;
//! option storage
std::vector<LV2_Options_Option> m_options;
//! option value storage
std::map<LV2_URID, std::shared_ptr<void>> m_optionValues;
};

#endif // LMMS_HAVE_LV2

#endif // LV2OPTIONS_H
5 changes: 4 additions & 1 deletion include/Lv2Proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include "Lv2Basics.h"
#include "Lv2Features.h"
#include "Lv2Options.h"
#include "LinkedModelGroups.h"
#include "MidiEvent.h"
#include "Plugin.h"
Expand Down Expand Up @@ -168,6 +169,7 @@ class Lv2Proc : public LinkedModelGroup
const LilvPlugin* m_plugin;
LilvInstance* m_instance;
Lv2Features m_features;
Lv2Options m_options;

// full list of ports
std::vector<std::unique_ptr<Lv2Ports::PortBase>> m_ports;
Expand All @@ -187,11 +189,12 @@ class Lv2Proc : public LinkedModelGroup
ringbuffer_reader_t<struct MidiInputEvent> m_midiInputReader;

// other
static std::size_t minimumEvbufSize() { return 1 << 15; /* ardour uses this*/ }
static int32_t defaultEvbufSize() { return 1 << 15; /* ardour uses this*/ }

//! models for the controls, sorted by port symbols
std::map<std::string, AutomatableModel *> m_connectedModels;

void initMOptions(); //!< initialize m_options
void initPluginSpecificFeatures();

//! load a file in the plugin, but don't do anything in LMMS
Expand Down
18 changes: 18 additions & 0 deletions include/Lv2UridCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#ifdef LMMS_HAVE_LV2

#include <QtGlobal>
#include <cstdint>

//! Cached URIDs for fast access (for use in real-time code)
Expand All @@ -37,16 +38,33 @@ class Lv2UridCache
public:
enum class Id //!< ID for m_uridCache array
{
// keep it alphabetically (except "size" at the end)
atom_Float,
atom_Int,
bufsz_minBlockLength,
bufsz_maxBlockLength,
bufsz_nominalBlockLength,
bufsz_sequenceSize,
midi_MidiEvent,
param_sampleRate,
// exception to alphabetic ordering - keep at the end:
size
};

template<typename T>
struct IdForType;

//! Return URID for a cache ID
uint32_t operator[](Id id) const;

Lv2UridCache(class UridMap& mapper);

private:
uint32_t m_cache[static_cast<int>(Id::size)];
};

template<> struct Lv2UridCache::IdForType<float> { static constexpr auto value = Id::atom_Float; };
template<> struct Lv2UridCache::IdForType<std::int32_t> { static constexpr auto value = Id::atom_Int; };

#endif // LMMS_HAVE_LV2
#endif // LV2URIDCACHE_H
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ set(LMMS_SRCS
core/lv2/Lv2Ports.cpp
core/lv2/Lv2Proc.cpp
core/lv2/Lv2Manager.cpp
core/lv2/Lv2Options.cpp
core/lv2/Lv2SubPluginFeatures.cpp
core/lv2/Lv2UridCache.cpp
core/lv2/Lv2UridMap.cpp
Expand Down
22 changes: 22 additions & 0 deletions src/core/lv2/Lv2Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <cstring>
#include <lilv/lilv.h>
#include <lv2.h>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <QDebug>
#include <QDir>
#include <QLibrary>
Expand All @@ -41,6 +42,7 @@
#include "Plugin.h"
#include "PluginFactory.h"
#include "Lv2ControlBase.h"
#include "Lv2Options.h"
#include "PluginIssue.h"


Expand All @@ -67,6 +69,17 @@ Lv2Manager::Lv2Manager() :

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

auto supportOpt = [this](Lv2UridCache::Id id)
{
Lv2Options::supportOption(uridCache()[id]);
};
supportOpt(Lv2UridCache::Id::param_sampleRate);
supportOpt(Lv2UridCache::Id::bufsz_maxBlockLength);
supportOpt(Lv2UridCache::Id::bufsz_minBlockLength);
supportOpt(Lv2UridCache::Id::bufsz_nominalBlockLength);
supportOpt(Lv2UridCache::Id::bufsz_sequenceSize);
}


Expand Down Expand Up @@ -205,6 +218,15 @@ bool Lv2Manager::isFeatureSupported(const char *featName) const



AutoLilvNodes Lv2Manager::findNodes(const LilvNode *subject,
const LilvNode *predicate, const LilvNode *object)
{
return AutoLilvNodes(lilv_world_find_nodes (m_world, subject, predicate, object));
}




// unused + untested yet
bool Lv2Manager::isSubclassOf(const LilvPluginClass* clvss, const char* uriStr)
{
Expand Down
93 changes: 93 additions & 0 deletions src/core/lv2/Lv2Options.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Lv2Options.cpp - Lv2Options 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 "Lv2Options.h"

#ifdef LMMS_HAVE_LV2

#include <QtGlobal>


std::set<LV2_URID> Lv2Options::s_supportedOptions;




bool Lv2Options::isOptionSupported(LV2_URID key)
{
return s_supportedOptions.find(key) != s_supportedOptions.end();
}




void Lv2Options::supportOption(LV2_URID key)
{
const auto result = s_supportedOptions.insert(key);
Q_ASSERT(result.second);
}




void Lv2Options::createOptionVectors()
{
// create vector of options
for(LV2_URID urid : s_supportedOptions)
{
auto itr = m_optionByUrid.find(urid);
Q_ASSERT(itr != m_optionByUrid.end());
m_options.push_back(itr->second);
}
LV2_Options_Option nullOption;
nullOption.key = 0;
nullOption.value = nullptr;
m_options.push_back(nullOption);
}




void Lv2Options::initOption(LV2_URID key, uint32_t size, LV2_URID type,
std::shared_ptr<void> value,
LV2_Options_Context context, uint32_t subject)
{
Q_ASSERT(isOptionSupported(key));

LV2_Options_Option opt;
opt.key = key;
opt.context = context;
opt.subject = subject;
opt.size = size;
opt.type = type;
opt.value = value.get();

const auto optResult = m_optionByUrid.emplace(key, opt);
const auto valResult = m_optionValues.emplace(key, std::move(value));
Q_ASSERT(optResult.second);
Q_ASSERT(valResult.second);
}


#endif // LMMS_HAVE_LV2
Loading