mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
LV2PluginFormat: Extract headless plugin format type
This commit is contained in:
parent
c3a3409c4d
commit
bf4486e2aa
13 changed files with 4934 additions and 4780 deletions
|
|
@ -1,675 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** @cond */
|
||||
|
||||
#include "juce_lv2_config.h"
|
||||
|
||||
#ifdef Bool
|
||||
#undef Bool // previously defined in X11/Xlib.h
|
||||
#endif
|
||||
|
||||
#ifdef verify
|
||||
#undef verify // previously defined in macOS 10.11 SDK
|
||||
#endif
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant",
|
||||
"-Wcast-align",
|
||||
"-Wparentheses",
|
||||
"-Wnullability-extension",
|
||||
"-Wsign-conversion")
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "lilv/lilv/lilv.h"
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/atom/forge.h"
|
||||
#include "lv2/atom/util.h"
|
||||
#include "lv2/buf-size/buf-size.h"
|
||||
#include "lv2/data-access/data-access.h"
|
||||
#include "lv2/dynmanifest/dynmanifest.h"
|
||||
#include "lv2/instance-access/instance-access.h"
|
||||
#include "lv2/log/log.h"
|
||||
#include "lv2/midi/midi.h"
|
||||
#include "lv2/options/options.h"
|
||||
#include "lv2/parameters/parameters.h"
|
||||
#include "lv2/patch/patch.h"
|
||||
#include "lv2/port-groups/port-groups.h"
|
||||
#include "lv2/presets/presets.h"
|
||||
#include "lv2/resize-port/resize-port.h"
|
||||
#include "lv2/state/state.h"
|
||||
#include "lv2/time/time.h"
|
||||
#include "lv2/ui/ui.h"
|
||||
#include "lv2/units/units.h"
|
||||
#include "lv2/worker/worker.h"
|
||||
#include "serd/serd/serd.h"
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
|
||||
namespace juce::lv2_shared
|
||||
{
|
||||
|
||||
class AtomForge
|
||||
{
|
||||
public:
|
||||
explicit AtomForge (LV2_URID_Map m)
|
||||
: map { m },
|
||||
chunk { map.map (map.handle, LV2_ATOM__Chunk) }
|
||||
{
|
||||
lv2_atom_forge_init (&forge, &map);
|
||||
}
|
||||
|
||||
void setBuffer (void* buf, size_t size)
|
||||
{
|
||||
lv2_atom_forge_set_buffer (&forge, static_cast<uint8_t*> (buf), size);
|
||||
}
|
||||
|
||||
LV2_Atom_Forge* get() { return &forge; }
|
||||
const LV2_Atom_Forge* get() const { return &forge; }
|
||||
|
||||
void writeChunk (uint32_t size)
|
||||
{
|
||||
lv2_atom_forge_atom (&forge, size, chunk);
|
||||
}
|
||||
|
||||
private:
|
||||
LV2_URID_Map map;
|
||||
LV2_Atom_Forge forge;
|
||||
const LV2_URID chunk;
|
||||
|
||||
JUCE_LEAK_DETECTOR (AtomForge)
|
||||
};
|
||||
|
||||
template <typename Constructor>
|
||||
struct ScopedFrame
|
||||
{
|
||||
template <typename... Args>
|
||||
explicit ScopedFrame (LV2_Atom_Forge* f, Args&&... args)
|
||||
: forge (f)
|
||||
{
|
||||
Constructor::construct (forge, &frame, std::forward<Args> (args)...);
|
||||
}
|
||||
|
||||
~ScopedFrame() { lv2_atom_forge_pop (forge, &frame); }
|
||||
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
LV2_Atom_Forge* forge = nullptr;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ScopedFrame)
|
||||
JUCE_DECLARE_NON_MOVEABLE (ScopedFrame)
|
||||
JUCE_LEAK_DETECTOR (ScopedFrame)
|
||||
};
|
||||
|
||||
struct SequenceTraits { static constexpr auto construct = lv2_atom_forge_sequence_head; };
|
||||
struct ObjectTraits { static constexpr auto construct = lv2_atom_forge_object; };
|
||||
|
||||
using SequenceFrame = ScopedFrame<SequenceTraits>;
|
||||
using ObjectFrame = ScopedFrame<ObjectTraits>;
|
||||
|
||||
struct NumericAtomParser
|
||||
{
|
||||
explicit NumericAtomParser (LV2_URID_Map mapFeatureIn)
|
||||
: mapFeature (mapFeatureIn) {}
|
||||
|
||||
template <typename T> struct Tag { LV2_URID urid; };
|
||||
|
||||
template <typename Target, typename... Types>
|
||||
static Optional<Target> tryParse (const LV2_Atom&, const void*)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename Target, typename Head, typename... Tail>
|
||||
static Optional<Target> tryParse (const LV2_Atom& atom, const void* data, Tag<Head> head, Tag<Tail>... tail)
|
||||
{
|
||||
if (atom.type == head.urid && atom.size == sizeof (Head))
|
||||
return static_cast<Target> (*reinterpret_cast<const Head*> (data));
|
||||
|
||||
return tryParse<Target> (atom, data, tail...);
|
||||
}
|
||||
|
||||
template <typename Target>
|
||||
Optional<Target> parseNumericAtom (const LV2_Atom* atom, const void* data) const
|
||||
{
|
||||
if (atom == nullptr)
|
||||
return {};
|
||||
|
||||
return tryParse<Target> (*atom,
|
||||
data,
|
||||
Tag<int32_t> { mLV2_ATOM__Bool },
|
||||
Tag<int32_t> { mLV2_ATOM__Int },
|
||||
Tag<int64_t> { mLV2_ATOM__Long },
|
||||
Tag<float> { mLV2_ATOM__Float },
|
||||
Tag<double> { mLV2_ATOM__Double });
|
||||
}
|
||||
|
||||
template <typename Target>
|
||||
Optional<Target> parseNumericAtom (const LV2_Atom* atom) const
|
||||
{
|
||||
return parseNumericAtom<Target> (atom, atom + 1);
|
||||
}
|
||||
|
||||
template <typename Target>
|
||||
Optional<Target> parseNumericOption (const LV2_Options_Option* option) const
|
||||
{
|
||||
if (option != nullptr)
|
||||
{
|
||||
const LV2_Atom atom { option->size, option->type };
|
||||
return parseNumericAtom<Target> (&atom, option->value);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
LV2_URID map (const char* str) const { return mapFeature.map (mapFeature.handle, str); }
|
||||
|
||||
const LV2_URID_Map mapFeature;
|
||||
#define X(str) const LV2_URID m##str = map (str);
|
||||
X (LV2_ATOM__Double)
|
||||
X (LV2_ATOM__Float)
|
||||
X (LV2_ATOM__Int)
|
||||
X (LV2_ATOM__Long)
|
||||
X (LV2_ATOM__Bool)
|
||||
#undef X
|
||||
|
||||
JUCE_LEAK_DETECTOR (NumericAtomParser)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct PatchSetHelper
|
||||
{
|
||||
PatchSetHelper (LV2_URID_Map mapFeatureIn, const char* pluginUri)
|
||||
: parser (mapFeatureIn),
|
||||
pluginUrid (parser.map (pluginUri))
|
||||
{}
|
||||
|
||||
bool isPlugin (const LV2_Atom* subject) const
|
||||
{
|
||||
if (subject == nullptr)
|
||||
return true;
|
||||
|
||||
return subject->type == mLV2_ATOM__URID
|
||||
&& reinterpret_cast<const LV2_Atom_URID*> (subject)->body == pluginUrid;
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void processPatchSet (const LV2_Atom_Object* object, Callback&& callback)
|
||||
{
|
||||
if (object->body.otype != mLV2_PATCH__Set)
|
||||
return;
|
||||
|
||||
const LV2_Atom* subject = nullptr;
|
||||
const LV2_Atom* property = nullptr;
|
||||
const LV2_Atom* value = nullptr;
|
||||
|
||||
LV2_Atom_Object_Query query[] { { mLV2_PATCH__subject, &subject },
|
||||
{ mLV2_PATCH__property, &property },
|
||||
{ mLV2_PATCH__value, &value },
|
||||
LV2_ATOM_OBJECT_QUERY_END };
|
||||
|
||||
lv2_atom_object_query (object, query);
|
||||
|
||||
if (! isPlugin (subject))
|
||||
return;
|
||||
|
||||
setPluginProperty (property, value, std::forward<Callback> (callback));
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void processPatchSet (const LV2_Atom_Event* event, Callback&& callback)
|
||||
{
|
||||
if (event->body.type == mLV2_ATOM__Object)
|
||||
processPatchSet (reinterpret_cast<const LV2_Atom_Object*> (&event->body), std::forward<Callback> (callback));
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void setPluginProperty (const LV2_Atom* property, const LV2_Atom* value, Callback&& callback)
|
||||
{
|
||||
if (property == nullptr)
|
||||
{
|
||||
// No property was supplied.
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
if (property->type != mLV2_ATOM__URID)
|
||||
{
|
||||
// Set property is not a URID.
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto parseResult = parser.parseNumericAtom<float> (value);
|
||||
|
||||
if (! parseResult.hasValue())
|
||||
{
|
||||
// Didn't understand the type of this atom.
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
callback.setParameter (reinterpret_cast<const LV2_Atom_URID*> (property)->body, *parseResult);
|
||||
}
|
||||
|
||||
NumericAtomParser parser;
|
||||
LV2_URID pluginUrid;
|
||||
#define X(str) const LV2_URID m##str = parser.map (str);
|
||||
X (LV2_ATOM__Bool)
|
||||
X (LV2_ATOM__Object)
|
||||
X (LV2_ATOM__URID)
|
||||
X (LV2_PATCH__Set)
|
||||
X (LV2_PATCH__property)
|
||||
X (LV2_PATCH__subject)
|
||||
X (LV2_PATCH__value)
|
||||
#undef X
|
||||
|
||||
JUCE_LEAK_DETECTOR (PatchSetHelper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <typename Traits>
|
||||
class Iterator
|
||||
{
|
||||
using Container = typename Traits::Container;
|
||||
using Iter = typename Traits::Iter;
|
||||
|
||||
public:
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = decltype (Traits::get (std::declval<Container>(), std::declval<Iter>()));
|
||||
using pointer = value_type*;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
/** Create iterator in end/sentinel state */
|
||||
Iterator() = default;
|
||||
|
||||
/** Create iterator pointing to the beginning of this collection */
|
||||
explicit Iterator (Container p) noexcept
|
||||
: container (p), iter (testEnd (Traits::begin (container))) {}
|
||||
|
||||
Iterator begin() const noexcept { return *this; }
|
||||
Iterator end() const noexcept { return {}; }
|
||||
|
||||
bool operator== (const Iterator& other) const noexcept
|
||||
{
|
||||
return iter == nullptr && other.iter == nullptr;
|
||||
}
|
||||
|
||||
bool operator!= (const Iterator& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
iter = testEnd (Traits::next (container, iter));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++ (int)
|
||||
{
|
||||
auto copy = *this;
|
||||
++(*this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
reference operator*() const noexcept
|
||||
{
|
||||
return Traits::get (container, iter);
|
||||
}
|
||||
|
||||
private:
|
||||
Iter testEnd (Iter i) const noexcept
|
||||
{
|
||||
return Traits::isEnd (container, i) ? Iter{} : i;
|
||||
}
|
||||
|
||||
Container container{};
|
||||
Iter iter{};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct SequenceWithSize
|
||||
{
|
||||
SequenceWithSize() = default;
|
||||
|
||||
SequenceWithSize (const LV2_Atom_Sequence_Body* bodyIn, size_t sizeIn)
|
||||
: body (bodyIn), size (sizeIn) {}
|
||||
|
||||
explicit SequenceWithSize (const LV2_Atom_Sequence* sequence)
|
||||
: body (&sequence->body), size (sequence->atom.size) {}
|
||||
|
||||
const LV2_Atom_Sequence_Body* body = nullptr;
|
||||
size_t size = 0;
|
||||
|
||||
JUCE_LEAK_DETECTOR (SequenceWithSize)
|
||||
};
|
||||
|
||||
struct SequenceIteratorTraits
|
||||
{
|
||||
using Container = SequenceWithSize;
|
||||
using Iter = LV2_Atom_Event*;
|
||||
|
||||
static LV2_Atom_Event* begin (const Container& s) noexcept
|
||||
{
|
||||
return lv2_atom_sequence_begin (s.body);
|
||||
}
|
||||
|
||||
static LV2_Atom_Event* next (const Container&, Iter it) noexcept
|
||||
{
|
||||
return lv2_atom_sequence_next (it);
|
||||
}
|
||||
|
||||
static bool isEnd (const Container& s, Iter it) noexcept
|
||||
{
|
||||
return lv2_atom_sequence_is_end (s.body, static_cast<uint32_t> (s.size), it);
|
||||
}
|
||||
|
||||
static LV2_Atom_Event* get (const Container&, Iter e) noexcept { return e; }
|
||||
};
|
||||
|
||||
using SequenceIterator = Iterator<SequenceIteratorTraits>;
|
||||
|
||||
const std::map<String, AudioChannelSet::ChannelType> channelDesignationMap
|
||||
{
|
||||
{ LV2_PORT_GROUPS__center, AudioChannelSet::ChannelType::centre },
|
||||
{ LV2_PORT_GROUPS__centerLeft, AudioChannelSet::ChannelType::leftCentre },
|
||||
{ LV2_PORT_GROUPS__centerRight, AudioChannelSet::ChannelType::rightCentre },
|
||||
{ LV2_PORT_GROUPS__left, AudioChannelSet::ChannelType::left },
|
||||
{ LV2_PORT_GROUPS__lowFrequencyEffects, AudioChannelSet::ChannelType::LFE },
|
||||
{ LV2_PORT_GROUPS__rearCenter, AudioChannelSet::ChannelType::surround },
|
||||
{ LV2_PORT_GROUPS__rearLeft, AudioChannelSet::ChannelType::leftSurroundRear },
|
||||
{ LV2_PORT_GROUPS__rearRight, AudioChannelSet::ChannelType::rightSurroundRear },
|
||||
{ LV2_PORT_GROUPS__right, AudioChannelSet::ChannelType::right },
|
||||
{ LV2_PORT_GROUPS__sideLeft, AudioChannelSet::ChannelType::leftSurroundSide },
|
||||
{ LV2_PORT_GROUPS__sideRight, AudioChannelSet::ChannelType::rightSurroundSide }
|
||||
};
|
||||
|
||||
/* Useful for converting a `void*` to another type (X11 Window, function pointer etc.) without
|
||||
invoking UB.
|
||||
*/
|
||||
template <typename OtherWordType, typename Word>
|
||||
static auto wordCast (Word word)
|
||||
{
|
||||
static_assert (sizeof (word) == sizeof (OtherWordType), "Word sizes must match");
|
||||
return readUnaligned<OtherWordType> (&word);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct SinglePortInfo
|
||||
{
|
||||
uint32_t index;
|
||||
AudioChannelSet::ChannelType designation;
|
||||
bool optional;
|
||||
|
||||
auto tie() const { return std::tie (index, designation, optional); }
|
||||
bool operator== (const SinglePortInfo& other) const { return tie() == other.tie(); }
|
||||
bool operator< (const SinglePortInfo& other) const { return index < other.index; }
|
||||
};
|
||||
|
||||
struct ParsedGroup
|
||||
{
|
||||
String uid;
|
||||
std::set<SinglePortInfo> info;
|
||||
|
||||
auto tie() const { return std::tie (uid, info); }
|
||||
bool operator== (const ParsedGroup& other) const { return tie() == other.tie(); }
|
||||
|
||||
static AudioChannelSet getEquivalentSet (const std::set<SinglePortInfo>& info)
|
||||
{
|
||||
const auto hasUnknownKind = [] (const SinglePortInfo& i) { return i.designation == AudioChannelSet::unknown; };
|
||||
|
||||
if (std::any_of (info.begin(), info.end(), hasUnknownKind))
|
||||
return AudioChannelSet::discreteChannels ((int) info.size());
|
||||
|
||||
AudioChannelSet result;
|
||||
|
||||
for (const auto& port : info)
|
||||
result.addChannel (port.designation);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AudioChannelSet getEquivalentSet() const noexcept { return getEquivalentSet (info); }
|
||||
|
||||
bool isRequired() const
|
||||
{
|
||||
const auto getRequired = [] (const SinglePortInfo& i) { return ! i.optional; };
|
||||
return std::any_of (info.begin(), info.end(), getRequired);
|
||||
}
|
||||
|
||||
bool isCompatible (const AudioChannelSet& requestedBus) const
|
||||
{
|
||||
return requestedBus == getEquivalentSet() || (! isRequired() && requestedBus.isDisabled());
|
||||
}
|
||||
};
|
||||
|
||||
struct ParsedBuses
|
||||
{
|
||||
std::vector<ParsedGroup> inputs, outputs;
|
||||
};
|
||||
|
||||
class PortToAudioBufferMap
|
||||
{
|
||||
public:
|
||||
PortToAudioBufferMap (const AudioProcessor::BusesLayout& layout, const ParsedBuses& buses)
|
||||
: PortToAudioBufferMap ({ layout.inputBuses, buses.inputs },
|
||||
{ layout.outputBuses, buses.outputs })
|
||||
{}
|
||||
|
||||
int getChannelForPort (uint32_t port) const
|
||||
{
|
||||
const auto it = ports.find (port);
|
||||
return it != ports.end() ? it->second : -1;
|
||||
}
|
||||
|
||||
private:
|
||||
PortToAudioBufferMap (const Array<AudioChannelSet>& host,
|
||||
const std::vector<ParsedGroup>& client)
|
||||
: ports (getPortLayout (host, client))
|
||||
{}
|
||||
|
||||
PortToAudioBufferMap (const PortToAudioBufferMap& inputs,
|
||||
const PortToAudioBufferMap& outputs)
|
||||
{
|
||||
ports.insert (inputs.ports.begin(), inputs.ports.end());
|
||||
ports.insert (outputs.ports.begin(), outputs.ports.end());
|
||||
|
||||
// If this assertion is hit, some ports have duplicate indices
|
||||
jassert (ports.size() == inputs.ports.size() + outputs.ports.size());
|
||||
}
|
||||
|
||||
static std::map<uint32_t, int> getPortLayout (const Array<AudioChannelSet>& layout,
|
||||
const std::vector<ParsedGroup>& parsedGroup)
|
||||
{
|
||||
if ((int) parsedGroup.size() != layout.size())
|
||||
{
|
||||
// Something has gone very wrong when computing/applying bus layouts!
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::map<uint32_t, int> result;
|
||||
int channelOffsetOfBus = 0;
|
||||
auto groupIterator = parsedGroup.begin();
|
||||
|
||||
for (const auto& bus : layout)
|
||||
{
|
||||
const auto& group = groupIterator->info;
|
||||
|
||||
for (const auto& port : group)
|
||||
{
|
||||
const auto index = bus.getChannelIndexForType (port.designation);
|
||||
|
||||
if (index >= 0)
|
||||
result.emplace (port.index, channelOffsetOfBus + index);
|
||||
}
|
||||
|
||||
channelOffsetOfBus += bus.size();
|
||||
++groupIterator;
|
||||
}
|
||||
|
||||
if ((int) result.size() != channelOffsetOfBus)
|
||||
{
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<uint32_t, int> ports;
|
||||
|
||||
JUCE_LEAK_DETECTOR (PortToAudioBufferMap)
|
||||
};
|
||||
|
||||
// This will convert some grouped and ungrouped ports into a single collection of
|
||||
// buses with a stable order.
|
||||
// If any group has been marked as the main group, this will be placed first in the
|
||||
// collection of results. The remaining groups will be sorted according to the
|
||||
// indices of their ports.
|
||||
// If there are no groups, all mandatory ports will be grouped into the first bus,
|
||||
// and all remaining optional ports will have a separate bus each.
|
||||
static inline std::vector<ParsedGroup> findStableBusOrder (const String& mainGroupUid,
|
||||
const std::map<String, std::set<SinglePortInfo>>& groupedPorts,
|
||||
const std::set<SinglePortInfo>& ungroupedPorts)
|
||||
{
|
||||
if (groupedPorts.empty())
|
||||
{
|
||||
std::vector<ParsedGroup> result;
|
||||
|
||||
ParsedGroup mandatoryPorts;
|
||||
|
||||
for (const auto& port : ungroupedPorts)
|
||||
if (! port.optional)
|
||||
mandatoryPorts.info.insert (port);
|
||||
|
||||
if (! mandatoryPorts.info.empty())
|
||||
result.push_back (std::move (mandatoryPorts));
|
||||
|
||||
for (const auto& port : ungroupedPorts)
|
||||
if (port.optional)
|
||||
result.push_back ({ String{}, { port } });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ParsedGroup> result;
|
||||
|
||||
const auto pushGroup = [&] (const std::pair<String, std::set<SinglePortInfo>>& info)
|
||||
{
|
||||
result.push_back ({ info.first, info.second });
|
||||
};
|
||||
|
||||
const auto mainGroupIterator = groupedPorts.find (mainGroupUid);
|
||||
|
||||
if (mainGroupIterator != groupedPorts.end())
|
||||
pushGroup (*mainGroupIterator);
|
||||
|
||||
for (auto it = groupedPorts.begin(); it != groupedPorts.end(); ++it)
|
||||
if (it != mainGroupIterator)
|
||||
pushGroup (*it);
|
||||
|
||||
for (const auto& info : ungroupedPorts)
|
||||
result.push_back ({ String{}, { info } });
|
||||
|
||||
if (! result.empty())
|
||||
{
|
||||
// It is an error for the same port to be a member of multiple groups.
|
||||
// Therefore, a standard sort will always be stable, and we don't need to
|
||||
// use an explicitly stable sort.
|
||||
const auto compare = [] (const ParsedGroup& a, const ParsedGroup& b) { return a.info < b.info; };
|
||||
std::sort (std::next (result.begin()), result.end(), compare);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* See https://www.w3.org/TeamSubmission/turtle/#sec-grammar-grammar
|
||||
*/
|
||||
static inline bool isNameStartChar (juce_wchar input)
|
||||
{
|
||||
return ('A' <= input && input <= 'Z')
|
||||
|| input == '_'
|
||||
|| ('a' <= input && input <= 'z')
|
||||
|| (0x000c0 <= input && input <= 0x000d6)
|
||||
|| (0x000d8 <= input && input <= 0x000f6)
|
||||
|| (0x000f8 <= input && input <= 0x000ff)
|
||||
|| (0x00370 <= input && input <= 0x0037d)
|
||||
|| (0x0037f <= input && input <= 0x01fff)
|
||||
|| (0x0200c <= input && input <= 0x0200d)
|
||||
|| (0x02070 <= input && input <= 0x0218f)
|
||||
|| (0x02c00 <= input && input <= 0x02fef)
|
||||
|| (0x03001 <= input && input <= 0x0d7ff)
|
||||
|| (0x0f900 <= input && input <= 0x0fdcf)
|
||||
|| (0x0fdf0 <= input && input <= 0x0fffd)
|
||||
|| (0x10000 <= input && input <= 0xeffff);
|
||||
}
|
||||
|
||||
static inline bool isNameChar (juce_wchar input)
|
||||
{
|
||||
return isNameStartChar (input)
|
||||
|| input == '-'
|
||||
|| ('0' <= input && input <= '9')
|
||||
|| input == 0x000b7
|
||||
|| (0x00300 <= input && input <= 0x0036f)
|
||||
|| (0x0203f <= input && input <= 0x02040);
|
||||
}
|
||||
|
||||
static inline String sanitiseStringAsTtlName (const String& input)
|
||||
{
|
||||
if (input.isEmpty())
|
||||
return {};
|
||||
|
||||
std::vector<juce_wchar> sanitised;
|
||||
sanitised.reserve (static_cast<size_t> (input.length()));
|
||||
|
||||
sanitised.push_back (isNameStartChar (input[0]) ? input[0] : '_');
|
||||
|
||||
std::for_each (std::begin (input) + 1, std::end (input), [&] (juce_wchar x)
|
||||
{
|
||||
sanitised.push_back (isNameChar (x) ? x : '_');
|
||||
});
|
||||
|
||||
return String (CharPointer_UTF32 { sanitised.data() }, sanitised.size());
|
||||
}
|
||||
|
||||
} // namespace juce::lv2_shared
|
||||
/** @endcond */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -42,44 +42,9 @@ namespace juce
|
|||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API LV2PluginFormat : public AudioPluginFormat
|
||||
class JUCE_API LV2PluginFormat : public LV2PluginFormatHeadless
|
||||
{
|
||||
public:
|
||||
LV2PluginFormat();
|
||||
~LV2PluginFormat() override;
|
||||
|
||||
static String getFormatName() { return "LV2"; }
|
||||
String getName() const override { return getFormatName(); }
|
||||
|
||||
void findAllTypesForFile (OwnedArray<PluginDescription>& results,
|
||||
const String& fileOrIdentifier) override;
|
||||
|
||||
bool fileMightContainThisPluginType (const String& fileOrIdentifier) override;
|
||||
|
||||
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override;
|
||||
|
||||
bool pluginNeedsRescanning (const PluginDescription&) override;
|
||||
|
||||
bool doesPluginStillExist (const PluginDescription&) override;
|
||||
|
||||
bool canScanForPlugins() const override;
|
||||
|
||||
bool isTrivialToScan() const override;
|
||||
|
||||
StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch,
|
||||
bool recursive,
|
||||
bool allowPluginsWhichRequireAsynchronousInstantiation = false) override;
|
||||
|
||||
FileSearchPath getDefaultLocationsToSearch() override;
|
||||
|
||||
private:
|
||||
bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const override;
|
||||
void createPluginInstance (const PluginDescription&, double, int, PluginCreationCallback) override;
|
||||
|
||||
class Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LV2PluginFormat)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "juce_LV2Common.h"
|
||||
#include <juce_audio_processors_headless/format_types/juce_LV2Common.h>
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "juce_lv2_config.h"
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wc99-extensions",
|
||||
"-Wcast-align",
|
||||
"-Wconversion",
|
||||
"-Wextra-semi",
|
||||
"-Wfloat-conversion",
|
||||
"-Wfloat-equal",
|
||||
"-Wformat-overflow",
|
||||
"-Wimplicit-float-conversion",
|
||||
"-Wimplicit-int-conversion",
|
||||
"-Wmicrosoft-include",
|
||||
"-Wmissing-field-initializers",
|
||||
"-Wnullability-extension",
|
||||
"-Wnullable-to-nonnull-conversion",
|
||||
"-Wparentheses",
|
||||
"-Wpedantic",
|
||||
"-Wredundant-decls",
|
||||
"-Wshorten-64-to-32",
|
||||
"-Wsign-conversion",
|
||||
"-Wswitch-enum",
|
||||
"-Wunused-parameter",
|
||||
"-Wzero-as-null-pointer-constant")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4100 4200 4244 4267 4389 4702 4706 4800 6308 28182 28183 6385 6386 6387 6011 6282 6323 6330 6001 6031)
|
||||
JUCE_BEGIN_IGNORE_DEPRECATION_WARNINGS
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define is_windows_path serd_is_windows_path
|
||||
|
||||
#include "serd/src/base64.c"
|
||||
#include "serd/src/byte_source.c"
|
||||
#include "serd/src/env.c"
|
||||
#include "serd/src/n3.c"
|
||||
#undef TRY
|
||||
|
||||
#include "serd/src/node.c"
|
||||
#include "serd/src/reader.c"
|
||||
#include "serd/src/string.c"
|
||||
#include "serd/src/system.c"
|
||||
#include "serd/src/uri.c"
|
||||
#include "serd/src/writer.c"
|
||||
|
||||
#undef is_windows_path
|
||||
|
||||
#include "sord/src/sord.c"
|
||||
#include "sord/src/syntax.c"
|
||||
|
||||
#include "lilv/src/collections.c"
|
||||
#include "lilv/src/filesystem.c"
|
||||
#include "lilv/src/instance.c"
|
||||
#include "lilv/src/lib.c"
|
||||
#include "lilv/src/node.c"
|
||||
#include "lilv/src/plugin.c"
|
||||
#include "lilv/src/pluginclass.c"
|
||||
#include "lilv/src/port.c"
|
||||
#include "lilv/src/query.c"
|
||||
#include "lilv/src/scalepoint.c"
|
||||
#include "lilv/src/state.c"
|
||||
#include "lilv/src/ui.c"
|
||||
#include "lilv/src/util.c"
|
||||
#include "lilv/src/world.c"
|
||||
#include "lilv/src/zix/tree.c"
|
||||
|
||||
#undef NS_RDF
|
||||
#undef NS_XSD
|
||||
#undef USTR
|
||||
|
||||
#define read_object sratom_read_object
|
||||
#define read_literal sratom_read_literal
|
||||
|
||||
#pragma push_macro ("nil")
|
||||
#undef nil
|
||||
#include "sratom/src/sratom.c"
|
||||
#pragma pop_macro ("nil")
|
||||
|
||||
} // extern "C"
|
||||
|
||||
JUCE_END_IGNORE_DEPRECATION_WARNINGS
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_PLUGINHOST_LV2 && (! (JUCE_ANDROID || JUCE_IOS))
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <juce_core/system/juce_CompilerWarnings.h>
|
||||
#include <juce_core/system/juce_TargetPlatform.h>
|
||||
|
||||
#include "format_types/juce_LV2SupportLibs.cpp"
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue