migrating to the latest JUCE version

This commit is contained in:
2022-11-04 23:11:33 +01:00
committed by Nikolai Rodionov
parent 4257a0f8ba
commit faf8f18333
2796 changed files with 888518 additions and 784244 deletions

View File

@@ -1,98 +1,98 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
AudioPluginFormat::AudioPluginFormat() {}
AudioPluginFormat::~AudioPluginFormat() {}
std::unique_ptr<AudioPluginInstance> AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc,
double initialSampleRate,
int initialBufferSize)
{
String errorMessage;
return createInstanceFromDescription (desc, initialSampleRate, initialBufferSize, errorMessage);
}
std::unique_ptr<AudioPluginInstance> AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc,
double initialSampleRate,
int initialBufferSize,
String& errorMessage)
{
if (MessageManager::getInstance()->isThisTheMessageThread()
&& requiresUnblockedMessageThreadDuringCreation (desc))
{
errorMessage = NEEDS_TRANS ("This plug-in cannot be instantiated synchronously");
return {};
}
WaitableEvent finishedSignal;
std::unique_ptr<AudioPluginInstance> instance;
auto callback = [&] (std::unique_ptr<AudioPluginInstance> p, const String& error)
{
errorMessage = error;
instance = std::move (p);
finishedSignal.signal();
};
if (! MessageManager::getInstance()->isThisTheMessageThread())
createPluginInstanceAsync (desc, initialSampleRate, initialBufferSize, std::move (callback));
else
createPluginInstance (desc, initialSampleRate, initialBufferSize, std::move (callback));
finishedSignal.wait();
return instance;
}
struct AudioPluginFormat::AsyncCreateMessage : public Message
{
AsyncCreateMessage (const PluginDescription& d, double sr, int size, PluginCreationCallback call)
: desc (d), sampleRate (sr), bufferSize (size), callbackToUse (std::move (call))
{
}
PluginDescription desc;
double sampleRate;
int bufferSize;
PluginCreationCallback callbackToUse;
};
void AudioPluginFormat::createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
PluginCreationCallback callback)
{
jassert (callback != nullptr);
postMessage (new AsyncCreateMessage (description, initialSampleRate, initialBufferSize, std::move (callback)));
}
void AudioPluginFormat::handleMessage (const Message& message)
{
if (auto m = dynamic_cast<const AsyncCreateMessage*> (&message))
createPluginInstance (m->desc, m->sampleRate, m->bufferSize, std::move (m->callbackToUse));
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
AudioPluginFormat::AudioPluginFormat() {}
AudioPluginFormat::~AudioPluginFormat() {}
std::unique_ptr<AudioPluginInstance> AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc,
double initialSampleRate,
int initialBufferSize)
{
String errorMessage;
return createInstanceFromDescription (desc, initialSampleRate, initialBufferSize, errorMessage);
}
std::unique_ptr<AudioPluginInstance> AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc,
double initialSampleRate,
int initialBufferSize,
String& errorMessage)
{
if (MessageManager::getInstance()->isThisTheMessageThread()
&& requiresUnblockedMessageThreadDuringCreation (desc))
{
errorMessage = NEEDS_TRANS ("This plug-in cannot be instantiated synchronously");
return {};
}
WaitableEvent finishedSignal;
std::unique_ptr<AudioPluginInstance> instance;
auto callback = [&] (std::unique_ptr<AudioPluginInstance> p, const String& error)
{
errorMessage = error;
instance = std::move (p);
finishedSignal.signal();
};
if (! MessageManager::getInstance()->isThisTheMessageThread())
createPluginInstanceAsync (desc, initialSampleRate, initialBufferSize, std::move (callback));
else
createPluginInstance (desc, initialSampleRate, initialBufferSize, std::move (callback));
finishedSignal.wait();
return instance;
}
struct AudioPluginFormat::AsyncCreateMessage : public Message
{
AsyncCreateMessage (const PluginDescription& d, double sr, int size, PluginCreationCallback call)
: desc (d), sampleRate (sr), bufferSize (size), callbackToUse (std::move (call))
{
}
PluginDescription desc;
double sampleRate;
int bufferSize;
PluginCreationCallback callbackToUse;
};
void AudioPluginFormat::createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
PluginCreationCallback callback)
{
jassert (callback != nullptr);
postMessage (new AsyncCreateMessage (description, initialSampleRate, initialBufferSize, std::move (callback)));
}
void AudioPluginFormat::handleMessage (const Message& message)
{
if (auto m = dynamic_cast<const AsyncCreateMessage*> (&message))
createPluginInstance (m->desc, m->sampleRate, m->bufferSize, std::move (m->callbackToUse));
}
} // namespace juce

View File

@@ -1,162 +1,174 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc.
@see AudioPluginFormatManager
@tags{Audio}
*/
class JUCE_API AudioPluginFormat : private MessageListener
{
public:
/** Destructor. */
~AudioPluginFormat() override;
//==============================================================================
/** Returns the format name.
E.g. "VST", "AudioUnit", etc.
*/
virtual String getName() const = 0;
/** This tries to create descriptions for all the plugin types available in
a binary module file.
The file will be some kind of DLL or bundle.
Normally there will only be one type returned, but some plugins
(e.g. VST shells) can use a single DLL to create a set of different plugin
subtypes, so in that case, each subtype is returned as a separate object.
*/
virtual void findAllTypesForFile (OwnedArray<PluginDescription>& results,
const String& fileOrIdentifier) = 0;
/** Tries to recreate a type from a previously generated PluginDescription.
@see AudioPluginFormatManager::createInstance
*/
std::unique_ptr<AudioPluginInstance> createInstanceFromDescription (const PluginDescription&,
double initialSampleRate,
int initialBufferSize);
/** Same as above but with the possibility of returning an error message.
@see AudioPluginFormatManager::createInstance
*/
std::unique_ptr<AudioPluginInstance> createInstanceFromDescription (const PluginDescription&,
double initialSampleRate,
int initialBufferSize,
String& errorMessage);
/** A callback lambda that is passed to createPluginInstanceAsync() */
using PluginCreationCallback = std::function<void (std::unique_ptr<AudioPluginInstance>, const String&)>;
/** Tries to recreate a type from a previously generated PluginDescription.
When the plugin has been created, it will be passed to the caller via an
asynchronous call to the PluginCreationCallback lambda that was provided.
@see AudioPluginFormatManager::createPluginInstanceAsync
*/
void createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate,
int initialBufferSize,
PluginCreationCallback);
/** Should do a quick check to see if this file or directory might be a plugin of
this format.
This is for searching for potential files, so it shouldn't actually try to
load the plugin or do anything time-consuming.
*/
virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0;
/** Returns a readable version of the name of the plugin that this identifier refers to. */
virtual String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0;
/** Returns true if this plugin's version or date has changed and it should be re-checked. */
virtual bool pluginNeedsRescanning (const PluginDescription&) = 0;
/** Checks whether this plugin could possibly be loaded.
It doesn't actually need to load it, just to check whether the file or component
still exists.
*/
virtual bool doesPluginStillExist (const PluginDescription&) = 0;
/** Returns true if this format needs to run a scan to find its list of plugins. */
virtual bool canScanForPlugins() const = 0;
/** Should return true if this format is both safe and quick to scan - i.e. if a file
can be scanned within a few milliseconds on a background thread, without actually
needing to load an executable.
*/
virtual bool isTrivialToScan() const = 0;
/** Searches a suggested set of directories for any plugins in this format.
The path might be ignored, e.g. by AUs, which are found by the OS rather
than manually.
@param directoriesToSearch This specifies which directories shall be
searched for plug-ins.
@param recursive Should the search recursively traverse folders.
@param allowPluginsWhichRequireAsynchronousInstantiation
If this is false then plug-ins which require
asynchronous creation will be excluded.
*/
virtual StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch,
bool recursive,
bool allowPluginsWhichRequireAsynchronousInstantiation = false) = 0;
/** Returns the typical places to look for this kind of plugin.
Note that if this returns no paths, it means that the format doesn't search in
files or folders, e.g. AudioUnits.
*/
virtual FileSearchPath getDefaultLocationsToSearch() = 0;
protected:
//==============================================================================
friend class AudioPluginFormatManager;
AudioPluginFormat();
/** Implementors must override this function. This is guaranteed to be called on
the message thread. You may call the callback on any thread.
*/
virtual void createPluginInstance (const PluginDescription&, double initialSampleRate,
int initialBufferSize, PluginCreationCallback) = 0;
/** Returns true if instantiation of this plugin type must be done from a non-message thread. */
virtual bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const = 0;
private:
struct AsyncCreateMessage;
void handleMessage (const Message&) override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormat)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc.
@see AudioPluginFormatManager
@tags{Audio}
*/
class JUCE_API AudioPluginFormat : private MessageListener
{
public:
/** Destructor. */
~AudioPluginFormat() override;
//==============================================================================
/** Returns the format name.
E.g. "VST", "AudioUnit", etc.
*/
virtual String getName() const = 0;
/** This tries to create descriptions for all the plugin types available in
a binary module file.
The file will be some kind of DLL or bundle.
Normally there will only be one type returned, but some plugins
(e.g. VST shells) can use a single DLL to create a set of different plugin
subtypes, so in that case, each subtype is returned as a separate object.
*/
virtual void findAllTypesForFile (OwnedArray<PluginDescription>& results,
const String& fileOrIdentifier) = 0;
/** Tries to recreate a type from a previously generated PluginDescription.
@see AudioPluginFormatManager::createInstance
*/
std::unique_ptr<AudioPluginInstance> createInstanceFromDescription (const PluginDescription&,
double initialSampleRate,
int initialBufferSize);
/** Same as above but with the possibility of returning an error message.
@see AudioPluginFormatManager::createInstance
*/
std::unique_ptr<AudioPluginInstance> createInstanceFromDescription (const PluginDescription&,
double initialSampleRate,
int initialBufferSize,
String& errorMessage);
/** A callback lambda that is passed to createPluginInstanceAsync() */
using PluginCreationCallback = std::function<void (std::unique_ptr<AudioPluginInstance>, const String&)>;
/** Tries to recreate a type from a previously generated PluginDescription.
When the plugin has been created, it will be passed to the caller via an
asynchronous call to the PluginCreationCallback lambda that was provided.
@see AudioPluginFormatManager::createPluginInstanceAsync
*/
void createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate,
int initialBufferSize,
PluginCreationCallback);
/** Should do a quick check to see if this file or directory might be a plugin of
this format.
This is for searching for potential files, so it shouldn't actually try to
load the plugin or do anything time-consuming.
*/
virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0;
/** Returns a readable version of the name of the plugin that this identifier refers to. */
virtual String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0;
/** Returns true if this plugin's version or date has changed and it should be re-checked. */
virtual bool pluginNeedsRescanning (const PluginDescription&) = 0;
/** Checks whether this plugin could possibly be loaded.
It doesn't actually need to load it, just to check whether the file or component
still exists.
*/
virtual bool doesPluginStillExist (const PluginDescription&) = 0;
/** Returns true if this format needs to run a scan to find its list of plugins. */
virtual bool canScanForPlugins() const = 0;
/** Should return true if this format is both safe and quick to scan - i.e. if a file
can be scanned within a few milliseconds on a background thread, without actually
needing to load an executable.
*/
virtual bool isTrivialToScan() const = 0;
/** Searches a suggested set of directories for any plugins in this format.
The path might be ignored, e.g. by AUs, which are found by the OS rather
than manually.
@param directoriesToSearch This specifies which directories shall be
searched for plug-ins.
@param recursive Should the search recursively traverse folders.
@param allowPluginsWhichRequireAsynchronousInstantiation
If this is false then plug-ins which require
asynchronous creation will be excluded.
*/
virtual StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch,
bool recursive,
bool allowPluginsWhichRequireAsynchronousInstantiation = false) = 0;
/** Returns the typical places to look for this kind of plugin.
Note that if this returns no paths, it means that the format doesn't search in
files or folders, e.g. AudioUnits.
*/
virtual FileSearchPath getDefaultLocationsToSearch() = 0;
/** Returns true if instantiation of this plugin type must be done from a non-message thread. */
virtual bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const = 0;
/** A callback lambda that is passed to getARAFactory() */
using ARAFactoryCreationCallback = std::function<void (ARAFactoryResult)>;
/** Tries to create an ::ARAFactoryWrapper for this description.
The result of the operation will be wrapped into an ARAFactoryResult,
which will be passed to a callback object supplied by the caller.
@see AudioPluginFormatManager::createARAFactoryAsync
*/
virtual void createARAFactoryAsync (const PluginDescription&, ARAFactoryCreationCallback callback) { callback ({}); }
protected:
//==============================================================================
friend class AudioPluginFormatManager;
AudioPluginFormat();
/** Implementors must override this function. This is guaranteed to be called on
the message thread. You may call the callback on any thread.
*/
virtual void createPluginInstance (const PluginDescription&, double initialSampleRate,
int initialBufferSize, PluginCreationCallback) = 0;
private:
struct AsyncCreateMessage;
void handleMessage (const Message&) override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormat)
};
} // namespace juce

View File

@@ -1,151 +1,205 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
AudioPluginFormatManager::AudioPluginFormatManager() {}
AudioPluginFormatManager::~AudioPluginFormatManager() {}
//==============================================================================
void AudioPluginFormatManager::addDefaultFormats()
{
#if JUCE_DEBUG
// you should only call this method once!
for (auto* format : formats)
{
ignoreUnused (format);
#if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_IOS)
jassert (dynamic_cast<VSTPluginFormat*> (format) == nullptr);
#endif
#if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD)
jassert (dynamic_cast<VST3PluginFormat*> (format) == nullptr);
#endif
#if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS)
jassert (dynamic_cast<AudioUnitPluginFormat*> (format) == nullptr);
#endif
#if JUCE_PLUGINHOST_LADSPA && (JUCE_LINUX || JUCE_BSD)
jassert (dynamic_cast<LADSPAPluginFormat*> (format) == nullptr);
#endif
}
#endif
#if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS)
formats.add (new AudioUnitPluginFormat());
#endif
#if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_IOS)
formats.add (new VSTPluginFormat());
#endif
#if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD)
formats.add (new VST3PluginFormat());
#endif
#if JUCE_PLUGINHOST_LADSPA && (JUCE_LINUX || JUCE_BSD)
formats.add (new LADSPAPluginFormat());
#endif
}
int AudioPluginFormatManager::getNumFormats() const { return formats.size(); }
AudioPluginFormat* AudioPluginFormatManager::getFormat (int index) const { return formats[index]; }
Array<AudioPluginFormat*> AudioPluginFormatManager::getFormats() const
{
Array<AudioPluginFormat*> a;
a.addArray (formats);
return a;
}
void AudioPluginFormatManager::addFormat (AudioPluginFormat* format)
{
formats.add (format);
}
std::unique_ptr<AudioPluginInstance> AudioPluginFormatManager::createPluginInstance (const PluginDescription& description,
double rate, int blockSize,
String& errorMessage) const
{
if (auto* format = findFormatForDescription (description, errorMessage))
return format->createInstanceFromDescription (description, rate, blockSize, errorMessage);
return {};
}
void AudioPluginFormatManager::createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
AudioPluginFormat::PluginCreationCallback callback)
{
String error;
if (auto* format = findFormatForDescription (description, error))
return format->createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, std::move (callback));
struct DeliverError : public CallbackMessage
{
DeliverError (AudioPluginFormat::PluginCreationCallback c, const String& e)
: call (std::move (c)), error (e)
{
post();
}
void messageCallback() override { call (nullptr, error); }
AudioPluginFormat::PluginCreationCallback call;
String error;
};
new DeliverError (std::move (callback), error);
}
AudioPluginFormat* AudioPluginFormatManager::findFormatForDescription (const PluginDescription& description,
String& errorMessage) const
{
errorMessage = {};
for (auto* format : formats)
if (format->getName() == description.pluginFormatName
&& format->fileMightContainThisPluginType (description.fileOrIdentifier))
return format;
errorMessage = NEEDS_TRANS ("No compatible plug-in format exists for this plug-in");
return {};
}
bool AudioPluginFormatManager::doesPluginStillExist (const PluginDescription& description) const
{
for (auto* format : formats)
if (format->getName() == description.pluginFormatName)
return format->doesPluginStillExist (description);
return false;
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
AudioPluginFormatManager::AudioPluginFormatManager() {}
AudioPluginFormatManager::~AudioPluginFormatManager() {}
//==============================================================================
void AudioPluginFormatManager::addDefaultFormats()
{
#if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_IOS)
#define HAS_VST 1
#else
#define HAS_VST 0
#endif
#if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD)
#define HAS_VST3 1
#else
#define HAS_VST3 0
#endif
#if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS)
#define HAS_AU 1
#else
#define HAS_AU 0
#endif
#if JUCE_PLUGINHOST_LADSPA && (JUCE_LINUX || JUCE_BSD)
#define HAS_LADSPA 1
#else
#define HAS_LADSPA 0
#endif
#if JUCE_PLUGINHOST_LV2 && (JUCE_MAC || JUCE_LINUX || JUCE_BSD || JUCE_WINDOWS)
#define HAS_LV2 1
#else
#define HAS_LV2 0
#endif
#if JUCE_DEBUG
// you should only call this method once!
for (auto* format : formats)
{
ignoreUnused (format);
#if HAS_VST
jassert (dynamic_cast<VSTPluginFormat*> (format) == nullptr);
#endif
#if HAS_VST3
jassert (dynamic_cast<VST3PluginFormat*> (format) == nullptr);
#endif
#if HAS_AU
jassert (dynamic_cast<AudioUnitPluginFormat*> (format) == nullptr);
#endif
#if HAS_LADSPA
jassert (dynamic_cast<LADSPAPluginFormat*> (format) == nullptr);
#endif
#if HAS_LV2
jassert (dynamic_cast<LV2PluginFormat*> (format) == nullptr);
#endif
}
#endif
#if HAS_AU
formats.add (new AudioUnitPluginFormat());
#endif
#if HAS_VST
formats.add (new VSTPluginFormat());
#endif
#if HAS_VST3
formats.add (new VST3PluginFormat());
#endif
#if HAS_LADSPA
formats.add (new LADSPAPluginFormat());
#endif
#if HAS_LV2
formats.add (new LV2PluginFormat());
#endif
}
int AudioPluginFormatManager::getNumFormats() const { return formats.size(); }
AudioPluginFormat* AudioPluginFormatManager::getFormat (int index) const { return formats[index]; }
Array<AudioPluginFormat*> AudioPluginFormatManager::getFormats() const
{
Array<AudioPluginFormat*> a;
a.addArray (formats);
return a;
}
void AudioPluginFormatManager::addFormat (AudioPluginFormat* format)
{
formats.add (format);
}
std::unique_ptr<AudioPluginInstance> AudioPluginFormatManager::createPluginInstance (const PluginDescription& description,
double rate, int blockSize,
String& errorMessage) const
{
if (auto* format = findFormatForDescription (description, errorMessage))
return format->createInstanceFromDescription (description, rate, blockSize, errorMessage);
return {};
}
void AudioPluginFormatManager::createARAFactoryAsync (const PluginDescription& description,
AudioPluginFormat::ARAFactoryCreationCallback callback) const
{
String errorMessage;
if (auto* format = findFormatForDescription (description, errorMessage))
{
format->createARAFactoryAsync (description, callback);
}
else
{
errorMessage = NEEDS_TRANS ("Couldn't find format for the provided description");
callback ({ {}, std::move (errorMessage) });
}
}
void AudioPluginFormatManager::createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
AudioPluginFormat::PluginCreationCallback callback)
{
String error;
if (auto* format = findFormatForDescription (description, error))
return format->createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, std::move (callback));
struct DeliverError : public CallbackMessage
{
DeliverError (AudioPluginFormat::PluginCreationCallback c, const String& e)
: call (std::move (c)), error (e)
{
post();
}
void messageCallback() override { call (nullptr, error); }
AudioPluginFormat::PluginCreationCallback call;
String error;
};
new DeliverError (std::move (callback), error);
}
AudioPluginFormat* AudioPluginFormatManager::findFormatForDescription (const PluginDescription& description,
String& errorMessage) const
{
errorMessage = {};
for (auto* format : formats)
if (format->getName() == description.pluginFormatName
&& format->fileMightContainThisPluginType (description.fileOrIdentifier))
return format;
errorMessage = NEEDS_TRANS ("No compatible plug-in format exists for this plug-in");
return {};
}
bool AudioPluginFormatManager::doesPluginStillExist (const PluginDescription& description) const
{
for (auto* format : formats)
if (format->getName() == description.pluginFormatName)
return format->doesPluginStillExist (description);
return false;
}
} // namespace juce

View File

@@ -1,126 +1,142 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
This maintains a list of known AudioPluginFormats.
@see AudioPluginFormat
@tags{Audio}
*/
class JUCE_API AudioPluginFormatManager
{
public:
//==============================================================================
AudioPluginFormatManager();
/** Destructor. */
~AudioPluginFormatManager();
//==============================================================================
/** Adds the set of available standard formats, e.g. VST. */
void addDefaultFormats();
//==============================================================================
/** Returns the number of types of format that are available.
Use getFormat() to get one of them.
*/
int getNumFormats() const;
/** Returns one of the available formats.
@see getNumFormats
*/
AudioPluginFormat* getFormat (int index) const;
/** Returns a list of all the registered formats. */
Array<AudioPluginFormat*> getFormats() const;
//==============================================================================
/** Adds a format to the list.
The object passed in will be owned and deleted by the manager.
*/
void addFormat (AudioPluginFormat*);
//==============================================================================
/** Tries to load the type for this description, by trying all the formats
that this manager knows about.
If it can't load the plugin, it returns nullptr and leaves a message in the
errorMessage string.
If you intend to instantiate a AudioUnit v3 plug-in then you must either
use the non-blocking asynchronous version below - or call this method from a
thread other than the message thread and without blocking the message
thread.
*/
std::unique_ptr<AudioPluginInstance> createPluginInstance (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
String& errorMessage) const;
/** Tries to asynchronously load the type for this description, by trying
all the formats that this manager knows about.
The caller must supply a callback object which will be called when
the instantiation has completed.
If it can't load the plugin then the callback function will be called
passing a nullptr as the instance argument along with an error message.
The callback function will be called on the message thread so the caller
must not block the message thread.
The callback object will be deleted automatically after it has been
invoked.
The caller is responsible for deleting the instance that is passed to
the callback function.
If you intend to instantiate a AudioUnit v3 plug-in then you must use
this non-blocking asynchronous version - or call the synchronous method
from an auxiliary thread.
*/
void createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
AudioPluginFormat::PluginCreationCallback callback);
/** Checks that the file or component for this plugin actually still exists.
(This won't try to load the plugin)
*/
bool doesPluginStillExist (const PluginDescription&) const;
private:
//==============================================================================
AudioPluginFormat* findFormatForDescription (const PluginDescription&, String& errorMessage) const;
OwnedArray<AudioPluginFormat> formats;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
This maintains a list of known AudioPluginFormats.
@see AudioPluginFormat
@tags{Audio}
*/
class JUCE_API AudioPluginFormatManager
{
public:
//==============================================================================
AudioPluginFormatManager();
/** Destructor. */
~AudioPluginFormatManager();
//==============================================================================
/** Adds the set of available standard formats, e.g. VST. */
void addDefaultFormats();
//==============================================================================
/** Returns the number of types of format that are available.
Use getFormat() to get one of them.
*/
int getNumFormats() const;
/** Returns one of the available formats.
@see getNumFormats
*/
AudioPluginFormat* getFormat (int index) const;
/** Returns a list of all the registered formats. */
Array<AudioPluginFormat*> getFormats() const;
//==============================================================================
/** Adds a format to the list.
The object passed in will be owned and deleted by the manager.
*/
void addFormat (AudioPluginFormat*);
//==============================================================================
/** Tries to load the type for this description, by trying all the formats
that this manager knows about.
If it can't load the plugin, it returns nullptr and leaves a message in the
errorMessage string.
If you intend to instantiate a AudioUnit v3 plug-in then you must either
use the non-blocking asynchronous version below - or call this method from a
thread other than the message thread and without blocking the message
thread.
*/
std::unique_ptr<AudioPluginInstance> createPluginInstance (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
String& errorMessage) const;
/** Tries to asynchronously load the type for this description, by trying
all the formats that this manager knows about.
The caller must supply a callback object which will be called when
the instantiation has completed.
If it can't load the plugin then the callback function will be called
passing a nullptr as the instance argument along with an error message.
The callback function will be called on the message thread so the caller
must not block the message thread.
The callback object will be deleted automatically after it has been
invoked.
The caller is responsible for deleting the instance that is passed to
the callback function.
If you intend to instantiate a AudioUnit v3 plug-in then you must use
this non-blocking asynchronous version - or call the synchronous method
from an auxiliary thread.
*/
void createPluginInstanceAsync (const PluginDescription& description,
double initialSampleRate, int initialBufferSize,
AudioPluginFormat::PluginCreationCallback callback);
/** Tries to create an ::ARAFactoryWrapper for this description.
The result of the operation will be wrapped into an ARAFactoryResult,
which will be passed to a callback object supplied by the caller.
The operation may fail, in which case the callback will be called with
with a result object where ARAFactoryResult::araFactory.get() will return
a nullptr.
In case of success the returned ::ARAFactoryWrapper will ensure that
modules required for the correct functioning of the ARAFactory will remain
loaded for the lifetime of the object.
*/
void createARAFactoryAsync (const PluginDescription& description,
AudioPluginFormat::ARAFactoryCreationCallback callback) const;
/** Checks that the file or component for this plugin actually still exists.
(This won't try to load the plugin)
*/
bool doesPluginStillExist (const PluginDescription&) const;
private:
//==============================================================================
AudioPluginFormat* findFormatForDescription (const PluginDescription&, String& errorMessage) const;
OwnedArray<AudioPluginFormat> formats;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager)
};
} // namespace juce

View File

@@ -0,0 +1,11 @@
The source code for lilv and its dependent libraries have been copied into this
directory. The following modifications were made:
- Removed files not strictly required to build the lilv library,
including generated config headers
- Added handwritten config headers
- Removed the include of dlfcn.h in world.c
Remember to update the versions in the config headers if you ever update
the library versions!

View File

@@ -0,0 +1,157 @@
# ==============================================================================
#
# This file is part of the JUCE library.
# Copyright (c) 2020 - Raw Material Software Limited
#
# JUCE is an open source library subject to commercial or open-source
# licensing.
#
# By using JUCE, you agree to the terms of both the JUCE 7 End-User License
# Agreement and JUCE Privacy Policy.
#
# End User License Agreement: www.juce.com/juce-7-licence
# Privacy Policy: www.juce.com/juce-privacy-policy
#
# Or: You may also use this code under the terms of the GPL v3 (see
# www.gnu.org/licenses).
#
# JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
# EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
# DISCLAIMED.
#
# ==============================================================================
# This script is used to convert the data files from the LV2 distribution into
# a form suitable for inclusion in a C++ project. An LV2 host would normally
# expect these files to be installed on disk, but this places a burden on host
# developers to include these files in their product installers, and to install
# them to sensible locations. Instead of forcing host developers to handle this
# case, JUCE hosts will use the embedded copy of this data to write all of the
# files to a temporary location at runtime.
import argparse
import os
BUNDLE_TEMPLATE = """juce::lv2::Bundle
{{
"{}",
{{
{}
}}
}}
"""
BUNDLE_RESOURCE_TEMPLATE = """juce::lv2::BundleResource
{{
"{}",
{}
}}
"""
FUNCTION_TEMPLATE = """/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/*
This file is auto-generated by generate_lv2_bundle_sources.py.
*/
#pragma once
#ifndef DOXYGEN
#include <vector>
namespace juce
{{
namespace lv2
{{
struct BundleResource
{{
const char* name;
const char* contents;
}};
struct Bundle
{{
const char* name;
std::vector<BundleResource> contents;
static std::vector<Bundle> getAllBundles();
}};
}}
}}
std::vector<juce::lv2::Bundle> juce::lv2::Bundle::getAllBundles()
{{
return {{
{}
}};
}}
#endif"""
def chunks(lst, n):
for i in range(0, len(lst), n):
yield lst[i:i + n]
def get_chunked_string_literal(s):
return ' '.join(map(lambda x: 'R"lv2ttl({})lv2ttl"'.format(''.join(x)), chunks(s, 8000)))
def get_file_source_string(ttl):
with open(ttl) as f:
return BUNDLE_RESOURCE_TEMPLATE.format(os.path.basename(ttl),
get_chunked_string_literal(f.read()))
def generate_bundle_source(root, files):
if len(files) == 0:
return ""
return BUNDLE_TEMPLATE.format(os.path.basename(root),
", ".join(get_file_source_string(os.path.join(root, ttl)) for ttl in files))
def filter_turtle(files):
return [f for f in files if f.endswith(".ttl")]
def filter_ttl_files(lv2_dir):
for root, _, files in os.walk(args.lv2_dir):
yield root, filter_turtle(files)
parser = argparse.ArgumentParser()
parser.add_argument("lv2_dir")
args = parser.parse_args()
print(FUNCTION_TEMPLATE.format(", ".join(generate_bundle_source(root, files)
for root, files in filter_ttl_files(args.lv2_dir)
if len(files) != 0))
.replace("\t", " "),
end = "\r\n")

View File

@@ -0,0 +1,78 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/*
This header contains preprocessor config flags that would normally be
generated by the build systems of the various LV2 libraries.
Rather than using the generated platform-dependent headers, we use JUCE's
platform detection macros to pick the right config values at build time.
*/
#pragma once
#define LILV_DYN_MANIFEST
#define LILV_STATIC
#define LV2_STATIC
#define SERD_STATIC
#define SORD_STATIC
#define SRATOM_STATIC
#define ZIX_STATIC
#define LILV_VERSION "0.24.12"
#define SERD_VERSION "0.30.10"
#define SORD_VERSION "0.16.9"
#define LILV_CXX 1
#if JUCE_WINDOWS
#define LILV_DIR_SEP "\\"
#define LILV_PATH_SEP ";"
#else
#define LILV_DIR_SEP "/"
#define LILV_PATH_SEP ":"
#endif
#ifndef LILV_DEFAULT_LV2_PATH
#if JUCE_MAC || JUCE_IOS
#define LILV_DEFAULT_LV2_PATH \
"~/Library/Audio/Plug-Ins/LV2" LILV_PATH_SEP \
"~/.lv2" LILV_PATH_SEP \
"/usr/local/lib/lv2" LILV_PATH_SEP \
"/usr/lib/lv2" LILV_PATH_SEP \
"/Library/Audio/Plug-Ins/LV2"
#elif JUCE_WINDOWS
#define LILV_DEFAULT_LV2_PATH \
"%APPDATA%\\LV2" LILV_PATH_SEP \
"%COMMONPROGRAMFILES%\\LV2"
#elif JUCE_LINUX || JUCE_ANDROID
#define LILV_DEFAULT_LV2_PATH \
"~/.lv2" LILV_PATH_SEP \
"/usr/lib/lv2" LILV_PATH_SEP \
"/usr/local/lib/lv2"
#else
#error "Unsupported platform"
#endif
#endif

View File

@@ -0,0 +1,13 @@
Copyright 2011-2021 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,440 @@
/*
Copyright 2007-2017 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LILV_LILVMM_HPP
#define LILV_LILVMM_HPP
#include "lilv/lilv.h"
#include "lv2/core/lv2.h"
#include <cstdarg>
#include <cstdint>
namespace Lilv {
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__GNUC__) && __GNUC__ > 4
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
struct Instance;
struct Node;
struct Nodes;
struct Plugin;
struct PluginClass;
struct PluginClasses;
struct Plugins;
struct Port;
struct ScalePoint;
struct ScalePoints;
struct UI;
struct UIs;
struct World;
LILV_DEPRECATED
static inline const char*
uri_to_path(const char* uri)
{
return lilv_uri_to_path(uri);
}
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__GNUC__) && __GNUC__ > 4
# pragma GCC diagnostic pop
#endif
#define LILV_WRAP0(RT, prefix, name) \
inline RT name() { return lilv_##prefix##_##name(me); }
#define LILV_WRAP0_VOID(prefix, name) \
inline void name() { lilv_##prefix##_##name(me); }
#define LILV_WRAP1(RT, prefix, name, T1, a1) \
inline RT name(T1 a1) { return lilv_##prefix##_##name(me, a1); }
#define LILV_WRAP1_VOID(prefix, name, T1, a1) \
inline void name(T1 a1) { lilv_##prefix##_##name(me, a1); }
#define LILV_WRAP2(RT, prefix, name, T1, a1, T2, a2) \
inline RT name(T1 a1, T2 a2) { return lilv_##prefix##_##name(me, a1, a2); }
#define LILV_WRAP3(RT, prefix, name, T1, a1, T2, a2, T3, a3) \
inline RT name(T1 a1, T2 a2, T3 a3) \
{ \
return lilv_##prefix##_##name(me, a1, a2, a3); \
}
#define LILV_WRAP2_VOID(prefix, name, T1, a1, T2, a2) \
inline void name(T1 a1, T2 a2) { lilv_##prefix##_##name(me, a1, a2); }
#ifndef SWIG
# define LILV_WRAP_CONVERSION(CT) \
inline operator CT*() const { return me; }
#else
# define LILV_WRAP_CONVERSION(CT)
#endif
struct Node {
inline Node(const LilvNode* node)
: me(lilv_node_duplicate(node))
{}
inline Node(const Node& copy)
: me(lilv_node_duplicate(copy.me))
{}
inline Node& operator=(const Node& rhs)
{
if (&rhs != this) {
lilv_node_free(me);
me = lilv_node_duplicate(rhs.me);
}
return *this;
}
inline Node(Node&& other) noexcept
: me(other.me)
{
other.me = nullptr;
}
inline Node& operator=(Node&& rhs) noexcept
{
if (&rhs != this) {
me = rhs.me;
rhs.me = nullptr;
}
return *this;
}
inline ~Node() { lilv_node_free(me); }
inline bool equals(const Node& other) const
{
return lilv_node_equals(me, other.me);
}
inline bool operator==(const Node& other) const { return equals(other); }
LILV_WRAP_CONVERSION(LilvNode);
LILV_WRAP0(char*, node, get_turtle_token);
LILV_WRAP0(bool, node, is_uri);
LILV_WRAP0(const char*, node, as_uri);
LILV_WRAP0(bool, node, is_blank);
LILV_WRAP0(const char*, node, as_blank);
LILV_WRAP0(bool, node, is_literal);
LILV_WRAP0(bool, node, is_string);
LILV_WRAP0(const char*, node, as_string);
LILV_WRAP0(bool, node, is_float);
LILV_WRAP0(float, node, as_float);
LILV_WRAP0(bool, node, is_int);
LILV_WRAP0(int, node, as_int);
LILV_WRAP0(bool, node, is_bool);
LILV_WRAP0(bool, node, as_bool);
LilvNode* me;
};
struct ScalePoint {
inline ScalePoint(const LilvScalePoint* c_obj)
: me(c_obj)
{}
LILV_WRAP_CONVERSION(const LilvScalePoint);
LILV_WRAP0(const LilvNode*, scale_point, get_label);
LILV_WRAP0(const LilvNode*, scale_point, get_value);
const LilvScalePoint* me;
};
struct PluginClass {
inline PluginClass(const LilvPluginClass* c_obj)
: me(c_obj)
{}
LILV_WRAP_CONVERSION(const LilvPluginClass);
LILV_WRAP0(Node, plugin_class, get_parent_uri);
LILV_WRAP0(Node, plugin_class, get_uri);
LILV_WRAP0(Node, plugin_class, get_label);
LILV_WRAP0(LilvPluginClasses*, plugin_class, get_children);
const LilvPluginClass* me;
};
#define LILV_WRAP_COLL(CT, ET, prefix) \
inline CT(const Lilv##CT* c_obj) \
: me(c_obj) \
{} \
LILV_WRAP_CONVERSION(const Lilv##CT); \
LILV_WRAP0(unsigned, prefix, size); \
LILV_WRAP1(ET, prefix, get, LilvIter*, i); \
LILV_WRAP0(LilvIter*, prefix, begin); \
LILV_WRAP1(LilvIter*, prefix, next, LilvIter*, i); \
LILV_WRAP1(bool, prefix, is_end, LilvIter*, i); \
const Lilv##CT* me;
struct PluginClasses {
LILV_WRAP_COLL(PluginClasses, PluginClass, plugin_classes);
LILV_WRAP1(PluginClass, plugin_classes, get_by_uri, const LilvNode*, uri);
};
struct ScalePoints {
LILV_WRAP_COLL(ScalePoints, ScalePoint, scale_points);
};
struct Nodes {
LILV_WRAP_COLL(Nodes, Node, nodes);
LILV_WRAP1(bool, nodes, contains, const Node&, node);
LILV_WRAP0(Node, nodes, get_first);
};
struct UI {
inline UI(const LilvUI* c_obj)
: me(c_obj)
{}
LILV_WRAP_CONVERSION(const LilvUI);
LILV_WRAP0(const LilvNode*, ui, get_uri);
LILV_WRAP0(const LilvNode*, ui, get_bundle_uri);
LILV_WRAP0(const LilvNode*, ui, get_binary_uri);
LILV_WRAP0(const LilvNodes*, ui, get_classes);
/*LILV_WRAP3(bool, ui, is_supported,
LilvUISupportedFunc, supported_func,
const LilvNode*, container_type,
const LilvNode**, ui_type);*/
LILV_WRAP1(bool, ui, is_a, const LilvNode*, class_uri);
const LilvUI* me;
};
struct UIs {
LILV_WRAP_COLL(UIs, UI, uis);
};
struct Port {
inline Port(const LilvPlugin* p, const LilvPort* c_obj)
: parent(p)
, me(c_obj)
{}
LILV_WRAP_CONVERSION(const LilvPort);
#define LILV_PORT_WRAP0(RT, name) \
inline RT name() { return lilv_port_##name(parent, me); }
#define LILV_PORT_WRAP1(RT, name, T1, a1) \
inline RT name(T1 a1) { return lilv_port_##name(parent, me, a1); }
LILV_PORT_WRAP1(LilvNodes*, get_value, LilvNode*, predicate);
LILV_PORT_WRAP0(LilvNodes*, get_properties)
LILV_PORT_WRAP1(bool, has_property, LilvNode*, property_uri);
LILV_PORT_WRAP1(bool, supports_event, LilvNode*, event_uri);
LILV_PORT_WRAP0(const LilvNode*, get_symbol);
LILV_PORT_WRAP0(LilvNode*, get_name);
LILV_PORT_WRAP0(const LilvNodes*, get_classes);
LILV_PORT_WRAP1(bool, is_a, LilvNode*, port_class);
LILV_PORT_WRAP0(LilvScalePoints*, get_scale_points);
// TODO: get_range (output parameters)
const LilvPlugin* parent;
const LilvPort* me;
};
struct Plugin {
inline Plugin(const LilvPlugin* c_obj)
: me(c_obj)
{}
LILV_WRAP_CONVERSION(const LilvPlugin);
LILV_WRAP0(bool, plugin, verify);
LILV_WRAP0(Node, plugin, get_uri);
LILV_WRAP0(Node, plugin, get_bundle_uri);
LILV_WRAP0(Nodes, plugin, get_data_uris);
LILV_WRAP0(Node, plugin, get_library_uri);
LILV_WRAP0(Node, plugin, get_name);
LILV_WRAP0(PluginClass, plugin, get_class);
LILV_WRAP1(Nodes, plugin, get_value, const Node&, pred);
LILV_WRAP1(bool, plugin, has_feature, const Node&, feature_uri);
LILV_WRAP0(Nodes, plugin, get_supported_features);
LILV_WRAP0(Nodes, plugin, get_required_features);
LILV_WRAP0(Nodes, plugin, get_optional_features);
LILV_WRAP0(unsigned, plugin, get_num_ports);
LILV_WRAP0(bool, plugin, has_latency);
LILV_WRAP0(unsigned, plugin, get_latency_port_index);
LILV_WRAP0(Node, plugin, get_author_name);
LILV_WRAP0(Node, plugin, get_author_email);
LILV_WRAP0(Node, plugin, get_author_homepage);
LILV_WRAP0(bool, plugin, is_replaced);
LILV_WRAP0(Nodes, plugin, get_extension_data);
LILV_WRAP0(UIs, plugin, get_uis);
LILV_WRAP1(Nodes, plugin, get_related, const Node&, type);
inline Port get_port_by_index(unsigned index) const
{
return Port(me, lilv_plugin_get_port_by_index(me, index));
}
inline Port get_port_by_symbol(LilvNode* symbol) const
{
return Port(me, lilv_plugin_get_port_by_symbol(me, symbol));
}
inline void get_port_ranges_float(float* min_values,
float* max_values,
float* def_values) const
{
return lilv_plugin_get_port_ranges_float(
me, min_values, max_values, def_values);
}
inline unsigned get_num_ports_of_class(LilvNode* class_1, ...) const
{
va_list args;
va_start(args, class_1);
const uint32_t count =
lilv_plugin_get_num_ports_of_class_va(me, class_1, args);
va_end(args);
return count;
}
const LilvPlugin* me;
};
struct Plugins {
LILV_WRAP_COLL(Plugins, Plugin, plugins);
LILV_WRAP1(Plugin, plugins, get_by_uri, const LilvNode*, uri);
};
struct Instance {
inline Instance(LilvInstance* instance)
: me(instance)
{}
LILV_DEPRECATED
inline Instance(Plugin plugin, double sample_rate)
{
me = lilv_plugin_instantiate(plugin, sample_rate, nullptr);
}
LILV_DEPRECATED inline Instance(Plugin plugin,
double sample_rate,
LV2_Feature* const* features)
{
me = lilv_plugin_instantiate(plugin, sample_rate, features);
}
static inline Instance* create(Plugin plugin,
double sample_rate,
LV2_Feature* const* features)
{
LilvInstance* me = lilv_plugin_instantiate(plugin, sample_rate, features);
return me ? new Instance(me) : nullptr;
}
LILV_WRAP_CONVERSION(LilvInstance);
LILV_WRAP2_VOID(instance,
connect_port,
unsigned,
port_index,
void*,
data_location);
LILV_WRAP0_VOID(instance, activate);
LILV_WRAP1_VOID(instance, run, unsigned, sample_count);
LILV_WRAP0_VOID(instance, deactivate);
inline const void* get_extension_data(const char* uri) const
{
return lilv_instance_get_extension_data(me, uri);
}
inline const LV2_Descriptor* get_descriptor() const
{
return lilv_instance_get_descriptor(me);
}
inline LV2_Handle get_handle() const { return lilv_instance_get_handle(me); }
LilvInstance* me;
};
struct World {
inline World()
: me(lilv_world_new())
{}
inline ~World() { lilv_world_free(me); }
World(const World&) = delete;
World& operator=(const World&) = delete;
World(World&&) = delete;
World& operator=(World&&) = delete;
inline LilvNode* new_uri(const char* uri) const
{
return lilv_new_uri(me, uri);
}
inline LilvNode* new_string(const char* str) const
{
return lilv_new_string(me, str);
}
inline LilvNode* new_int(int val) const { return lilv_new_int(me, val); }
inline LilvNode* new_float(float val) const
{
return lilv_new_float(me, val);
}
inline LilvNode* new_bool(bool val) const { return lilv_new_bool(me, val); }
inline Nodes find_nodes(const LilvNode* subject,
const LilvNode* predicate,
const LilvNode* object) const
{
return lilv_world_find_nodes(me, subject, predicate, object);
}
LILV_WRAP2_VOID(world, set_option, const char*, uri, LilvNode*, value);
LILV_WRAP0_VOID(world, load_all);
LILV_WRAP1_VOID(world, load_bundle, LilvNode*, bundle_uri);
LILV_WRAP0(const LilvPluginClass*, world, get_plugin_class);
LILV_WRAP0(const LilvPluginClasses*, world, get_plugin_classes);
LILV_WRAP0(Plugins, world, get_all_plugins);
LILV_WRAP1(int, world, load_resource, const LilvNode*, resource);
LilvWorld* me;
};
} /* namespace Lilv */
#endif /* LILV_LILVMM_HPP */

View File

@@ -0,0 +1,240 @@
/*
Copyright 2008-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "sord/sord.h"
#include "zix/common.h"
#include "zix/tree.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
int
lilv_ptr_cmp(const void* a, const void* b, const void* user_data)
{
(void)user_data;
return (intptr_t)a - (intptr_t)b;
}
int
lilv_resource_node_cmp(const void* a, const void* b, const void* user_data)
{
(void)user_data;
const SordNode* an = ((const LilvNode*)a)->node;
const SordNode* bn = ((const LilvNode*)b)->node;
return (intptr_t)an - (intptr_t)bn;
}
/* Generic collection functions */
static inline LilvCollection*
lilv_collection_new(ZixComparator cmp, ZixDestroyFunc destructor)
{
return zix_tree_new(false, cmp, NULL, destructor);
}
void
lilv_collection_free(LilvCollection* collection)
{
if (collection) {
zix_tree_free((ZixTree*)collection);
}
}
unsigned
lilv_collection_size(const LilvCollection* collection)
{
return (collection ? zix_tree_size((const ZixTree*)collection) : 0);
}
LilvIter*
lilv_collection_begin(const LilvCollection* collection)
{
return collection ? (LilvIter*)zix_tree_begin((ZixTree*)collection) : NULL;
}
void*
lilv_collection_get(const LilvCollection* collection, const LilvIter* i)
{
(void)collection;
return zix_tree_get((const ZixTreeIter*)i);
}
/* Constructors */
LilvScalePoints*
lilv_scale_points_new(void)
{
return lilv_collection_new(lilv_ptr_cmp,
(ZixDestroyFunc)lilv_scale_point_free);
}
LilvNodes*
lilv_nodes_new(void)
{
return lilv_collection_new(lilv_ptr_cmp, (ZixDestroyFunc)lilv_node_free);
}
LilvUIs*
lilv_uis_new(void)
{
return lilv_collection_new(lilv_header_compare_by_uri,
(ZixDestroyFunc)lilv_ui_free);
}
LilvPluginClasses*
lilv_plugin_classes_new(void)
{
return lilv_collection_new(lilv_header_compare_by_uri,
(ZixDestroyFunc)lilv_plugin_class_free);
}
/* URI based accessors (for collections of things with URIs) */
const LilvPluginClass*
lilv_plugin_classes_get_by_uri(const LilvPluginClasses* classes,
const LilvNode* uri)
{
return (LilvPluginClass*)lilv_collection_get_by_uri((const ZixTree*)classes,
uri);
}
const LilvUI*
lilv_uis_get_by_uri(const LilvUIs* uis, const LilvNode* uri)
{
return (LilvUI*)lilv_collection_get_by_uri((const ZixTree*)uis, uri);
}
/* Plugins */
LilvPlugins*
lilv_plugins_new(void)
{
return lilv_collection_new(lilv_header_compare_by_uri, NULL);
}
const LilvPlugin*
lilv_plugins_get_by_uri(const LilvPlugins* plugins, const LilvNode* uri)
{
return (LilvPlugin*)lilv_collection_get_by_uri((const ZixTree*)plugins, uri);
}
/* Nodes */
bool
lilv_nodes_contains(const LilvNodes* nodes, const LilvNode* value)
{
LILV_FOREACH (nodes, i, nodes) {
if (lilv_node_equals(lilv_nodes_get(nodes, i), value)) {
return true;
}
}
return false;
}
LilvNodes*
lilv_nodes_merge(const LilvNodes* a, const LilvNodes* b)
{
LilvNodes* result = lilv_nodes_new();
LILV_FOREACH (nodes, i, a) {
zix_tree_insert(
(ZixTree*)result, lilv_node_duplicate(lilv_nodes_get(a, i)), NULL);
}
LILV_FOREACH (nodes, i, b) {
zix_tree_insert(
(ZixTree*)result, lilv_node_duplicate(lilv_nodes_get(b, i)), NULL);
}
return result;
}
/* Iterator */
#define LILV_COLLECTION_IMPL(prefix, CT, ET) \
\
unsigned prefix##_size(const CT* collection) \
{ \
return lilv_collection_size(collection); \
} \
\
LilvIter* prefix##_begin(const CT* collection) \
{ \
return lilv_collection_begin(collection); \
} \
\
const ET* prefix##_get(const CT* collection, LilvIter* i) \
{ \
return (ET*)lilv_collection_get(collection, i); \
} \
\
LilvIter* prefix##_next(const CT* collection, LilvIter* i) \
{ \
(void)collection; \
return zix_tree_iter_next((ZixTreeIter*)i); \
} \
\
bool prefix##_is_end(const CT* collection, LilvIter* i) \
{ \
(void)collection; \
return zix_tree_iter_is_end((ZixTreeIter*)i); \
}
LILV_COLLECTION_IMPL(lilv_plugin_classes, LilvPluginClasses, LilvPluginClass)
LILV_COLLECTION_IMPL(lilv_scale_points, LilvScalePoints, LilvScalePoint)
LILV_COLLECTION_IMPL(lilv_uis, LilvUIs, LilvUI)
LILV_COLLECTION_IMPL(lilv_nodes, LilvNodes, LilvNode)
LILV_COLLECTION_IMPL(lilv_plugins, LilvPlugins, LilvPlugin)
void
lilv_plugin_classes_free(LilvPluginClasses* collection)
{
lilv_collection_free(collection);
}
void
lilv_scale_points_free(LilvScalePoints* collection)
{
lilv_collection_free(collection);
}
void
lilv_uis_free(LilvUIs* collection)
{
lilv_collection_free(collection);
}
void
lilv_nodes_free(LilvNodes* collection)
{
lilv_collection_free(collection);
}
LilvNode*
lilv_nodes_get_first(const LilvNodes* collection)
{
return (LilvNode*)lilv_collection_get(collection,
lilv_collection_begin(collection));
}

View File

@@ -0,0 +1,564 @@
/*
Copyright 2007-2021 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define _POSIX_C_SOURCE 200809L /* for fileno */
#define _BSD_SOURCE 1 /* for realpath, symlink */
#define _DEFAULT_SOURCE 1 /* for realpath, symlink */
#ifdef __APPLE__
# define _DARWIN_C_SOURCE 1 /* for flock */
#endif
#include "filesystem.h"
#include "lilv_config.h"
#include "lilv_internal.h"
#ifdef _WIN32
# include <direct.h>
# include <io.h>
# include <windows.h>
# define F_OK 0
# define mkdir(path, flags) _mkdir(path)
# define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
#else
# include <dirent.h>
# include <unistd.h>
#endif
#if USE_FLOCK && USE_FILENO
# include <sys/file.h>
#endif
#include <sys/stat.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef PAGE_SIZE
# define PAGE_SIZE 4096
#endif
static bool
lilv_is_dir_sep(const char c)
{
return c == '/' || c == LILV_DIR_SEP[0];
}
#ifdef _WIN32
static inline bool
is_windows_path(const char* path)
{
return (isalpha(path[0]) && (path[1] == ':' || path[1] == '|') &&
(path[2] == '/' || path[2] == '\\'));
}
#endif
char*
lilv_temp_directory_path(void)
{
#ifdef _WIN32
DWORD len = GetTempPath(0, NULL);
char* buf = (char*)calloc(len, 1);
if (GetTempPath(len, buf) == 0) {
free(buf);
return NULL;
}
return buf;
#else
const char* const tmpdir = getenv("TMPDIR");
return tmpdir ? lilv_strdup(tmpdir) : lilv_strdup("/tmp");
#endif
}
bool
lilv_path_is_absolute(const char* path)
{
if (lilv_is_dir_sep(path[0])) {
return true;
}
#ifdef _WIN32
if (is_windows_path(path)) {
return true;
}
#endif
return false;
}
bool
lilv_path_is_child(const char* path, const char* dir)
{
if (path && dir) {
const size_t path_len = strlen(path);
const size_t dir_len = strlen(dir);
return dir && path_len >= dir_len && !strncmp(path, dir, dir_len);
}
return false;
}
char*
lilv_path_current(void)
{
return getcwd(NULL, 0);
}
char*
lilv_path_absolute(const char* path)
{
if (lilv_path_is_absolute(path)) {
return lilv_strdup(path);
}
char* cwd = getcwd(NULL, 0);
char* abs_path = lilv_path_join(cwd, path);
free(cwd);
return abs_path;
}
char*
lilv_path_absolute_child(const char* path, const char* parent)
{
if (lilv_path_is_absolute(path)) {
return lilv_strdup(path);
}
return lilv_path_join(parent, path);
}
char*
lilv_path_relative_to(const char* path, const char* base)
{
const size_t path_len = strlen(path);
const size_t base_len = strlen(base);
const size_t min_len = (path_len < base_len) ? path_len : base_len;
// Find the last separator common to both paths
size_t last_shared_sep = 0;
for (size_t i = 0; i < min_len && path[i] == base[i]; ++i) {
if (lilv_is_dir_sep(path[i])) {
last_shared_sep = i;
}
}
if (last_shared_sep == 0) {
// No common components, return path
return lilv_strdup(path);
}
// Find the number of up references ("..") required
size_t up = 0;
for (size_t i = last_shared_sep + 1; i < base_len; ++i) {
if (lilv_is_dir_sep(base[i])) {
++up;
}
}
#ifdef _WIN32
const bool use_slash = strchr(path, '/');
#else
static const bool use_slash = true;
#endif
// Write up references
const size_t suffix_len = path_len - last_shared_sep;
char* rel = (char*)calloc(1, suffix_len + (up * 3) + 1);
for (size_t i = 0; i < up; ++i) {
if (use_slash) {
memcpy(rel + (i * 3), "../", 3);
} else {
memcpy(rel + (i * 3), "..\\", 3);
}
}
// Write suffix
memcpy(rel + (up * 3), path + last_shared_sep + 1, suffix_len);
return rel;
}
char*
lilv_path_parent(const char* path)
{
const char* s = path + strlen(path) - 1; // Last character
// Last non-slash
for (; s > path && lilv_is_dir_sep(*s); --s) {
}
// Last internal slash
for (; s > path && !lilv_is_dir_sep(*s); --s) {
}
// Skip duplicates
for (; s > path && lilv_is_dir_sep(*s); --s) {
}
if (s == path) { // Hit beginning
return lilv_is_dir_sep(*s) ? lilv_strdup("/") : lilv_strdup(".");
}
// Pointing to the last character of the result (inclusive)
char* dirname = (char*)malloc(s - path + 2);
memcpy(dirname, path, s - path + 1);
dirname[s - path + 1] = '\0';
return dirname;
}
char*
lilv_path_filename(const char* path)
{
const size_t path_len = strlen(path);
size_t last_sep = path_len;
for (size_t i = 0; i < path_len; ++i) {
if (lilv_is_dir_sep(path[i])) {
last_sep = i;
}
}
if (last_sep >= path_len) {
return lilv_strdup(path);
}
const size_t ret_len = path_len - last_sep;
char* const ret = (char*)calloc(ret_len + 1, 1);
strncpy(ret, path + last_sep + 1, ret_len);
return ret;
}
char*
lilv_path_join(const char* a, const char* b)
{
if (!a) {
return (b && b[0]) ? lilv_strdup(b) : NULL;
}
const size_t a_len = strlen(a);
const size_t b_len = b ? strlen(b) : 0;
const bool a_end_is_sep = a_len > 0 && lilv_is_dir_sep(a[a_len - 1]);
const size_t pre_len = a_len - (a_end_is_sep ? 1 : 0);
char* path = (char*)calloc(1, a_len + b_len + 2);
memcpy(path, a, pre_len);
#ifdef _WIN32
// Use forward slash if it seems that the input paths do
const bool a_has_slash = strchr(a, '/');
const bool b_has_slash = b && strchr(b, '/');
if (a_has_slash || b_has_slash) {
path[pre_len] = '/';
} else {
path[pre_len] = '\\';
}
#else
path[pre_len] = '/';
#endif
if (b) {
memcpy(path + pre_len + 1,
b + (lilv_is_dir_sep(b[0]) ? 1 : 0),
lilv_is_dir_sep(b[0]) ? b_len - 1 : b_len);
}
return path;
}
char*
lilv_path_canonical(const char* path)
{
if (!path) {
return NULL;
}
#if defined(_WIN32)
char* out = (char*)malloc(MAX_PATH);
GetFullPathName(path, MAX_PATH, out, NULL);
return out;
#else
char* real_path = realpath(path, NULL);
return real_path ? real_path : lilv_strdup(path);
#endif
}
bool
lilv_path_exists(const char* path)
{
#if USE_LSTAT
struct stat st;
return !lstat(path, &st);
#else
return !access(path, F_OK);
#endif
}
bool
lilv_is_directory(const char* path)
{
struct stat st;
return !stat(path, &st) && S_ISDIR(st.st_mode);
}
int
lilv_copy_file(const char* src, const char* dst)
{
FILE* in = fopen(src, "r");
if (!in) {
return errno;
}
FILE* out = fopen(dst, "w");
if (!out) {
fclose(in);
return errno;
}
char* page = (char*)malloc(PAGE_SIZE);
size_t n_read = 0;
int st = 0;
while ((n_read = fread(page, 1, PAGE_SIZE, in)) > 0) {
if (fwrite(page, 1, n_read, out) != n_read) {
st = errno;
break;
}
}
if (!st && fflush(out)) {
st = errno;
}
if (!st && (ferror(in) || ferror(out))) {
st = EBADF;
}
free(page);
fclose(in);
fclose(out);
return st;
}
int
lilv_symlink(const char* oldpath, const char* newpath)
{
int ret = 0;
if (strcmp(oldpath, newpath)) {
#ifdef _WIN32
ret = !CreateHardLink(newpath, oldpath, 0);
#else
char* target = lilv_path_relative_to(oldpath, newpath);
ret = symlink(target, newpath);
free(target);
#endif
}
return ret;
}
int
lilv_flock(FILE* file, bool lock, bool block)
{
#ifdef _WIN32
HANDLE handle = (HANDLE)_get_osfhandle(fileno(file));
OVERLAPPED overlapped = {0};
if (lock) {
const DWORD flags =
(LOCKFILE_EXCLUSIVE_LOCK | (block ? 0 : LOCKFILE_FAIL_IMMEDIATELY));
return !LockFileEx(handle, flags, 0, UINT32_MAX, UINT32_MAX, &overlapped);
} else {
return !UnlockFileEx(handle, 0, UINT32_MAX, UINT32_MAX, &overlapped);
}
#elif USE_FLOCK && USE_FILENO
return flock(fileno(file),
(lock ? LOCK_EX : LOCK_UN) | (block ? 0 : LOCK_NB));
#else
return 0;
#endif
}
void
lilv_dir_for_each(const char* path,
void* data,
void (*f)(const char* path, const char* name, void* data))
{
#ifdef _WIN32
char* pat = lilv_path_join(path, "*");
WIN32_FIND_DATA fd;
HANDLE fh = FindFirstFile(pat, &fd);
if (fh != INVALID_HANDLE_VALUE) {
do {
if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")) {
f(path, fd.cFileName, data);
}
} while (FindNextFile(fh, &fd));
}
FindClose(fh);
free(pat);
#else
DIR* dir = opendir(path);
if (dir) {
for (struct dirent* entry = NULL; (entry = readdir(dir));) {
if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
f(path, entry->d_name, data);
}
}
closedir(dir);
}
#endif
}
char*
lilv_create_temporary_directory_in(const char* pattern, const char* parent)
{
#ifdef _WIN32
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const int n_chars = sizeof(chars) - 1;
const size_t pattern_len = strlen(pattern);
if (pattern_len < 7 || strcmp(pattern + pattern_len - 6, "XXXXXX")) {
errno = EINVAL;
return NULL;
}
char* const path_pattern = lilv_path_join(parent, pattern);
const size_t path_pattern_len = strlen(path_pattern);
char* const suffix = path_pattern + path_pattern_len - 6;
for (unsigned attempt = 0; attempt < 128; ++attempt) {
for (unsigned i = 0; i < 6; ++i) {
suffix[i] = chars[rand() % n_chars];
}
if (!mkdir(path_pattern, 0700)) {
return path_pattern;
}
}
return NULL;
#else
char* const path_pattern = lilv_path_join(parent, pattern);
return mkdtemp(path_pattern); // NOLINT (not a leak)
#endif
}
char*
lilv_create_temporary_directory(const char* pattern)
{
char* const tmpdir = lilv_temp_directory_path();
char* const result = lilv_create_temporary_directory_in(pattern, tmpdir);
free(tmpdir);
return result;
}
int
lilv_create_directories(const char* dir_path)
{
char* path = lilv_strdup(dir_path);
const size_t path_len = strlen(path);
size_t i = 1;
#ifdef _WIN32
if (is_windows_path(dir_path)) {
i = 3;
}
#endif
for (; i <= path_len; ++i) {
const char c = path[i];
if (c == LILV_DIR_SEP[0] || c == '/' || c == '\0') {
path[i] = '\0';
if (mkdir(path, 0755) && (errno != EEXIST || !lilv_is_directory(path))) {
free(path);
return errno;
}
path[i] = c;
}
}
free(path);
return 0;
}
static off_t
lilv_file_size(const char* path)
{
struct stat buf;
if (stat(path, &buf)) {
return 0;
}
return buf.st_size;
}
int
lilv_remove(const char* path)
{
#ifdef _WIN32
if (lilv_is_directory(path)) {
return !RemoveDirectory(path);
}
#endif
return remove(path);
}
bool
lilv_file_equals(const char* a_path, const char* b_path)
{
if (!strcmp(a_path, b_path)) {
return true; // Paths match
}
bool match = false;
FILE* a_file = NULL;
FILE* b_file = NULL;
char* const a_real = lilv_path_canonical(a_path);
char* const b_real = lilv_path_canonical(b_path);
if (!strcmp(a_real, b_real)) {
match = true; // Real paths match
} else if (lilv_file_size(a_path) != lilv_file_size(b_path)) {
match = false; // Sizes differ
} else if (!(a_file = fopen(a_real, "rb")) ||
!(b_file = fopen(b_real, "rb"))) {
match = false; // Missing file matches nothing
} else {
// TODO: Improve performance by reading chunks
match = true;
while (!feof(a_file) && !feof(b_file)) {
if (fgetc(a_file) != fgetc(b_file)) {
match = false;
break;
}
}
}
if (a_file) {
fclose(a_file);
}
if (b_file) {
fclose(b_file);
}
free(a_real);
free(b_real);
return match;
}

View File

@@ -0,0 +1,182 @@
/*
Copyright 2007-2020 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdbool.h>
#include <stdio.h>
/// Return the path to a directory suitable for making temporary files
char*
lilv_temp_directory_path(void);
/// Return true iff `path` is an absolute path
bool
lilv_path_is_absolute(const char* path);
/// Return true iff `path` is a child of `dir`
bool
lilv_path_is_child(const char* path, const char* dir);
/// Return the current working directory
char*
lilv_path_current(void);
/**
Return `path` as an absolute path.
If `path` is absolute, an identical copy of it is returned. Otherwise, the
returned path is relative to the current working directory.
*/
char*
lilv_path_absolute(const char* path);
/**
Return `path` as an absolute path relative to `parent`.
If `path` is absolute, an identical copy of it is returned. Otherwise, the
returned path is relative to `parent`.
*/
char*
lilv_path_absolute_child(const char* path, const char* parent);
/**
Return `path` relative to `base` if possible.
If `path` is not within `base`, a copy is returned. Otherwise, an
equivalent path relative to `base` is returned (which may contain
up-references).
*/
char*
lilv_path_relative_to(const char* path, const char* base);
/**
Return the path to the directory that contains `path`.
Returns the root path if `path` is the root path.
*/
char*
lilv_path_parent(const char* path);
/**
Return the filename component of `path` without any directories.
Returns the empty string if `path` is the root path.
*/
char*
lilv_path_filename(const char* path);
/// Join path `a` and path `b` with a single directory separator between them
char*
lilv_path_join(const char* a, const char* b);
/**
Return `path` as a canonicalized absolute path.
This expands all symbolic links, relative references, and removes extra
directory separators.
*/
char*
lilv_path_canonical(const char* path);
/// Return true iff `path` points to an existing file system entry
bool
lilv_path_exists(const char* path);
/// Return true iff `path` points to an existing directory
bool
lilv_is_directory(const char* path);
/**
Copy the file at path `src` to path `dst`.
@return Zero on success, or a standard `errno` error code.
*/
int
lilv_copy_file(const char* src, const char* dst);
/**
Create a symlink at `newpath` that points to `oldpath`.
@return Zero on success, otherwise non-zero and `errno` is set.
*/
int
lilv_symlink(const char* oldpath, const char* newpath);
/**
Set or remove an advisory exclusive lock on `file`.
If the `lock` is true and the file is already locked by another process, or
by this process via a different file handle, then this will not succeed and
non-zero will be returned.
@param file Handle for open file to lock.
@param lock True to set lock, false to release lock.
@param block If true, then this call will block until the lock is acquired.
@return Zero on success.
*/
int
lilv_flock(FILE* file, bool lock, bool block);
/**
Visit every file in the directory at `path`.
@param path A path to a directory.
@param data Opaque user data that is passed to `f`.
@param f A function called on every entry in the directory. The `path`
parameter is always the directory path passed to this function, the `name`
parameter is the name of the directory entry (not its full path).
*/
void
lilv_dir_for_each(const char* path,
void* data,
void (*f)(const char* path, const char* name, void* data));
/**
Create a unique temporary directory in a specific directory.
The last six characters of `pattern` must be `XXXXXX` and will be replaced
with random characters. This works roughly like mkdtemp, except the pattern
should only be a directory name, not a full path. The created path will be
a child of the given parent directory.
*/
char*
lilv_create_temporary_directory_in(const char* pattern, const char* parent);
/**
Create a unique temporary directory.
This is like lilv_create_temporary_directory_in(), except it creates the
directory in the system temporary directory.
*/
char*
lilv_create_temporary_directory(const char* pattern);
/**
Create the directory `dir_path` and any parent directories if necessary.
@return Zero on success, or an `errno` error code.
*/
int
lilv_create_directories(const char* dir_path);
/// Remove the file or empty directory at `path`
int
lilv_remove(const char* path);
/// Return true iff the given paths point to files with identical contents
bool
lilv_file_equals(const char* a_path, const char* b_path);

View File

@@ -0,0 +1,115 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "lv2/core/lv2.h"
#include "serd/serd.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
LilvInstance*
lilv_plugin_instantiate(const LilvPlugin* plugin,
double sample_rate,
const LV2_Feature* const* features)
{
lilv_plugin_load_if_necessary(plugin);
if (plugin->parse_errors) {
return NULL;
}
LilvInstance* result = NULL;
const LilvNode* const lib_uri = lilv_plugin_get_library_uri(plugin);
const LilvNode* const bundle_uri = lilv_plugin_get_bundle_uri(plugin);
if (!lib_uri || !bundle_uri) {
return NULL;
}
char* const bundle_path =
lilv_file_uri_parse(lilv_node_as_uri(bundle_uri), NULL);
LilvLib* lib = lilv_lib_open(plugin->world, lib_uri, bundle_path, features);
if (!lib) {
serd_free(bundle_path);
return NULL;
}
const LV2_Feature** local_features = NULL;
if (features == NULL) {
local_features = (const LV2_Feature**)malloc(sizeof(LV2_Feature*));
local_features[0] = NULL;
}
// Search for plugin by URI
for (uint32_t i = 0; true; ++i) {
const LV2_Descriptor* ld = lilv_lib_get_plugin(lib, i);
if (!ld) {
LILV_ERRORF("No plugin <%s> in <%s>\n",
lilv_node_as_uri(lilv_plugin_get_uri(plugin)),
lilv_node_as_uri(lib_uri));
lilv_lib_close(lib);
break; // return NULL
}
if (!strcmp(ld->URI, lilv_node_as_uri(lilv_plugin_get_uri(plugin)))) {
// Create LilvInstance to return
result = (LilvInstance*)malloc(sizeof(LilvInstance));
result->lv2_descriptor = ld;
result->lv2_handle = ld->instantiate(
ld, sample_rate, bundle_path, (features) ? features : local_features);
result->pimpl = lib;
break;
}
}
free(local_features);
serd_free(bundle_path);
if (result) {
if (result->lv2_handle == NULL) {
// Failed to instantiate
free(result);
lilv_lib_close(lib);
return NULL;
}
// "Connect" all ports to NULL (catches bugs)
for (uint32_t i = 0; i < lilv_plugin_get_num_ports(plugin); ++i) {
result->lv2_descriptor->connect_port(result->lv2_handle, i, NULL);
}
}
return result;
}
void
lilv_instance_free(LilvInstance* instance)
{
if (!instance) {
return;
}
instance->lv2_descriptor->cleanup(instance->lv2_handle);
instance->lv2_descriptor = NULL;
lilv_lib_close((LilvLib*)instance->pimpl);
instance->pimpl = NULL;
free(instance);
}

View File

@@ -0,0 +1,127 @@
/*
Copyright 2012-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "lv2/core/lv2.h"
#include "serd/serd.h"
#include "zix/tree.h"
#ifndef _WIN32
# include <dlfcn.h>
#endif
#include <stdint.h>
#include <stdlib.h>
LilvLib*
lilv_lib_open(LilvWorld* world,
const LilvNode* uri,
const char* bundle_path,
const LV2_Feature* const* features)
{
ZixTreeIter* i = NULL;
const LilvLib key = {
world, (LilvNode*)uri, (char*)bundle_path, NULL, NULL, NULL, 0};
if (!zix_tree_find(world->libs, &key, &i)) {
LilvLib* llib = (LilvLib*)zix_tree_get(i);
++llib->refs;
return llib;
}
const char* const lib_uri = lilv_node_as_uri(uri);
char* const lib_path =
(char*)serd_file_uri_parse((const uint8_t*)lib_uri, NULL);
if (!lib_path) {
return NULL;
}
dlerror();
void* lib = dlopen(lib_path, RTLD_NOW);
if (!lib) {
LILV_ERRORF("Failed to open library %s (%s)\n", lib_path, dlerror());
serd_free(lib_path);
return NULL;
}
LV2_Descriptor_Function df =
(LV2_Descriptor_Function)lilv_dlfunc(lib, "lv2_descriptor");
LV2_Lib_Descriptor_Function ldf =
(LV2_Lib_Descriptor_Function)lilv_dlfunc(lib, "lv2_lib_descriptor");
const LV2_Lib_Descriptor* desc = NULL;
if (ldf) {
desc = ldf(bundle_path, features);
if (!desc) {
LILV_ERRORF("Call to %s:lv2_lib_descriptor failed\n", lib_path);
dlclose(lib);
serd_free(lib_path);
return NULL;
}
} else if (!df) {
LILV_ERRORF("No `lv2_descriptor' or `lv2_lib_descriptor' in %s\n",
lib_path);
dlclose(lib);
serd_free(lib_path);
return NULL;
}
serd_free(lib_path);
LilvLib* llib = (LilvLib*)malloc(sizeof(LilvLib));
llib->world = world;
llib->uri = lilv_node_duplicate(uri);
llib->bundle_path = lilv_strdup(bundle_path);
llib->lib = lib;
llib->lv2_descriptor = df;
llib->desc = desc;
llib->refs = 1;
zix_tree_insert(world->libs, llib, NULL);
return llib;
}
const LV2_Descriptor*
lilv_lib_get_plugin(LilvLib* lib, uint32_t index)
{
if (lib->lv2_descriptor) {
return lib->lv2_descriptor(index);
}
if (lib->desc) {
return lib->desc->get_plugin(lib->desc->handle, index);
}
return NULL;
}
void
lilv_lib_close(LilvLib* lib)
{
if (--lib->refs == 0) {
dlclose(lib->lib);
ZixTreeIter* i = NULL;
if (lib->world->libs && !zix_tree_find(lib->world->libs, lib, &i)) {
zix_tree_remove(lib->world->libs, i);
}
lilv_node_free(lib->uri);
free(lib->bundle_path);
free(lib);
}
}

View File

@@ -0,0 +1,477 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LILV_INTERNAL_H
#define LILV_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
#include "lilv_config.h" // IWYU pragma: keep
#include "lilv/lilv.h"
#include "lv2/core/lv2.h"
#include "serd/serd.h"
#include "sord/sord.h"
#include "zix/tree.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#ifdef _WIN32
# include <direct.h>
# include <stdio.h>
# include <windows.h>
# define dlopen(path, flags) LoadLibrary(path)
# define dlclose(lib) FreeLibrary((HMODULE)lib)
# ifdef _MSC_VER
# define __func__ __FUNCTION__
# ifndef snprintf
# define snprintf _snprintf
# endif
# endif
# ifndef INFINITY
# define INFINITY DBL_MAX + DBL_MAX
# endif
# ifndef NAN
# define NAN INFINITY - INFINITY
# endif
static inline const char*
dlerror(void)
{
return "Unknown error";
}
#else
# include <dlfcn.h>
#endif
#ifdef LILV_DYN_MANIFEST
# include "lv2/dynmanifest/dynmanifest.h"
#endif
/*
*
* Types
*
*/
typedef void LilvCollection;
struct LilvPortImpl {
LilvNode* node; ///< RDF node
uint32_t index; ///< lv2:index
LilvNode* symbol; ///< lv2:symbol
LilvNodes* classes; ///< rdf:type
};
typedef struct LilvSpecImpl {
SordNode* spec;
SordNode* bundle;
LilvNodes* data_uris;
struct LilvSpecImpl* next;
} LilvSpec;
/**
Header of an LilvPlugin, LilvPluginClass, or LilvUI.
Any of these structs may be safely casted to LilvHeader, which is used to
implement collections using the same comparator.
*/
struct LilvHeader {
LilvWorld* world;
LilvNode* uri;
};
#ifdef LILV_DYN_MANIFEST
typedef struct {
LilvNode* bundle;
void* lib;
LV2_Dyn_Manifest_Handle handle;
uint32_t refs;
} LilvDynManifest;
#endif
typedef struct {
LilvWorld* world;
LilvNode* uri;
char* bundle_path;
void* lib;
LV2_Descriptor_Function lv2_descriptor;
const LV2_Lib_Descriptor* desc;
uint32_t refs;
} LilvLib;
struct LilvPluginImpl {
LilvWorld* world;
LilvNode* plugin_uri;
LilvNode* bundle_uri; ///< Bundle plugin was loaded from
LilvNode* binary_uri; ///< lv2:binary
#ifdef LILV_DYN_MANIFEST
LilvDynManifest* dynmanifest;
#endif
const LilvPluginClass* plugin_class;
LilvNodes* data_uris; ///< rdfs::seeAlso
LilvPort** ports;
uint32_t num_ports;
bool loaded;
bool parse_errors;
bool replaced;
};
struct LilvPluginClassImpl {
LilvWorld* world;
LilvNode* uri;
LilvNode* parent_uri;
LilvNode* label;
};
struct LilvInstancePimpl {
LilvWorld* world;
LilvLib* lib;
};
typedef struct {
bool dyn_manifest;
bool filter_language;
char* lv2_path;
} LilvOptions;
struct LilvWorldImpl {
SordWorld* world;
SordModel* model;
SerdReader* reader;
unsigned n_read_files;
LilvPluginClass* lv2_plugin_class;
LilvPluginClasses* plugin_classes;
LilvSpec* specs;
LilvPlugins* plugins;
LilvPlugins* zombies;
LilvNodes* loaded_files;
ZixTree* libs;
struct {
SordNode* dc_replaces;
SordNode* dman_DynManifest;
SordNode* doap_name;
SordNode* lv2_Plugin;
SordNode* lv2_Specification;
SordNode* lv2_appliesTo;
SordNode* lv2_binary;
SordNode* lv2_default;
SordNode* lv2_designation;
SordNode* lv2_extensionData;
SordNode* lv2_index;
SordNode* lv2_latency;
SordNode* lv2_maximum;
SordNode* lv2_microVersion;
SordNode* lv2_minimum;
SordNode* lv2_minorVersion;
SordNode* lv2_name;
SordNode* lv2_optionalFeature;
SordNode* lv2_port;
SordNode* lv2_portProperty;
SordNode* lv2_reportsLatency;
SordNode* lv2_requiredFeature;
SordNode* lv2_symbol;
SordNode* lv2_prototype;
SordNode* owl_Ontology;
SordNode* pset_value;
SordNode* rdf_a;
SordNode* rdf_value;
SordNode* rdfs_Class;
SordNode* rdfs_label;
SordNode* rdfs_seeAlso;
SordNode* rdfs_subClassOf;
SordNode* xsd_base64Binary;
SordNode* xsd_boolean;
SordNode* xsd_decimal;
SordNode* xsd_double;
SordNode* xsd_integer;
SordNode* null_uri;
} uris;
LilvOptions opt;
};
typedef enum {
LILV_VALUE_URI,
LILV_VALUE_STRING,
LILV_VALUE_INT,
LILV_VALUE_FLOAT,
LILV_VALUE_BOOL,
LILV_VALUE_BLANK,
LILV_VALUE_BLOB
} LilvNodeType;
struct LilvNodeImpl {
LilvWorld* world;
SordNode* node;
LilvNodeType type;
union {
int int_val;
float float_val;
bool bool_val;
} val;
};
struct LilvScalePointImpl {
LilvNode* value;
LilvNode* label;
};
struct LilvUIImpl {
LilvWorld* world;
LilvNode* uri;
LilvNode* bundle_uri;
LilvNode* binary_uri;
LilvNodes* classes;
};
typedef struct LilvVersion {
int minor;
int micro;
} LilvVersion;
/*
*
* Functions
*
*/
LilvPort*
lilv_port_new(LilvWorld* world,
const SordNode* node,
uint32_t index,
const char* symbol);
void
lilv_port_free(const LilvPlugin* plugin, LilvPort* port);
LilvPlugin*
lilv_plugin_new(LilvWorld* world, LilvNode* uri, LilvNode* bundle_uri);
void
lilv_plugin_clear(LilvPlugin* plugin, LilvNode* bundle_uri);
void
lilv_plugin_load_if_necessary(const LilvPlugin* plugin);
void
lilv_plugin_free(LilvPlugin* plugin);
LilvNode*
lilv_plugin_get_unique(const LilvPlugin* plugin,
const SordNode* subject,
const SordNode* predicate);
void
lilv_collection_free(LilvCollection* collection);
unsigned
lilv_collection_size(const LilvCollection* collection);
LilvIter*
lilv_collection_begin(const LilvCollection* collection);
void*
lilv_collection_get(const LilvCollection* collection, const LilvIter* i);
LilvPluginClass*
lilv_plugin_class_new(LilvWorld* world,
const SordNode* parent_node,
const SordNode* uri,
const char* label);
void
lilv_plugin_class_free(LilvPluginClass* plugin_class);
LilvLib*
lilv_lib_open(LilvWorld* world,
const LilvNode* uri,
const char* bundle_path,
const LV2_Feature* const* features);
const LV2_Descriptor*
lilv_lib_get_plugin(LilvLib* lib, uint32_t index);
void
lilv_lib_close(LilvLib* lib);
LilvNodes*
lilv_nodes_new(void);
LilvPlugins*
lilv_plugins_new(void);
LilvScalePoints*
lilv_scale_points_new(void);
LilvPluginClasses*
lilv_plugin_classes_new(void);
LilvUIs*
lilv_uis_new(void);
LilvNode*
lilv_world_get_manifest_uri(LilvWorld* world, const LilvNode* bundle_uri);
const uint8_t*
lilv_world_blank_node_prefix(LilvWorld* world);
SerdStatus
lilv_world_load_file(LilvWorld* world, SerdReader* reader, const LilvNode* uri);
SerdStatus
lilv_world_load_graph(LilvWorld* world, SordNode* graph, const LilvNode* uri);
LilvUI*
lilv_ui_new(LilvWorld* world,
LilvNode* uri,
LilvNode* type_uri,
LilvNode* binary_uri);
void
lilv_ui_free(LilvUI* ui);
LilvNode*
lilv_node_new(LilvWorld* world, LilvNodeType type, const char* str);
LilvNode*
lilv_node_new_from_node(LilvWorld* world, const SordNode* node);
int
lilv_header_compare_by_uri(const void* a, const void* b, const void* user_data);
int
lilv_lib_compare(const void* a, const void* b, const void* user_data);
int
lilv_ptr_cmp(const void* a, const void* b, const void* user_data);
int
lilv_resource_node_cmp(const void* a, const void* b, const void* user_data);
static inline int
lilv_version_cmp(const LilvVersion* a, const LilvVersion* b)
{
if (a->minor == b->minor && a->micro == b->micro) {
return 0;
}
if ((a->minor < b->minor) || (a->minor == b->minor && a->micro < b->micro)) {
return -1;
}
return 1;
}
struct LilvHeader*
lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri);
LilvScalePoint*
lilv_scale_point_new(LilvNode* value, LilvNode* label);
void
lilv_scale_point_free(LilvScalePoint* point);
SordIter*
lilv_world_query_internal(LilvWorld* world,
const SordNode* subject,
const SordNode* predicate,
const SordNode* object);
bool
lilv_world_ask_internal(LilvWorld* world,
const SordNode* subject,
const SordNode* predicate,
const SordNode* object);
LilvNodes*
lilv_world_find_nodes_internal(LilvWorld* world,
const SordNode* subject,
const SordNode* predicate,
const SordNode* object);
SordModel*
lilv_world_filter_model(LilvWorld* world,
SordModel* model,
const SordNode* subject,
const SordNode* predicate,
const SordNode* object,
const SordNode* graph);
#define FOREACH_MATCH(iter) for (; !sord_iter_end(iter); sord_iter_next(iter))
LilvNodes*
lilv_nodes_from_stream_objects(LilvWorld* world,
SordIter* stream,
SordQuadIndex field);
char*
lilv_strjoin(const char* first, ...);
char*
lilv_strdup(const char* str);
char*
lilv_get_lang(void);
char*
lilv_expand(const char* path);
char*
lilv_get_latest_copy(const char* path, const char* copy_path);
char*
lilv_find_free_path(const char* in_path,
bool (*exists)(const char*, const void*),
const void* user_data);
typedef void (*LilvVoidFunc)(void);
/** dlsym wrapper to return a function pointer (without annoying warning) */
static inline LilvVoidFunc
lilv_dlfunc(void* handle, const char* symbol)
{
#ifdef _WIN32
return (LilvVoidFunc)GetProcAddress((HMODULE)handle, symbol);
#else
typedef LilvVoidFunc (*VoidFuncGetter)(void*, const char*);
VoidFuncGetter dlfunc = (VoidFuncGetter)dlsym;
return dlfunc(handle, symbol);
#endif
}
#ifdef LILV_DYN_MANIFEST
static const LV2_Feature* const dman_features = {NULL};
void
lilv_dynmanifest_free(LilvDynManifest* dynmanifest);
#endif
#define LILV_ERROR(str) fprintf(stderr, "%s(): error: " str, __func__)
#define LILV_ERRORF(fmt, ...) \
fprintf(stderr, "%s(): error: " fmt, __func__, __VA_ARGS__)
#define LILV_WARN(str) fprintf(stderr, "%s(): warning: " str, __func__)
#define LILV_WARNF(fmt, ...) \
fprintf(stderr, "%s(): warning: " fmt, __func__, __VA_ARGS__)
#define LILV_NOTE(str) fprintf(stderr, "%s(): note: " str, __func__)
#define LILV_NOTEF(fmt, ...) \
fprintf(stderr, "%s(): note: " fmt, __func__, __VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif /* LILV_INTERNAL_H */

View File

@@ -0,0 +1,413 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "filesystem.h"
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "serd/serd.h"
#include "sord/sord.h"
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
lilv_node_set_numerics_from_string(LilvNode* val)
{
const char* str = (const char*)sord_node_get_string(val->node);
switch (val->type) {
case LILV_VALUE_URI:
case LILV_VALUE_BLANK:
case LILV_VALUE_STRING:
case LILV_VALUE_BLOB:
break;
case LILV_VALUE_INT:
val->val.int_val = strtol(str, NULL, 10);
break;
case LILV_VALUE_FLOAT:
val->val.float_val = serd_strtod(str, NULL);
break;
case LILV_VALUE_BOOL:
val->val.bool_val = !strcmp(str, "true");
break;
}
}
/** Note that if `type` is numeric or boolean, the returned value is corrupt
* until lilv_node_set_numerics_from_string is called. It is not
* automatically called from here to avoid overhead and imprecision when the
* exact string value is known.
*/
LilvNode*
lilv_node_new(LilvWorld* world, LilvNodeType type, const char* str)
{
LilvNode* val = (LilvNode*)malloc(sizeof(LilvNode));
val->world = world;
val->type = type;
const uint8_t* ustr = (const uint8_t*)str;
switch (type) {
case LILV_VALUE_URI:
val->node = sord_new_uri(world->world, ustr);
break;
case LILV_VALUE_BLANK:
val->node = sord_new_blank(world->world, ustr);
break;
case LILV_VALUE_STRING:
val->node = sord_new_literal(world->world, NULL, ustr, NULL);
break;
case LILV_VALUE_INT:
val->node =
sord_new_literal(world->world, world->uris.xsd_integer, ustr, NULL);
break;
case LILV_VALUE_FLOAT:
val->node =
sord_new_literal(world->world, world->uris.xsd_decimal, ustr, NULL);
break;
case LILV_VALUE_BOOL:
val->node =
sord_new_literal(world->world, world->uris.xsd_boolean, ustr, NULL);
break;
case LILV_VALUE_BLOB:
val->node =
sord_new_literal(world->world, world->uris.xsd_base64Binary, ustr, NULL);
break;
}
if (!val->node) {
free(val);
return NULL;
}
return val;
}
/** Create a new LilvNode from `node`, or return NULL if impossible */
LilvNode*
lilv_node_new_from_node(LilvWorld* world, const SordNode* node)
{
if (!node) {
return NULL;
}
LilvNode* result = NULL;
SordNode* datatype_uri = NULL;
LilvNodeType type = LILV_VALUE_STRING;
switch (sord_node_get_type(node)) {
case SORD_URI:
result = (LilvNode*)malloc(sizeof(LilvNode));
result->world = world;
result->type = LILV_VALUE_URI;
result->node = sord_node_copy(node);
break;
case SORD_BLANK:
result = (LilvNode*)malloc(sizeof(LilvNode));
result->world = world;
result->type = LILV_VALUE_BLANK;
result->node = sord_node_copy(node);
break;
case SORD_LITERAL:
datatype_uri = sord_node_get_datatype(node);
if (datatype_uri) {
if (sord_node_equals(datatype_uri, world->uris.xsd_boolean)) {
type = LILV_VALUE_BOOL;
} else if (sord_node_equals(datatype_uri, world->uris.xsd_decimal) ||
sord_node_equals(datatype_uri, world->uris.xsd_double)) {
type = LILV_VALUE_FLOAT;
} else if (sord_node_equals(datatype_uri, world->uris.xsd_integer)) {
type = LILV_VALUE_INT;
} else if (sord_node_equals(datatype_uri, world->uris.xsd_base64Binary)) {
type = LILV_VALUE_BLOB;
} else {
LILV_ERRORF("Unknown datatype `%s'\n",
sord_node_get_string(datatype_uri));
}
}
result =
lilv_node_new(world, type, (const char*)sord_node_get_string(node));
lilv_node_set_numerics_from_string(result);
break;
}
return result;
}
LilvNode*
lilv_new_uri(LilvWorld* world, const char* uri)
{
return lilv_node_new(world, LILV_VALUE_URI, uri);
}
LilvNode*
lilv_new_file_uri(LilvWorld* world, const char* host, const char* path)
{
char* abs_path = lilv_path_absolute(path);
SerdNode s = serd_node_new_file_uri(
(const uint8_t*)abs_path, (const uint8_t*)host, NULL, true);
LilvNode* ret = lilv_node_new(world, LILV_VALUE_URI, (const char*)s.buf);
serd_node_free(&s);
free(abs_path);
return ret;
}
LilvNode*
lilv_new_string(LilvWorld* world, const char* str)
{
return lilv_node_new(world, LILV_VALUE_STRING, str);
}
LilvNode*
lilv_new_int(LilvWorld* world, int val)
{
char str[32];
snprintf(str, sizeof(str), "%d", val);
LilvNode* ret = lilv_node_new(world, LILV_VALUE_INT, str);
if (ret) {
ret->val.int_val = val;
}
return ret;
}
LilvNode*
lilv_new_float(LilvWorld* world, float val)
{
char str[32];
snprintf(str, sizeof(str), "%f", val);
LilvNode* ret = lilv_node_new(world, LILV_VALUE_FLOAT, str);
if (ret) {
ret->val.float_val = val;
}
return ret;
}
LilvNode*
lilv_new_bool(LilvWorld* world, bool val)
{
LilvNode* ret = lilv_node_new(world, LILV_VALUE_BOOL, val ? "true" : "false");
if (ret) {
ret->val.bool_val = val;
}
return ret;
}
LilvNode*
lilv_node_duplicate(const LilvNode* val)
{
if (!val) {
return NULL;
}
LilvNode* result = (LilvNode*)malloc(sizeof(LilvNode));
result->world = val->world;
result->node = sord_node_copy(val->node);
result->val = val->val;
result->type = val->type;
return result;
}
void
lilv_node_free(LilvNode* val)
{
if (val) {
sord_node_free(val->world->world, val->node);
free(val);
}
}
bool
lilv_node_equals(const LilvNode* value, const LilvNode* other)
{
if (value == NULL && other == NULL) {
return true;
}
if (value == NULL || other == NULL || value->type != other->type) {
return false;
}
switch (value->type) {
case LILV_VALUE_URI:
case LILV_VALUE_BLANK:
case LILV_VALUE_STRING:
case LILV_VALUE_BLOB:
return sord_node_equals(value->node, other->node);
case LILV_VALUE_INT:
return (value->val.int_val == other->val.int_val);
case LILV_VALUE_FLOAT:
return (value->val.float_val == other->val.float_val);
case LILV_VALUE_BOOL:
return (value->val.bool_val == other->val.bool_val);
}
return false; /* shouldn't get here */
}
char*
lilv_node_get_turtle_token(const LilvNode* value)
{
const char* str = (const char*)sord_node_get_string(value->node);
size_t len = 0;
char* result = NULL;
SerdNode node;
switch (value->type) {
case LILV_VALUE_URI:
len = strlen(str) + 3;
result = (char*)calloc(len, 1);
snprintf(result, len, "<%s>", str);
break;
case LILV_VALUE_BLANK:
len = strlen(str) + 3;
result = (char*)calloc(len, 1);
snprintf(result, len, "_:%s", str);
break;
case LILV_VALUE_STRING:
case LILV_VALUE_BOOL:
case LILV_VALUE_BLOB:
result = lilv_strdup(str);
break;
case LILV_VALUE_INT:
node = serd_node_new_integer(value->val.int_val);
result = lilv_strdup((char*)node.buf);
serd_node_free(&node);
break;
case LILV_VALUE_FLOAT:
node = serd_node_new_decimal(value->val.float_val, 8);
result = lilv_strdup((char*)node.buf);
serd_node_free(&node);
break;
}
return result;
}
bool
lilv_node_is_uri(const LilvNode* value)
{
return (value && value->type == LILV_VALUE_URI);
}
const char*
lilv_node_as_uri(const LilvNode* value)
{
return (lilv_node_is_uri(value)
? (const char*)sord_node_get_string(value->node)
: NULL);
}
bool
lilv_node_is_blank(const LilvNode* value)
{
return (value && value->type == LILV_VALUE_BLANK);
}
const char*
lilv_node_as_blank(const LilvNode* value)
{
return (lilv_node_is_blank(value)
? (const char*)sord_node_get_string(value->node)
: NULL);
}
bool
lilv_node_is_literal(const LilvNode* value)
{
if (!value) {
return false;
}
switch (value->type) {
case LILV_VALUE_STRING:
case LILV_VALUE_INT:
case LILV_VALUE_FLOAT:
case LILV_VALUE_BLOB:
return true;
default:
return false;
}
}
bool
lilv_node_is_string(const LilvNode* value)
{
return (value && value->type == LILV_VALUE_STRING);
}
const char*
lilv_node_as_string(const LilvNode* value)
{
return value ? (const char*)sord_node_get_string(value->node) : NULL;
}
bool
lilv_node_is_int(const LilvNode* value)
{
return (value && value->type == LILV_VALUE_INT);
}
int
lilv_node_as_int(const LilvNode* value)
{
return lilv_node_is_int(value) ? value->val.int_val : 0;
}
bool
lilv_node_is_float(const LilvNode* value)
{
return (value && value->type == LILV_VALUE_FLOAT);
}
float
lilv_node_as_float(const LilvNode* value)
{
if (lilv_node_is_float(value)) {
return value->val.float_val;
}
if (lilv_node_is_int(value)) {
return (float)value->val.int_val;
}
return NAN;
}
bool
lilv_node_is_bool(const LilvNode* value)
{
return (value && value->type == LILV_VALUE_BOOL);
}
bool
lilv_node_as_bool(const LilvNode* value)
{
return lilv_node_is_bool(value) ? value->val.bool_val : false;
}
char*
lilv_node_get_path(const LilvNode* value, char** hostname)
{
if (lilv_node_is_uri(value)) {
return lilv_file_uri_parse(lilv_node_as_uri(value), hostname);
}
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "sord/sord.h"
#include "zix/tree.h"
#include <stdbool.h>
#include <stdlib.h>
LilvPluginClass*
lilv_plugin_class_new(LilvWorld* world,
const SordNode* parent_node,
const SordNode* uri,
const char* label)
{
LilvPluginClass* pc = (LilvPluginClass*)malloc(sizeof(LilvPluginClass));
pc->world = world;
pc->uri = lilv_node_new_from_node(world, uri);
pc->label = lilv_node_new(world, LILV_VALUE_STRING, label);
pc->parent_uri =
(parent_node ? lilv_node_new_from_node(world, parent_node) : NULL);
return pc;
}
void
lilv_plugin_class_free(LilvPluginClass* plugin_class)
{
if (!plugin_class) {
return;
}
lilv_node_free(plugin_class->uri);
lilv_node_free(plugin_class->parent_uri);
lilv_node_free(plugin_class->label);
free(plugin_class);
}
const LilvNode*
lilv_plugin_class_get_parent_uri(const LilvPluginClass* plugin_class)
{
return plugin_class->parent_uri ? plugin_class->parent_uri : NULL;
}
const LilvNode*
lilv_plugin_class_get_uri(const LilvPluginClass* plugin_class)
{
return plugin_class->uri;
}
const LilvNode*
lilv_plugin_class_get_label(const LilvPluginClass* plugin_class)
{
return plugin_class->label;
}
LilvPluginClasses*
lilv_plugin_class_get_children(const LilvPluginClass* plugin_class)
{
// Returned list doesn't own categories
LilvPluginClasses* all = plugin_class->world->plugin_classes;
LilvPluginClasses* result = zix_tree_new(false, lilv_ptr_cmp, NULL, NULL);
for (ZixTreeIter* i = zix_tree_begin((ZixTree*)all);
i != zix_tree_end((ZixTree*)all);
i = zix_tree_iter_next(i)) {
const LilvPluginClass* c = (LilvPluginClass*)zix_tree_get(i);
const LilvNode* parent = lilv_plugin_class_get_parent_uri(c);
if (parent &&
lilv_node_equals(lilv_plugin_class_get_uri(plugin_class), parent)) {
zix_tree_insert((ZixTree*)result, (LilvPluginClass*)c, NULL);
}
}
return result;
}

View File

@@ -0,0 +1,272 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lv2/atom/atom.h"
#include "lv2/core/lv2.h"
#include "lv2/event/event.h"
#include "lilv/lilv.h"
#include "sord/sord.h"
#include "zix/tree.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
LilvPort*
lilv_port_new(LilvWorld* world,
const SordNode* node,
uint32_t index,
const char* symbol)
{
LilvPort* port = (LilvPort*)malloc(sizeof(LilvPort));
port->node = lilv_node_new_from_node(world, node);
port->index = index;
port->symbol = lilv_node_new(world, LILV_VALUE_STRING, symbol);
port->classes = lilv_nodes_new();
return port;
}
void
lilv_port_free(const LilvPlugin* plugin, LilvPort* port)
{
(void)plugin;
if (port) {
lilv_node_free(port->node);
lilv_nodes_free(port->classes);
lilv_node_free(port->symbol);
free(port);
}
}
bool
lilv_port_is_a(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* port_class)
{
(void)plugin;
LILV_FOREACH (nodes, i, port->classes) {
if (lilv_node_equals(lilv_nodes_get(port->classes, i), port_class)) {
return true;
}
}
return false;
}
bool
lilv_port_has_property(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* property)
{
return lilv_world_ask_internal(plugin->world,
port->node->node,
plugin->world->uris.lv2_portProperty,
property->node);
}
bool
lilv_port_supports_event(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* event_type)
{
const uint8_t* predicates[] = {(const uint8_t*)LV2_EVENT__supportsEvent,
(const uint8_t*)LV2_ATOM__supports,
NULL};
for (const uint8_t** pred = predicates; *pred; ++pred) {
if (lilv_world_ask_internal(plugin->world,
port->node->node,
sord_new_uri(plugin->world->world, *pred),
event_type->node)) {
return true;
}
}
return false;
}
static LilvNodes*
lilv_port_get_value_by_node(const LilvPlugin* plugin,
const LilvPort* port,
const SordNode* predicate)
{
return lilv_world_find_nodes_internal(
plugin->world, port->node->node, predicate, NULL);
}
const LilvNode*
lilv_port_get_node(const LilvPlugin* plugin, const LilvPort* port)
{
(void)plugin;
return port->node;
}
LilvNodes*
lilv_port_get_value(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* predicate)
{
if (!lilv_node_is_uri(predicate)) {
LILV_ERRORF("Predicate `%s' is not a URI\n",
sord_node_get_string(predicate->node));
return NULL;
}
return lilv_port_get_value_by_node(plugin, port, predicate->node);
}
LilvNode*
lilv_port_get(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* predicate)
{
LilvNodes* values = lilv_port_get_value(plugin, port, predicate);
LilvNode* value =
lilv_node_duplicate(values ? lilv_nodes_get_first(values) : NULL);
lilv_nodes_free(values);
return value;
}
uint32_t
lilv_port_get_index(const LilvPlugin* plugin, const LilvPort* port)
{
(void)plugin;
return port->index;
}
const LilvNode*
lilv_port_get_symbol(const LilvPlugin* plugin, const LilvPort* port)
{
(void)plugin;
return port->symbol;
}
LilvNode*
lilv_port_get_name(const LilvPlugin* plugin, const LilvPort* port)
{
LilvNodes* results =
lilv_port_get_value_by_node(plugin, port, plugin->world->uris.lv2_name);
LilvNode* ret = NULL;
if (results) {
LilvNode* val = lilv_nodes_get_first(results);
if (lilv_node_is_string(val)) {
ret = lilv_node_duplicate(val);
}
lilv_nodes_free(results);
}
if (!ret) {
LILV_WARNF("Plugin <%s> port has no (mandatory) doap:name\n",
lilv_node_as_string(lilv_plugin_get_uri(plugin)));
}
return ret;
}
const LilvNodes*
lilv_port_get_classes(const LilvPlugin* plugin, const LilvPort* port)
{
(void)plugin;
return port->classes;
}
void
lilv_port_get_range(const LilvPlugin* plugin,
const LilvPort* port,
LilvNode** def,
LilvNode** min,
LilvNode** max)
{
if (def) {
LilvNodes* defaults = lilv_port_get_value_by_node(
plugin, port, plugin->world->uris.lv2_default);
*def =
defaults ? lilv_node_duplicate(lilv_nodes_get_first(defaults)) : NULL;
lilv_nodes_free(defaults);
}
if (min) {
LilvNodes* minimums = lilv_port_get_value_by_node(
plugin, port, plugin->world->uris.lv2_minimum);
*min =
minimums ? lilv_node_duplicate(lilv_nodes_get_first(minimums)) : NULL;
lilv_nodes_free(minimums);
}
if (max) {
LilvNodes* maximums = lilv_port_get_value_by_node(
plugin, port, plugin->world->uris.lv2_maximum);
*max =
maximums ? lilv_node_duplicate(lilv_nodes_get_first(maximums)) : NULL;
lilv_nodes_free(maximums);
}
}
LilvScalePoints*
lilv_port_get_scale_points(const LilvPlugin* plugin, const LilvPort* port)
{
SordIter* points = lilv_world_query_internal(
plugin->world,
port->node->node,
sord_new_uri(plugin->world->world, (const uint8_t*)LV2_CORE__scalePoint),
NULL);
LilvScalePoints* ret = NULL;
if (!sord_iter_end(points)) {
ret = lilv_scale_points_new();
}
FOREACH_MATCH (points) {
const SordNode* point = sord_iter_get_node(points, SORD_OBJECT);
LilvNode* value =
lilv_plugin_get_unique(plugin, point, plugin->world->uris.rdf_value);
LilvNode* label =
lilv_plugin_get_unique(plugin, point, plugin->world->uris.rdfs_label);
if (value && label) {
zix_tree_insert((ZixTree*)ret, lilv_scale_point_new(value, label), NULL);
}
}
sord_iter_free(points);
assert(!ret || lilv_nodes_size(ret) > 0);
return ret;
}
LilvNodes*
lilv_port_get_properties(const LilvPlugin* plugin, const LilvPort* port)
{
LilvNode* pred = lilv_node_new_from_node(
plugin->world, plugin->world->uris.lv2_portProperty);
LilvNodes* ret = lilv_port_get_value(plugin, port, pred);
lilv_node_free(pred);
return ret;
}

View File

@@ -0,0 +1,144 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "sord/sord.h"
#include "zix/tree.h"
#include <stdlib.h>
#include <string.h>
typedef enum {
LILV_LANG_MATCH_NONE, ///< Language does not match at all
LILV_LANG_MATCH_PARTIAL, ///< Partial (language, but not country) match
LILV_LANG_MATCH_EXACT ///< Exact (language and country) match
} LilvLangMatch;
static LilvLangMatch
lilv_lang_matches(const char* a, const char* b)
{
if (!a || !b) {
return LILV_LANG_MATCH_NONE;
}
if (!strcmp(a, b)) {
return LILV_LANG_MATCH_EXACT;
}
const char* a_dash = strchr(a, '-');
const size_t a_lang_len = a_dash ? (size_t)(a_dash - a) : strlen(a);
const char* b_dash = strchr(b, '-');
const size_t b_lang_len = b_dash ? (size_t)(b_dash - b) : strlen(b);
if (a_lang_len == b_lang_len && !strncmp(a, b, a_lang_len)) {
return LILV_LANG_MATCH_PARTIAL;
}
return LILV_LANG_MATCH_NONE;
}
static LilvNodes*
lilv_nodes_from_stream_objects_i18n(LilvWorld* world,
SordIter* stream,
SordQuadIndex field)
{
LilvNodes* values = lilv_nodes_new();
const SordNode* nolang = NULL; // Untranslated value
const SordNode* partial = NULL; // Partial language match
char* syslang = lilv_get_lang();
FOREACH_MATCH (stream) {
const SordNode* value = sord_iter_get_node(stream, field);
if (sord_node_get_type(value) == SORD_LITERAL) {
const char* lang = sord_node_get_language(value);
if (!lang) {
nolang = value;
} else {
switch (lilv_lang_matches(lang, syslang)) {
case LILV_LANG_MATCH_EXACT:
// Exact language match, add to results
zix_tree_insert(
(ZixTree*)values, lilv_node_new_from_node(world, value), NULL);
break;
case LILV_LANG_MATCH_PARTIAL:
// Partial language match, save in case we find no exact
partial = value;
break;
case LILV_LANG_MATCH_NONE:
break;
}
}
} else {
zix_tree_insert(
(ZixTree*)values, lilv_node_new_from_node(world, value), NULL);
}
}
sord_iter_free(stream);
free(syslang);
if (lilv_nodes_size(values) > 0) {
return values;
}
const SordNode* best = nolang;
if (syslang && partial) {
// Partial language match for system language
best = partial;
} else if (!best) {
// No languages matches at all, and no untranslated value
// Use any value, if possible
best = partial;
}
if (best) {
zix_tree_insert(
(ZixTree*)values, lilv_node_new_from_node(world, best), NULL);
} else {
// No matches whatsoever
lilv_nodes_free(values);
values = NULL;
}
return values;
}
LilvNodes*
lilv_nodes_from_stream_objects(LilvWorld* world,
SordIter* stream,
SordQuadIndex field)
{
if (sord_iter_end(stream)) {
sord_iter_free(stream);
return NULL;
}
if (world->opt.filter_language) {
return lilv_nodes_from_stream_objects_i18n(world, stream, field);
}
LilvNodes* values = lilv_nodes_new();
FOREACH_MATCH (stream) {
const SordNode* value = sord_iter_get_node(stream, field);
LilvNode* node = lilv_node_new_from_node(world, value);
if (node) {
zix_tree_insert((ZixTree*)values, node, NULL);
}
}
sord_iter_free(stream);
return values;
}

View File

@@ -0,0 +1,53 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include <stdlib.h>
/** Ownership of value and label is taken */
LilvScalePoint*
lilv_scale_point_new(LilvNode* value, LilvNode* label)
{
LilvScalePoint* point = (LilvScalePoint*)malloc(sizeof(LilvScalePoint));
point->value = value;
point->label = label;
return point;
}
void
lilv_scale_point_free(LilvScalePoint* point)
{
if (point) {
lilv_node_free(point->value);
lilv_node_free(point->label);
free(point);
}
}
const LilvNode*
lilv_scale_point_get_value(const LilvScalePoint* point)
{
return point->value;
}
const LilvNode*
lilv_scale_point_get_label(const LilvScalePoint* point)
{
return point->label;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "zix/tree.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
LilvUI*
lilv_ui_new(LilvWorld* world,
LilvNode* uri,
LilvNode* type_uri,
LilvNode* binary_uri)
{
assert(uri);
assert(type_uri);
assert(binary_uri);
LilvUI* ui = (LilvUI*)malloc(sizeof(LilvUI));
ui->world = world;
ui->uri = uri;
ui->binary_uri = binary_uri;
// FIXME: kludge
char* bundle = lilv_strdup(lilv_node_as_string(ui->binary_uri));
char* last_slash = strrchr(bundle, '/') + 1;
*last_slash = '\0';
ui->bundle_uri = lilv_new_uri(world, bundle);
free(bundle);
ui->classes = lilv_nodes_new();
zix_tree_insert((ZixTree*)ui->classes, type_uri, NULL);
return ui;
}
void
lilv_ui_free(LilvUI* ui)
{
lilv_node_free(ui->uri);
lilv_node_free(ui->bundle_uri);
lilv_node_free(ui->binary_uri);
lilv_nodes_free(ui->classes);
free(ui);
}
const LilvNode*
lilv_ui_get_uri(const LilvUI* ui)
{
return ui->uri;
}
unsigned
lilv_ui_is_supported(const LilvUI* ui,
LilvUISupportedFunc supported_func,
const LilvNode* container_type,
const LilvNode** ui_type)
{
const LilvNodes* classes = lilv_ui_get_classes(ui);
LILV_FOREACH (nodes, c, classes) {
const LilvNode* type = lilv_nodes_get(classes, c);
const unsigned q =
supported_func(lilv_node_as_uri(container_type), lilv_node_as_uri(type));
if (q) {
if (ui_type) {
*ui_type = type;
}
return q;
}
}
return 0;
}
const LilvNodes*
lilv_ui_get_classes(const LilvUI* ui)
{
return ui->classes;
}
bool
lilv_ui_is_a(const LilvUI* ui, const LilvNode* class_uri)
{
return lilv_nodes_contains(ui->classes, class_uri);
}
const LilvNode*
lilv_ui_get_bundle_uri(const LilvUI* ui)
{
return ui->bundle_uri;
}
const LilvNode*
lilv_ui_get_binary_uri(const LilvUI* ui)
{
return ui->binary_uri;
}

View File

@@ -0,0 +1,291 @@
/*
Copyright 2007-2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "filesystem.h"
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "serd/serd.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
lilv_free(void* ptr)
{
free(ptr);
}
char*
lilv_strjoin(const char* first, ...)
{
size_t len = strlen(first);
char* result = (char*)malloc(len + 1);
memcpy(result, first, len);
va_list args;
va_start(args, first);
while (1) {
const char* const s = va_arg(args, const char*);
if (s == NULL) {
break;
}
const size_t this_len = strlen(s);
char* new_result = (char*)realloc(result, len + this_len + 1);
if (!new_result) {
va_end(args);
free(result);
return NULL;
}
result = new_result;
memcpy(result + len, s, this_len);
len += this_len;
}
va_end(args);
result[len] = '\0';
return result;
}
char*
lilv_strdup(const char* str)
{
if (!str) {
return NULL;
}
const size_t len = strlen(str);
char* copy = (char*)malloc(len + 1);
memcpy(copy, str, len + 1);
return copy;
}
const char*
lilv_uri_to_path(const char* uri)
{
#if defined(__GNUC__) && __GNUC__ > 4
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
return (const char*)serd_uri_to_path((const uint8_t*)uri);
#if defined(__GNUC__) && __GNUC__ > 4
# pragma GCC diagnostic pop
#endif
}
char*
lilv_file_uri_parse(const char* uri, char** hostname)
{
return (char*)serd_file_uri_parse((const uint8_t*)uri, (uint8_t**)hostname);
}
/** Return the current LANG converted to Turtle (i.e. RFC3066) style.
* For example, if LANG is set to "en_CA.utf-8", this returns "en-ca".
*/
char*
lilv_get_lang(void)
{
const char* const env_lang = getenv("LANG");
if (!env_lang || !strcmp(env_lang, "") || !strcmp(env_lang, "C") ||
!strcmp(env_lang, "POSIX")) {
return NULL;
}
const size_t env_lang_len = strlen(env_lang);
char* const lang = (char*)malloc(env_lang_len + 1);
for (size_t i = 0; i < env_lang_len + 1; ++i) {
if (env_lang[i] == '_') {
lang[i] = '-'; // Convert _ to -
} else if (env_lang[i] >= 'A' && env_lang[i] <= 'Z') {
lang[i] = env_lang[i] + ('a' - 'A'); // Convert to lowercase
} else if (env_lang[i] >= 'a' && env_lang[i] <= 'z') {
lang[i] = env_lang[i]; // Lowercase letter, copy verbatim
} else if (env_lang[i] >= '0' && env_lang[i] <= '9') {
lang[i] = env_lang[i]; // Digit, copy verbatim
} else if (env_lang[i] == '\0' || env_lang[i] == '.') {
// End, or start of suffix (e.g. en_CA.utf-8), finished
lang[i] = '\0';
break;
} else {
LILV_ERRORF("Illegal LANG `%s' ignored\n", env_lang);
free(lang);
return NULL;
}
}
return lang;
}
#ifndef _WIN32
/** Append suffix to dst, update dst_len, and return the realloc'd result. */
static char*
strappend(char* dst, size_t* dst_len, const char* suffix, size_t suffix_len)
{
dst = (char*)realloc(dst, *dst_len + suffix_len + 1);
memcpy(dst + *dst_len, suffix, suffix_len);
dst[(*dst_len += suffix_len)] = '\0';
return dst;
}
/** Append the value of the environment variable var to dst. */
static char*
append_var(char* dst, size_t* dst_len, const char* var)
{
// Get value from environment
const char* val = getenv(var);
if (val) { // Value found, append it
return strappend(dst, dst_len, val, strlen(val));
}
// No value found, append variable reference as-is
return strappend(strappend(dst, dst_len, "$", 1), dst_len, var, strlen(var));
}
#endif
/** Expand variables (e.g. POSIX ~ or $FOO, Windows %FOO%) in `path`. */
char*
lilv_expand(const char* path)
{
#ifdef _WIN32
char* out = (char*)malloc(MAX_PATH);
ExpandEnvironmentStrings(path, out, MAX_PATH);
#else
char* out = NULL;
size_t len = 0;
const char* start = path; // Start of current chunk to copy
for (const char* s = path; *s;) {
if (*s == '$') {
// Hit $ (variable reference, e.g. $VAR_NAME)
for (const char* t = s + 1;; ++t) {
if (!*t || (!isupper(*t) && !isdigit(*t) && *t != '_')) {
// Append preceding chunk
out = strappend(out, &len, start, s - start);
// Append variable value (or $VAR_NAME if not found)
char* var = (char*)calloc(t - s, 1);
memcpy(var, s + 1, t - s - 1);
out = append_var(out, &len, var);
free(var);
// Continue after variable reference
start = s = t;
break;
}
}
} else if (*s == '~' && (*(s + 1) == '/' || !*(s + 1))) {
// Hit ~ before slash or end of string (home directory reference)
out = strappend(out, &len, start, s - start);
out = append_var(out, &len, "HOME");
start = ++s;
} else {
++s;
}
}
if (*start) {
out = strappend(out, &len, start, strlen(start));
}
#endif
return out;
}
char*
lilv_find_free_path(const char* in_path,
bool (*exists)(const char*, const void*),
const void* user_data)
{
const size_t in_path_len = strlen(in_path);
char* path = (char*)malloc(in_path_len + 7);
memcpy(path, in_path, in_path_len + 1);
for (unsigned i = 2; i < 1000000u; ++i) {
if (!exists(path, user_data)) {
return path;
}
snprintf(path, in_path_len + 7, "%s.%u", in_path, i);
}
return NULL;
}
typedef struct {
char* pattern;
time_t time;
char* latest;
} Latest;
static void
update_latest(const char* path, const char* name, void* data)
{
Latest* latest = (Latest*)data;
char* entry_path = lilv_path_join(path, name);
unsigned num = 0;
if (sscanf(entry_path, latest->pattern, &num) == 1) {
struct stat st;
if (!stat(entry_path, &st)) {
if (st.st_mtime >= latest->time) {
free(latest->latest);
latest->latest = entry_path;
}
} else {
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno));
}
}
if (entry_path != latest->latest) {
free(entry_path);
}
}
/** Return the latest copy of the file at `path` that is newer. */
char*
lilv_get_latest_copy(const char* path, const char* copy_path)
{
char* copy_dir = lilv_path_parent(copy_path);
Latest latest = {lilv_strjoin(copy_path, ".%u", NULL), 0, NULL};
struct stat st;
if (!stat(path, &st)) {
latest.time = st.st_mtime;
} else {
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno));
}
lilv_dir_for_each(copy_dir, &latest, update_latest);
free(latest.pattern);
free(copy_dir);
return latest.latest;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,138 @@
/*
Copyright 2016-2020 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ZIX_COMMON_H
#define ZIX_COMMON_H
#include <stdbool.h>
/**
@addtogroup zix
@{
*/
/** @cond */
#if defined(_WIN32) && !defined(ZIX_STATIC) && defined(ZIX_INTERNAL)
# define ZIX_API __declspec(dllexport)
#elif defined(_WIN32) && !defined(ZIX_STATIC)
# define ZIX_API __declspec(dllimport)
#elif defined(__GNUC__)
# define ZIX_API __attribute__((visibility("default")))
#else
# define ZIX_API
#endif
#ifdef __GNUC__
# define ZIX_PURE_FUNC __attribute__((pure))
# define ZIX_CONST_FUNC __attribute__((const))
# define ZIX_MALLOC_FUNC __attribute__((malloc))
#else
# define ZIX_PURE_FUNC
# define ZIX_CONST_FUNC
# define ZIX_MALLOC_FUNC
#endif
#define ZIX_PURE_API \
ZIX_API \
ZIX_PURE_FUNC
#define ZIX_CONST_API \
ZIX_API \
ZIX_CONST_FUNC
#define ZIX_MALLOC_API \
ZIX_API \
ZIX_MALLOC_FUNC
/** @endcond */
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __GNUC__
# define ZIX_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
#else
# define ZIX_LOG_FUNC(fmt, arg1)
#endif
// Unused parameter macro to suppresses warnings and make it impossible to use
#if defined(__cplusplus)
# define ZIX_UNUSED(name)
#elif defined(__GNUC__)
# define ZIX_UNUSED(name) name##_unused __attribute__((__unused__))
#else
# define ZIX_UNUSED(name) name
#endif
typedef enum {
ZIX_STATUS_SUCCESS,
ZIX_STATUS_ERROR,
ZIX_STATUS_NO_MEM,
ZIX_STATUS_NOT_FOUND,
ZIX_STATUS_EXISTS,
ZIX_STATUS_BAD_ARG,
ZIX_STATUS_BAD_PERMS
} ZixStatus;
static inline const char*
zix_strerror(const ZixStatus status)
{
switch (status) {
case ZIX_STATUS_SUCCESS:
return "Success";
case ZIX_STATUS_ERROR:
return "Unknown error";
case ZIX_STATUS_NO_MEM:
return "Out of memory";
case ZIX_STATUS_NOT_FOUND:
return "Not found";
case ZIX_STATUS_EXISTS:
return "Exists";
case ZIX_STATUS_BAD_ARG:
return "Bad argument";
case ZIX_STATUS_BAD_PERMS:
return "Bad permissions";
}
return "Unknown error";
}
/**
Function for comparing two elements.
*/
typedef int (*ZixComparator)(const void* a,
const void* b,
const void* user_data);
/**
Function for testing equality of two elements.
*/
typedef bool (*ZixEqualFunc)(const void* a, const void* b);
/**
Function to destroy an element.
*/
typedef void (*ZixDestroyFunc)(void* ptr);
/**
@}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ZIX_COMMON_H */

View File

@@ -0,0 +1,727 @@
/*
Copyright 2011-2020 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "zix/tree.h"
#include "zix/common.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
typedef struct ZixTreeNodeImpl ZixTreeNode;
struct ZixTreeImpl {
ZixTreeNode* root;
ZixDestroyFunc destroy;
ZixComparator cmp;
void* cmp_data;
size_t size;
bool allow_duplicates;
};
struct ZixTreeNodeImpl {
void* data;
struct ZixTreeNodeImpl* left;
struct ZixTreeNodeImpl* right;
struct ZixTreeNodeImpl* parent;
int balance;
};
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
// Uncomment these for debugging features
// #define ZIX_TREE_DUMP 1
// #define ZIX_TREE_VERIFY 1
// #define ZIX_TREE_HYPER_VERIFY 1
#if defined(ZIX_TREE_VERIFY) || defined(ZIX_TREE_HYPER_VERIFY)
# include "tree_debug.h"
# define ASSERT_BALANCE(n) assert(verify_balance(n))
#else
# define ASSERT_BALANCE(n)
#endif
#ifdef ZIX_TREE_DUMP
# include "tree_debug.h"
# define DUMP(t) zix_tree_print(t->root, 0)
# define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
#else
# define DUMP(t)
# define DEBUG_PRINTF(fmt, ...)
#endif
ZixTree*
zix_tree_new(bool allow_duplicates,
ZixComparator cmp,
void* cmp_data,
ZixDestroyFunc destroy)
{
ZixTree* t = (ZixTree*)malloc(sizeof(ZixTree));
t->root = NULL;
t->destroy = destroy;
t->cmp = cmp;
t->cmp_data = cmp_data;
t->size = 0;
t->allow_duplicates = allow_duplicates;
return t;
}
static void
zix_tree_free_rec(ZixTree* t, ZixTreeNode* n)
{
if (n) {
zix_tree_free_rec(t, n->left);
zix_tree_free_rec(t, n->right);
if (t->destroy) {
t->destroy(n->data);
}
free(n);
}
}
void
zix_tree_free(ZixTree* t)
{
if (t) {
zix_tree_free_rec(t, t->root);
free(t);
}
}
size_t
zix_tree_size(const ZixTree* t)
{
return t->size;
}
static void
rotate(ZixTreeNode* p, ZixTreeNode* q)
{
assert(q->parent == p);
assert(p->left == q || p->right == q);
q->parent = p->parent;
if (q->parent) {
if (q->parent->left == p) {
q->parent->left = q;
} else {
q->parent->right = q;
}
}
if (p->right == q) {
// Rotate left
p->right = q->left;
q->left = p;
if (p->right) {
p->right->parent = p;
}
} else {
// Rotate right
assert(p->left == q);
p->left = q->right;
q->right = p;
if (p->left) {
p->left->parent = p;
}
}
p->parent = q;
}
/**
* Rotate left about `p`.
*
* p q
* / \ / \
* A q => p C
* / \ / \
* B C A B
*/
static ZixTreeNode*
rotate_left(ZixTreeNode* p, int* height_change)
{
ZixTreeNode* const q = p->right;
*height_change = (q->balance == 0) ? 0 : -1;
DEBUG_PRINTF("LL %ld\n", (intptr_t)p->data);
assert(p->balance == 2);
assert(q->balance == 0 || q->balance == 1);
rotate(p, q);
// p->balance -= 1 + MAX(0, q->balance);
// q->balance -= 1 - MIN(0, p->balance);
--q->balance;
p->balance = -(q->balance);
ASSERT_BALANCE(p);
ASSERT_BALANCE(q);
return q;
}
/**
* Rotate right about `p`.
*
* p q
* / \ / \
* q C => A p
* / \ / \
* A B B C
*
*/
static ZixTreeNode*
rotate_right(ZixTreeNode* p, int* height_change)
{
ZixTreeNode* const q = p->left;
*height_change = (q->balance == 0) ? 0 : -1;
DEBUG_PRINTF("RR %ld\n", (intptr_t)p->data);
assert(p->balance == -2);
assert(q->balance == 0 || q->balance == -1);
rotate(p, q);
// p->balance += 1 - MIN(0, q->balance);
// q->balance += 1 + MAX(0, p->balance);
++q->balance;
p->balance = -(q->balance);
ASSERT_BALANCE(p);
ASSERT_BALANCE(q);
return q;
}
/**
* Rotate left about `p->left` then right about `p`.
*
* p r
* / \ / \
* q D => q p
* / \ / \ / \
* A r A B C D
* / \
* B C
*
*/
static ZixTreeNode*
rotate_left_right(ZixTreeNode* p, int* height_change)
{
ZixTreeNode* const q = p->left;
ZixTreeNode* const r = q->right;
assert(p->balance == -2);
assert(q->balance == 1);
assert(r->balance == -1 || r->balance == 0 || r->balance == 1);
DEBUG_PRINTF("LR %ld P: %2d Q: %2d R: %2d\n",
(intptr_t)p->data,
p->balance,
q->balance,
r->balance);
rotate(q, r);
rotate(p, r);
q->balance -= 1 + MAX(0, r->balance);
p->balance += 1 - MIN(MIN(0, r->balance) - 1, r->balance + q->balance);
// r->balance += MAX(0, p->balance) + MIN(0, q->balance);
// p->balance = (p->left && p->right) ? -MIN(r->balance, 0) : 0;
// q->balance = - MAX(r->balance, 0);
r->balance = 0;
*height_change = -1;
ASSERT_BALANCE(p);
ASSERT_BALANCE(q);
ASSERT_BALANCE(r);
return r;
}
/**
* Rotate right about `p->right` then right about `p`.
*
* p r
* / \ / \
* A q => p q
* / \ / \ / \
* r D A B C D
* / \
* B C
*
*/
static ZixTreeNode*
rotate_right_left(ZixTreeNode* p, int* height_change)
{
ZixTreeNode* const q = p->right;
ZixTreeNode* const r = q->left;
assert(p->balance == 2);
assert(q->balance == -1);
assert(r->balance == -1 || r->balance == 0 || r->balance == 1);
DEBUG_PRINTF("RL %ld P: %2d Q: %2d R: %2d\n",
(intptr_t)p->data,
p->balance,
q->balance,
r->balance);
rotate(q, r);
rotate(p, r);
q->balance += 1 - MIN(0, r->balance);
p->balance -= 1 + MAX(MAX(0, r->balance) + 1, r->balance + q->balance);
// r->balance += MAX(0, q->balance) + MIN(0, p->balance);
// p->balance = (p->left && p->right) ? -MAX(r->balance, 0) : 0;
// q->balance = - MIN(r->balance, 0);
r->balance = 0;
// assert(r->balance == 0);
*height_change = -1;
ASSERT_BALANCE(p);
ASSERT_BALANCE(q);
ASSERT_BALANCE(r);
return r;
}
static ZixTreeNode*
zix_tree_rebalance(ZixTree* t, ZixTreeNode* node, int* height_change)
{
#ifdef ZIX_TREE_HYPER_VERIFY
const size_t old_height = height(node);
#endif
DEBUG_PRINTF("REBALANCE %ld (%d)\n", (intptr_t)node->data, node->balance);
*height_change = 0;
const bool is_root = !node->parent;
assert((is_root && t->root == node) || (!is_root && t->root != node));
ZixTreeNode* replacement = node;
if (node->balance == -2) {
assert(node->left);
if (node->left->balance == 1) {
replacement = rotate_left_right(node, height_change);
} else {
replacement = rotate_right(node, height_change);
}
} else if (node->balance == 2) {
assert(node->right);
if (node->right->balance == -1) {
replacement = rotate_right_left(node, height_change);
} else {
replacement = rotate_left(node, height_change);
}
}
if (is_root) {
assert(!replacement->parent);
t->root = replacement;
}
DUMP(t);
#ifdef ZIX_TREE_HYPER_VERIFY
assert(old_height + *height_change == height(replacement));
#endif
return replacement;
}
ZixStatus
zix_tree_insert(ZixTree* t, void* e, ZixTreeIter** ti)
{
DEBUG_PRINTF("**** INSERT %ld\n", (intptr_t)e);
int cmp = 0;
ZixTreeNode* n = t->root;
ZixTreeNode* p = NULL;
// Find the parent p of e
while (n) {
p = n;
cmp = t->cmp(e, n->data, t->cmp_data);
if (cmp < 0) {
n = n->left;
} else if (cmp > 0 || t->allow_duplicates) {
n = n->right;
} else {
if (ti) {
*ti = n;
}
DEBUG_PRINTF("%ld EXISTS!\n", (intptr_t)e);
return ZIX_STATUS_EXISTS;
}
}
// Allocate a new node n
if (!(n = (ZixTreeNode*)malloc(sizeof(ZixTreeNode)))) {
return ZIX_STATUS_NO_MEM;
}
memset(n, '\0', sizeof(ZixTreeNode));
n->data = e;
n->balance = 0;
if (ti) {
*ti = n;
}
bool p_height_increased = false;
// Make p the parent of n
n->parent = p;
if (!p) {
t->root = n;
} else {
if (cmp < 0) {
assert(!p->left);
assert(p->balance == 0 || p->balance == 1);
p->left = n;
--p->balance;
p_height_increased = !p->right;
} else {
assert(!p->right);
assert(p->balance == 0 || p->balance == -1);
p->right = n;
++p->balance;
p_height_increased = !p->left;
}
}
DUMP(t);
// Rebalance if necessary (at most 1 rotation)
assert(!p || p->balance == -1 || p->balance == 0 || p->balance == 1);
if (p && p_height_increased) {
int height_change = 0;
for (ZixTreeNode* i = p; i && i->parent; i = i->parent) {
if (i == i->parent->left) {
if (--i->parent->balance == -2) {
zix_tree_rebalance(t, i->parent, &height_change);
break;
}
} else {
assert(i == i->parent->right);
if (++i->parent->balance == 2) {
zix_tree_rebalance(t, i->parent, &height_change);
break;
}
}
if (i->parent->balance == 0) {
break;
}
}
}
DUMP(t);
++t->size;
#ifdef ZIX_TREE_VERIFY
if (!verify(t, t->root)) {
return ZIX_STATUS_ERROR;
}
#endif
return ZIX_STATUS_SUCCESS;
}
ZixStatus
zix_tree_remove(ZixTree* t, ZixTreeIter* ti)
{
ZixTreeNode* const n = ti;
ZixTreeNode** pp = NULL; // parent pointer
ZixTreeNode* to_balance = n->parent; // lowest node to balance
int d_balance = 0; // delta(balance) for n->parent
DEBUG_PRINTF("*** REMOVE %ld\n", (intptr_t)n->data);
if ((n == t->root) && !n->left && !n->right) {
t->root = NULL;
if (t->destroy) {
t->destroy(n->data);
}
free(n);
--t->size;
assert(t->size == 0);
return ZIX_STATUS_SUCCESS;
}
// Set pp to the parent pointer to n, if applicable
if (n->parent) {
assert(n->parent->left == n || n->parent->right == n);
if (n->parent->left == n) { // n is left child
pp = &n->parent->left;
d_balance = 1;
} else { // n is right child
assert(n->parent->right == n);
pp = &n->parent->right;
d_balance = -1;
}
}
assert(!pp || *pp == n);
int height_change = 0;
if (!n->left && !n->right) {
// n is a leaf, just remove it
if (pp) {
*pp = NULL;
to_balance = n->parent;
height_change = (!n->parent->left && !n->parent->right) ? -1 : 0;
}
} else if (!n->left) {
// Replace n with right (only) child
if (pp) {
*pp = n->right;
to_balance = n->parent;
} else {
t->root = n->right;
}
n->right->parent = n->parent;
height_change = -1;
} else if (!n->right) {
// Replace n with left (only) child
if (pp) {
*pp = n->left;
to_balance = n->parent;
} else {
t->root = n->left;
}
n->left->parent = n->parent;
height_change = -1;
} else {
// Replace n with in-order successor (leftmost child of right subtree)
ZixTreeNode* replace = n->right;
while (replace->left) {
assert(replace->left->parent == replace);
replace = replace->left;
}
// Remove replace from parent (replace_p)
if (replace->parent->left == replace) {
height_change = replace->parent->right ? 0 : -1;
d_balance = 1;
to_balance = replace->parent;
replace->parent->left = replace->right;
} else {
assert(replace->parent == n);
height_change = replace->parent->left ? 0 : -1;
d_balance = -1;
to_balance = replace->parent;
replace->parent->right = replace->right;
}
if (to_balance == n) {
to_balance = replace;
}
if (replace->right) {
replace->right->parent = replace->parent;
}
replace->balance = n->balance;
// Swap node to delete with replace
if (pp) {
*pp = replace;
} else {
assert(t->root == n);
t->root = replace;
}
replace->parent = n->parent;
replace->left = n->left;
n->left->parent = replace;
replace->right = n->right;
if (n->right) {
n->right->parent = replace;
}
assert(!replace->parent || replace->parent->left == replace ||
replace->parent->right == replace);
}
// Rebalance starting at to_balance upwards.
for (ZixTreeNode* i = to_balance; i; i = i->parent) {
i->balance += d_balance;
if (d_balance == 0 || i->balance == -1 || i->balance == 1) {
break;
}
assert(i != n);
i = zix_tree_rebalance(t, i, &height_change);
if (i->balance == 0) {
height_change = -1;
}
if (i->parent) {
if (i == i->parent->left) {
d_balance = height_change * -1;
} else {
assert(i == i->parent->right);
d_balance = height_change;
}
}
}
DUMP(t);
if (t->destroy) {
t->destroy(n->data);
}
free(n);
--t->size;
#ifdef ZIX_TREE_VERIFY
if (!verify(t, t->root)) {
return ZIX_STATUS_ERROR;
}
#endif
return ZIX_STATUS_SUCCESS;
}
ZixStatus
zix_tree_find(const ZixTree* t, const void* e, ZixTreeIter** ti)
{
ZixTreeNode* n = t->root;
while (n) {
const int cmp = t->cmp(e, n->data, t->cmp_data);
if (cmp == 0) {
break;
}
if (cmp < 0) {
n = n->left;
} else {
n = n->right;
}
}
*ti = n;
return (n) ? ZIX_STATUS_SUCCESS : ZIX_STATUS_NOT_FOUND;
}
void*
zix_tree_get(const ZixTreeIter* ti)
{
return ti ? ti->data : NULL;
}
ZixTreeIter*
zix_tree_begin(ZixTree* t)
{
if (!t->root) {
return NULL;
}
ZixTreeNode* n = t->root;
while (n->left) {
n = n->left;
}
return n;
}
ZixTreeIter*
zix_tree_end(ZixTree* ZIX_UNUSED(t))
{
return NULL;
}
ZixTreeIter*
zix_tree_rbegin(ZixTree* t)
{
if (!t->root) {
return NULL;
}
ZixTreeNode* n = t->root;
while (n->right) {
n = n->right;
}
return n;
}
ZixTreeIter*
zix_tree_rend(ZixTree* ZIX_UNUSED(t))
{
return NULL;
}
bool
zix_tree_iter_is_end(const ZixTreeIter* i)
{
return !i;
}
bool
zix_tree_iter_is_rend(const ZixTreeIter* i)
{
return !i;
}
ZixTreeIter*
zix_tree_iter_next(ZixTreeIter* i)
{
if (!i) {
return NULL;
}
if (i->right) {
i = i->right;
while (i->left) {
i = i->left;
}
} else {
while (i->parent && i->parent->right == i) { // i is a right child
i = i->parent;
}
i = i->parent;
}
return i;
}
ZixTreeIter*
zix_tree_iter_prev(ZixTreeIter* i)
{
if (!i) {
return NULL;
}
if (i->left) {
i = i->left;
while (i->right) {
i = i->right;
}
} else {
while (i->parent && i->parent->left == i) { // i is a left child
i = i->parent;
}
i = i->parent;
}
return i;
}

View File

@@ -0,0 +1,164 @@
/*
Copyright 2011-2020 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ZIX_TREE_H
#define ZIX_TREE_H
#include "zix/common.h"
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
@addtogroup zix
@{
@name Tree
@{
*/
/**
A balanced binary search tree.
*/
typedef struct ZixTreeImpl ZixTree;
/**
An iterator over a @ref ZixTree.
*/
typedef struct ZixTreeNodeImpl ZixTreeIter;
/**
Create a new (empty) tree.
*/
ZIX_API
ZixTree*
zix_tree_new(bool allow_duplicates,
ZixComparator cmp,
void* cmp_data,
ZixDestroyFunc destroy);
/**
Free `t`.
*/
ZIX_API
void
zix_tree_free(ZixTree* t);
/**
Return the number of elements in `t`.
*/
ZIX_PURE_API
size_t
zix_tree_size(const ZixTree* t);
/**
Insert the element `e` into `t` and point `ti` at the new element.
*/
ZIX_API
ZixStatus
zix_tree_insert(ZixTree* t, void* e, ZixTreeIter** ti);
/**
Remove the item pointed at by `ti` from `t`.
*/
ZIX_API
ZixStatus
zix_tree_remove(ZixTree* t, ZixTreeIter* ti);
/**
Set `ti` to an element equal to `e` in `t`.
If no such item exists, `ti` is set to NULL.
*/
ZIX_API
ZixStatus
zix_tree_find(const ZixTree* t, const void* e, ZixTreeIter** ti);
/**
Return the data associated with the given tree item.
*/
ZIX_PURE_API
void*
zix_tree_get(const ZixTreeIter* ti);
/**
Return an iterator to the first (smallest) element in `t`.
*/
ZIX_PURE_API
ZixTreeIter*
zix_tree_begin(ZixTree* t);
/**
Return an iterator the the element one past the last element in `t`.
*/
ZIX_CONST_API
ZixTreeIter*
zix_tree_end(ZixTree* t);
/**
Return true iff `i` is an iterator to the end of its tree.
*/
ZIX_CONST_API
bool
zix_tree_iter_is_end(const ZixTreeIter* i);
/**
Return an iterator to the last (largest) element in `t`.
*/
ZIX_PURE_API
ZixTreeIter*
zix_tree_rbegin(ZixTree* t);
/**
Return an iterator the the element one before the first element in `t`.
*/
ZIX_CONST_API
ZixTreeIter*
zix_tree_rend(ZixTree* t);
/**
Return true iff `i` is an iterator to the reverse end of its tree.
*/
ZIX_CONST_API
bool
zix_tree_iter_is_rend(const ZixTreeIter* i);
/**
Return an iterator that points to the element one past `i`.
*/
ZIX_PURE_API
ZixTreeIter*
zix_tree_iter_next(ZixTreeIter* i);
/**
Return an iterator that points to the element one before `i`.
*/
ZIX_PURE_API
ZixTreeIter*
zix_tree_iter_prev(ZixTreeIter* i);
/**
@}
@}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ZIX_TREE_H */

View File

@@ -0,0 +1,33 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/*
Instead of providing a config header per lv2-related library, we put all
of the config in a single file, which is included below.
*/
#pragma once
#include "juce_lv2_config.h"

View File

@@ -0,0 +1,16 @@
Copyright 2006-2012 Steve Harris, David Robillard.
Based on LADSPA, Copyright 2000-2002 Richard W.E. Furse,
Paul Barton-Davis, Stefan Westerfeld.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,73 @@
/*
Copyright 2012-2018 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lv2/atom/atom.h"
#include "lv2/atom/forge.h"
#include "lv2/atom/util.h"
#include "lv2/log/log.h"
#include "lv2/urid/urid.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
static char** uris = NULL;
static uint32_t n_uris = 0;
static char*
copy_string(const char* str)
{
const size_t len = strlen(str);
char* dup = (char*)malloc(len + 1);
memcpy(dup, str, len + 1);
return dup;
}
static LV2_URID
urid_map(LV2_URID_Map_Handle handle, const char* uri)
{
for (uint32_t i = 0; i < n_uris; ++i) {
if (!strcmp(uris[i], uri)) {
return i + 1;
}
}
uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
uris[n_uris - 1] = copy_string(uri);
return n_uris;
}
static void
free_urid_map(void)
{
for (uint32_t i = 0; i < n_uris; ++i) {
free(uris[i]);
}
free(uris);
}
LV2_LOG_FUNC(1, 2)
static int
test_fail(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "error: ");
vfprintf(stderr, fmt, args);
va_end(args);
return 1;
}

View File

@@ -0,0 +1,367 @@
/*
Copyright 2012-2015 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lv2/atom/atom-test-utils.c"
#include "lv2/atom/atom.h"
#include "lv2/atom/forge.h"
#include "lv2/atom/util.h"
#include "lv2/urid/urid.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
LV2_URID_Map map = {NULL, urid_map};
LV2_Atom_Forge forge;
lv2_atom_forge_init(&forge, &map);
LV2_URID eg_Object = urid_map(NULL, "http://example.org/Object");
LV2_URID eg_one = urid_map(NULL, "http://example.org/one");
LV2_URID eg_two = urid_map(NULL, "http://example.org/two");
LV2_URID eg_three = urid_map(NULL, "http://example.org/three");
LV2_URID eg_four = urid_map(NULL, "http://example.org/four");
LV2_URID eg_true = urid_map(NULL, "http://example.org/true");
LV2_URID eg_false = urid_map(NULL, "http://example.org/false");
LV2_URID eg_path = urid_map(NULL, "http://example.org/path");
LV2_URID eg_uri = urid_map(NULL, "http://example.org/uri");
LV2_URID eg_urid = urid_map(NULL, "http://example.org/urid");
LV2_URID eg_string = urid_map(NULL, "http://example.org/string");
LV2_URID eg_literal = urid_map(NULL, "http://example.org/literal");
LV2_URID eg_tuple = urid_map(NULL, "http://example.org/tuple");
LV2_URID eg_vector = urid_map(NULL, "http://example.org/vector");
LV2_URID eg_vector2 = urid_map(NULL, "http://example.org/vector2");
LV2_URID eg_seq = urid_map(NULL, "http://example.org/seq");
#define BUF_SIZE 1024
#define NUM_PROPS 15
uint8_t buf[BUF_SIZE];
lv2_atom_forge_set_buffer(&forge, buf, BUF_SIZE);
LV2_Atom_Forge_Frame obj_frame;
LV2_Atom* obj = lv2_atom_forge_deref(
&forge, lv2_atom_forge_object(&forge, &obj_frame, 0, eg_Object));
// eg_one = (Int)1
lv2_atom_forge_key(&forge, eg_one);
LV2_Atom_Int* one =
(LV2_Atom_Int*)lv2_atom_forge_deref(&forge, lv2_atom_forge_int(&forge, 1));
if (one->body != 1) {
return test_fail("%d != 1\n", one->body);
}
// eg_two = (Long)2
lv2_atom_forge_key(&forge, eg_two);
LV2_Atom_Long* two = (LV2_Atom_Long*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_long(&forge, 2));
if (two->body != 2) {
return test_fail("%" PRId64 " != 2\n", two->body);
}
// eg_three = (Float)3.0
lv2_atom_forge_key(&forge, eg_three);
LV2_Atom_Float* three = (LV2_Atom_Float*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_float(&forge, 3.0f));
if (three->body != 3) {
return test_fail("%f != 3\n", three->body);
}
// eg_four = (Double)4.0
lv2_atom_forge_key(&forge, eg_four);
LV2_Atom_Double* four = (LV2_Atom_Double*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_double(&forge, 4.0));
if (four->body != 4) {
return test_fail("%f != 4\n", four->body);
}
// eg_true = (Bool)1
lv2_atom_forge_key(&forge, eg_true);
LV2_Atom_Bool* t = (LV2_Atom_Bool*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_bool(&forge, true));
if (t->body != 1) {
return test_fail("%d != 1 (true)\n", t->body);
}
// eg_false = (Bool)0
lv2_atom_forge_key(&forge, eg_false);
LV2_Atom_Bool* f = (LV2_Atom_Bool*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_bool(&forge, false));
if (f->body != 0) {
return test_fail("%d != 0 (false)\n", f->body);
}
// eg_path = (Path)"/foo/bar"
const char* pstr = "/foo/bar";
const uint32_t pstr_len = (uint32_t)strlen(pstr);
lv2_atom_forge_key(&forge, eg_path);
LV2_Atom_String* path = (LV2_Atom_String*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_uri(&forge, pstr, pstr_len));
char* pbody = (char*)LV2_ATOM_BODY(path);
if (strcmp(pbody, pstr)) {
return test_fail("%s != \"%s\"\n", pbody, pstr);
}
// eg_uri = (URI)"http://example.org/value"
const char* ustr = "http://example.org/value";
const uint32_t ustr_len = (uint32_t)strlen(ustr);
lv2_atom_forge_key(&forge, eg_uri);
LV2_Atom_String* uri = (LV2_Atom_String*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_uri(&forge, ustr, ustr_len));
char* ubody = (char*)LV2_ATOM_BODY(uri);
if (strcmp(ubody, ustr)) {
return test_fail("%s != \"%s\"\n", ubody, ustr);
}
// eg_urid = (URID)"http://example.org/value"
LV2_URID eg_value = urid_map(NULL, "http://example.org/value");
lv2_atom_forge_key(&forge, eg_urid);
LV2_Atom_URID* urid = (LV2_Atom_URID*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_urid(&forge, eg_value));
if (urid->body != eg_value) {
return test_fail("%u != %u\n", urid->body, eg_value);
}
// eg_string = (String)"hello"
lv2_atom_forge_key(&forge, eg_string);
LV2_Atom_String* string = (LV2_Atom_String*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_string(&forge, "hello", strlen("hello")));
char* sbody = (char*)LV2_ATOM_BODY(string);
if (strcmp(sbody, "hello")) {
return test_fail("%s != \"hello\"\n", sbody);
}
// eg_literal = (Literal)"hello"@fr
lv2_atom_forge_key(&forge, eg_literal);
LV2_Atom_Literal* literal = (LV2_Atom_Literal*)lv2_atom_forge_deref(
&forge,
lv2_atom_forge_literal(&forge,
"bonjour",
strlen("bonjour"),
0,
urid_map(NULL, "http://lexvo.org/id/term/fr")));
char* lbody = (char*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal);
if (strcmp(lbody, "bonjour")) {
return test_fail("%s != \"bonjour\"\n", lbody);
}
// eg_tuple = "foo",true
lv2_atom_forge_key(&forge, eg_tuple);
LV2_Atom_Forge_Frame tuple_frame;
LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_tuple(&forge, &tuple_frame));
LV2_Atom_String* tup0 = (LV2_Atom_String*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_string(&forge, "foo", strlen("foo")));
LV2_Atom_Bool* tup1 = (LV2_Atom_Bool*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_bool(&forge, true));
lv2_atom_forge_pop(&forge, &tuple_frame);
LV2_Atom* i = lv2_atom_tuple_begin(tuple);
if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
return test_fail("Tuple iterator is empty\n");
}
LV2_Atom* tup0i = i;
if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) {
return test_fail("Corrupt tuple element 0\n");
}
i = lv2_atom_tuple_next(i);
if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
return test_fail("Premature end of tuple iterator\n");
}
LV2_Atom* tup1i = i;
if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) {
return test_fail("Corrupt tuple element 1\n");
}
i = lv2_atom_tuple_next(i);
if (!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
return test_fail("Tuple iter is not at end\n");
}
// eg_vector = (Vector<Int>)1,2,3,4
lv2_atom_forge_key(&forge, eg_vector);
int32_t elems[] = {1, 2, 3, 4};
LV2_Atom_Vector* vector = (LV2_Atom_Vector*)lv2_atom_forge_deref(
&forge,
lv2_atom_forge_vector(&forge, sizeof(int32_t), forge.Int, 4, elems));
void* vec_body = LV2_ATOM_CONTENTS(LV2_Atom_Vector, vector);
if (memcmp(elems, vec_body, sizeof(elems))) {
return test_fail("Corrupt vector\n");
}
// eg_vector2 = (Vector<Int>)1,2,3,4
lv2_atom_forge_key(&forge, eg_vector2);
LV2_Atom_Forge_Frame vec_frame;
LV2_Atom_Vector* vector2 = (LV2_Atom_Vector*)lv2_atom_forge_deref(
&forge,
lv2_atom_forge_vector_head(&forge, &vec_frame, sizeof(int32_t), forge.Int));
for (unsigned e = 0; e < sizeof(elems) / sizeof(int32_t); ++e) {
lv2_atom_forge_int(&forge, elems[e]);
}
lv2_atom_forge_pop(&forge, &vec_frame);
if (!lv2_atom_equals(&vector->atom, &vector2->atom)) {
return test_fail("Vector != Vector2\n");
}
// eg_seq = (Sequence)1, 2
lv2_atom_forge_key(&forge, eg_seq);
LV2_Atom_Forge_Frame seq_frame;
LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_deref(
&forge, lv2_atom_forge_sequence_head(&forge, &seq_frame, 0));
lv2_atom_forge_frame_time(&forge, 0);
lv2_atom_forge_int(&forge, 1);
lv2_atom_forge_frame_time(&forge, 1);
lv2_atom_forge_int(&forge, 2);
lv2_atom_forge_pop(&forge, &seq_frame);
lv2_atom_forge_pop(&forge, &obj_frame);
// Test equality
LV2_Atom_Int itwo = {{forge.Int, sizeof(int32_t)}, 2};
if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)two)) {
return test_fail("1 == 2.0\n");
} else if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)&itwo)) {
return test_fail("1 == 2\n");
} else if (!lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)one)) {
return test_fail("1 != 1\n");
}
unsigned n_events = 0;
LV2_ATOM_SEQUENCE_FOREACH (seq, ev) {
if (ev->time.frames != n_events) {
return test_fail("Corrupt event %u has bad time\n", n_events);
} else if (ev->body.type != forge.Int) {
return test_fail("Corrupt event %u has bad type\n", n_events);
} else if (((LV2_Atom_Int*)&ev->body)->body != (int)n_events + 1) {
return test_fail("Event %u != %u\n", n_events, n_events + 1);
}
++n_events;
}
int n_props = 0;
LV2_ATOM_OBJECT_FOREACH ((LV2_Atom_Object*)obj, prop) {
if (!prop->key) {
return test_fail("Corrupt property %d has no key\n", n_props);
} else if (prop->context) {
return test_fail("Corrupt property %d has context\n", n_props);
}
++n_props;
}
if (n_props != NUM_PROPS) {
return test_fail(
"Corrupt object has %d properties != %d\n", n_props, NUM_PROPS);
}
struct {
const LV2_Atom* one;
const LV2_Atom* two;
const LV2_Atom* three;
const LV2_Atom* four;
const LV2_Atom* affirmative;
const LV2_Atom* negative;
const LV2_Atom* path;
const LV2_Atom* uri;
const LV2_Atom* urid;
const LV2_Atom* string;
const LV2_Atom* literal;
const LV2_Atom* tuple;
const LV2_Atom* vector;
const LV2_Atom* vector2;
const LV2_Atom* seq;
} matches;
memset(&matches, 0, sizeof(matches));
LV2_Atom_Object_Query q[] = {{eg_one, &matches.one},
{eg_two, &matches.two},
{eg_three, &matches.three},
{eg_four, &matches.four},
{eg_true, &matches.affirmative},
{eg_false, &matches.negative},
{eg_path, &matches.path},
{eg_uri, &matches.uri},
{eg_urid, &matches.urid},
{eg_string, &matches.string},
{eg_literal, &matches.literal},
{eg_tuple, &matches.tuple},
{eg_vector, &matches.vector},
{eg_vector2, &matches.vector2},
{eg_seq, &matches.seq},
LV2_ATOM_OBJECT_QUERY_END};
int n_matches = lv2_atom_object_query((LV2_Atom_Object*)obj, q);
for (int n = 0; n < 2; ++n) {
if (n_matches != n_props) {
return test_fail("Query failed, %d matches != %d\n", n_matches, n_props);
} else if (!lv2_atom_equals((LV2_Atom*)one, matches.one)) {
return test_fail("Bad match one\n");
} else if (!lv2_atom_equals((LV2_Atom*)two, matches.two)) {
return test_fail("Bad match two\n");
} else if (!lv2_atom_equals((LV2_Atom*)three, matches.three)) {
return test_fail("Bad match three\n");
} else if (!lv2_atom_equals((LV2_Atom*)four, matches.four)) {
return test_fail("Bad match four\n");
} else if (!lv2_atom_equals((LV2_Atom*)t, matches.affirmative)) {
return test_fail("Bad match true\n");
} else if (!lv2_atom_equals((LV2_Atom*)f, matches.negative)) {
return test_fail("Bad match false\n");
} else if (!lv2_atom_equals((LV2_Atom*)path, matches.path)) {
return test_fail("Bad match path\n");
} else if (!lv2_atom_equals((LV2_Atom*)uri, matches.uri)) {
return test_fail("Bad match URI\n");
} else if (!lv2_atom_equals((LV2_Atom*)string, matches.string)) {
return test_fail("Bad match string\n");
} else if (!lv2_atom_equals((LV2_Atom*)literal, matches.literal)) {
return test_fail("Bad match literal\n");
} else if (!lv2_atom_equals((LV2_Atom*)tuple, matches.tuple)) {
return test_fail("Bad match tuple\n");
} else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector)) {
return test_fail("Bad match vector\n");
} else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector2)) {
return test_fail("Bad match vector2\n");
} else if (!lv2_atom_equals((LV2_Atom*)seq, matches.seq)) {
return test_fail("Bad match sequence\n");
}
memset(&matches, 0, sizeof(matches));
// clang-format off
n_matches = lv2_atom_object_get((LV2_Atom_Object*)obj,
eg_one, &matches.one,
eg_two, &matches.two,
eg_three, &matches.three,
eg_four, &matches.four,
eg_true, &matches.affirmative,
eg_false, &matches.negative,
eg_path, &matches.path,
eg_uri, &matches.uri,
eg_urid, &matches.urid,
eg_string, &matches.string,
eg_literal, &matches.literal,
eg_tuple, &matches.tuple,
eg_vector, &matches.vector,
eg_vector2, &matches.vector2,
eg_seq, &matches.seq,
0);
// clang-format on
}
free_urid_map();
return 0;
}

View File

@@ -0,0 +1,260 @@
/*
Copyright 2008-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_ATOM_H
#define LV2_ATOM_H
/**
@defgroup atom Atom
@ingroup lv2
A generic value container and several data types.
See <http://lv2plug.in/ns/ext/atom> for details.
@{
*/
#include <stdint.h>
// clang-format off
#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" ///< http://lv2plug.in/ns/ext/atom
#define LV2_ATOM_PREFIX LV2_ATOM_URI "#" ///< http://lv2plug.in/ns/ext/atom#
#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom" ///< http://lv2plug.in/ns/ext/atom#Atom
#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort" ///< http://lv2plug.in/ns/ext/atom#AtomPort
#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank" ///< http://lv2plug.in/ns/ext/atom#Blank
#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool" ///< http://lv2plug.in/ns/ext/atom#Bool
#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk" ///< http://lv2plug.in/ns/ext/atom#Chunk
#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double" ///< http://lv2plug.in/ns/ext/atom#Double
#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event" ///< http://lv2plug.in/ns/ext/atom#Event
#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float" ///< http://lv2plug.in/ns/ext/atom#Float
#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int" ///< http://lv2plug.in/ns/ext/atom#Int
#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal" ///< http://lv2plug.in/ns/ext/atom#Literal
#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long" ///< http://lv2plug.in/ns/ext/atom#Long
#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number" ///< http://lv2plug.in/ns/ext/atom#Number
#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object" ///< http://lv2plug.in/ns/ext/atom#Object
#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path" ///< http://lv2plug.in/ns/ext/atom#Path
#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property" ///< http://lv2plug.in/ns/ext/atom#Property
#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource" ///< http://lv2plug.in/ns/ext/atom#Resource
#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence" ///< http://lv2plug.in/ns/ext/atom#Sequence
#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound" ///< http://lv2plug.in/ns/ext/atom#Sound
#define LV2_ATOM__String LV2_ATOM_PREFIX "String" ///< http://lv2plug.in/ns/ext/atom#String
#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple" ///< http://lv2plug.in/ns/ext/atom#Tuple
#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI" ///< http://lv2plug.in/ns/ext/atom#URI
#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID" ///< http://lv2plug.in/ns/ext/atom#URID
#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector" ///< http://lv2plug.in/ns/ext/atom#Vector
#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer" ///< http://lv2plug.in/ns/ext/atom#atomTransfer
#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime" ///< http://lv2plug.in/ns/ext/atom#beatTime
#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType" ///< http://lv2plug.in/ns/ext/atom#bufferType
#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType" ///< http://lv2plug.in/ns/ext/atom#childType
#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer" ///< http://lv2plug.in/ns/ext/atom#eventTransfer
#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime" ///< http://lv2plug.in/ns/ext/atom#frameTime
#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports" ///< http://lv2plug.in/ns/ext/atom#supports
#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit" ///< http://lv2plug.in/ns/ext/atom#timeUnit
// clang-format on
#define LV2_ATOM_REFERENCE_TYPE 0 ///< The special type for a reference atom
#ifdef __cplusplus
extern "C" {
#endif
/** @cond */
/** This expression will fail to compile if double does not fit in 64 bits. */
typedef char lv2_atom_assert_double_fits_in_64_bits
[((sizeof(double) <= sizeof(uint64_t)) * 2) - 1];
/** @endcond */
/**
Return a pointer to the contents of an Atom. The "contents" of an atom
is the data past the complete type-specific header.
@param type The type of the atom, for example LV2_Atom_String.
@param atom A variable-sized atom.
*/
#define LV2_ATOM_CONTENTS(type, atom) ((void*)((uint8_t*)(atom) + sizeof(type)))
/**
Const version of LV2_ATOM_CONTENTS.
*/
#define LV2_ATOM_CONTENTS_CONST(type, atom) \
((const void*)((const uint8_t*)(atom) + sizeof(type)))
/**
Return a pointer to the body of an Atom. The "body" of an atom is the
data just past the LV2_Atom head (i.e. the same offset for all types).
*/
#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom)
/**
Const version of LV2_ATOM_BODY.
*/
#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom)
/** The header of an atom:Atom. */
typedef struct {
uint32_t size; /**< Size in bytes, not including type and size. */
uint32_t type; /**< Type of this atom (mapped URI). */
} LV2_Atom;
/** An atom:Int or atom:Bool. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
int32_t body; /**< Integer value. */
} LV2_Atom_Int;
/** An atom:Long. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
int64_t body; /**< Integer value. */
} LV2_Atom_Long;
/** An atom:Float. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
float body; /**< Floating point value. */
} LV2_Atom_Float;
/** An atom:Double. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
double body; /**< Floating point value. */
} LV2_Atom_Double;
/** An atom:Bool. May be cast to LV2_Atom. */
typedef LV2_Atom_Int LV2_Atom_Bool;
/** An atom:URID. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
uint32_t body; /**< URID. */
} LV2_Atom_URID;
/** An atom:String. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
/* Contents (a null-terminated UTF-8 string) follow here. */
} LV2_Atom_String;
/** The body of an atom:Literal. */
typedef struct {
uint32_t datatype; /**< Datatype URID. */
uint32_t lang; /**< Language URID. */
/* Contents (a null-terminated UTF-8 string) follow here. */
} LV2_Atom_Literal_Body;
/** An atom:Literal. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
LV2_Atom_Literal_Body body; /**< Body. */
} LV2_Atom_Literal;
/** An atom:Tuple. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
/* Contents (a series of complete atoms) follow here. */
} LV2_Atom_Tuple;
/** The body of an atom:Vector. */
typedef struct {
uint32_t child_size; /**< The size of each element in the vector. */
uint32_t child_type; /**< The type of each element in the vector. */
/* Contents (a series of packed atom bodies) follow here. */
} LV2_Atom_Vector_Body;
/** An atom:Vector. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
LV2_Atom_Vector_Body body; /**< Body. */
} LV2_Atom_Vector;
/** The body of an atom:Property (typically in an atom:Object). */
typedef struct {
uint32_t key; /**< Key (predicate) (mapped URI). */
uint32_t context; /**< Context URID (may be, and generally is, 0). */
LV2_Atom value; /**< Value atom header. */
/* Value atom body follows here. */
} LV2_Atom_Property_Body;
/** An atom:Property. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
LV2_Atom_Property_Body body; /**< Body. */
} LV2_Atom_Property;
/** The body of an atom:Object. May be cast to LV2_Atom. */
typedef struct {
uint32_t id; /**< URID, or 0 for blank. */
uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */
/* Contents (a series of property bodies) follow here. */
} LV2_Atom_Object_Body;
/** An atom:Object. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
LV2_Atom_Object_Body body; /**< Body. */
} LV2_Atom_Object;
/** The header of an atom:Event. Note this type is NOT an LV2_Atom. */
typedef struct {
/** Time stamp. Which type is valid is determined by context. */
union {
int64_t frames; /**< Time in audio frames. */
double beats; /**< Time in beats. */
} time;
LV2_Atom body; /**< Event body atom header. */
/* Body atom contents follow here. */
} LV2_Atom_Event;
/**
The body of an atom:Sequence (a sequence of events).
The unit field is either a URID that described an appropriate time stamp
type, or may be 0 where a default stamp type is known. For
LV2_Descriptor::run(), the default stamp type is audio frames.
The contents of a sequence is a series of LV2_Atom_Event, each aligned
to 64-bits, for example:
<pre>
| Event 1 (size 6) | Event 2
| | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|FRAMES |SUBFRMS|TYPE |SIZE |DATADATADATAPAD|FRAMES |SUBFRMS|...
</pre>
*/
typedef struct {
uint32_t unit; /**< URID of unit of event time stamps. */
uint32_t pad; /**< Currently unused. */
/* Contents (a series of events) follow here. */
} LV2_Atom_Sequence_Body;
/** An atom:Sequence. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
LV2_Atom_Sequence_Body body; /**< Body. */
} LV2_Atom_Sequence;
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
*/
#endif /* LV2_ATOM_H */

View File

@@ -0,0 +1,542 @@
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/atom>
a doap:Project ;
doap:name "LV2 Atom" ;
doap:shortdesc "A generic value container and several data types." ;
doap:license <http://opensource.org/licenses/isc> ;
doap:created "2007-00-00" ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "2.2" ;
doap:created "2019-02-03" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add lv2_atom_object_get_typed() for easy type-safe access to object properties."
]
]
] , [
doap:revision "2.0" ;
doap:created "2014-08-08" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Deprecate Blank and Resource in favour of just Object."
] , [
rdfs:label "Add lv2_atom_forge_is_object_type() and lv2_atom_forge_is_blank() to ease backwards compatibility."
] , [
rdfs:label "Add lv2_atom_forge_key() for terser object writing."
] , [
rdfs:label "Add lv2_atom_sequence_clear() and lv2_atom_sequence_append_event() helper functions."
]
]
] , [
doap:revision "1.8" ;
doap:created "2014-01-04" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.8.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Make lv2_atom_*_is_end() arguments const."
]
]
] , [
doap:revision "1.6" ;
doap:created "2013-05-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.6.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix crash in forge.h when pushing atoms to a full buffer."
]
]
] , [
doap:revision "1.4" ;
doap:created "2013-01-27" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix lv2_atom_sequence_end()."
] , [
rdfs:label "Remove atom:stringType in favour of owl:onDatatype so generic tools can understand and validate atom literals."
] , [
rdfs:label "Improve atom documentation."
]
]
] , [
doap:revision "1.2" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix implicit conversions in forge.h that are invalid in C++11."
] , [
rdfs:label "Fix lv2_atom_object_next() on 32-bit platforms."
] , [
rdfs:label "Add lv2_atom_object_body_get()."
] , [
rdfs:label "Fix outdated documentation in forge.h."
] , [
rdfs:label "Use consistent label style."
] , [
rdfs:label "Add LV2_ATOM_CONTENTS_CONST and LV2_ATOM_BODY_CONST."
]
]
] , [
doap:revision "1.0" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
An atom:Atom is a simple generic data container for holding any type of Plain
Old Data (POD). An Atom can contain simple primitive types like integers,
floating point numbers, and strings; as well as structured data like lists and
dictionary-like <q>Objects</q>. Since Atoms are POD, they can be easily copied
(for example, with `memcpy()`) anywhere and are suitable for use in real-time
code.
Every atom starts with an LV2_Atom header, followed by the contents. This
allows code to process atoms without requiring special code for every type of
data. For example, plugins that mutually understand a type can be used
together in a host that does not understand that type, because the host is only
required to copy atoms, not interpret their contents. Similarly, plugins (such
as routers, delays, or data structures) can meaningfully process atoms of a
type unknown to them.
Atoms should be used anywhere values of various types must be stored or
transmitted. An atom:AtomPort can be used to transmit atoms via ports. An
atom:AtomPort that contains a atom:Sequence can be used for sample accurate
communication of events, such as MIDI.
### Serialisation
Each Atom type defines a binary format for use at runtime, but also a
serialisation that is natural to express in Turtle format. Thus, this
specification defines a powerful real-time appropriate data model, as well as a
portable way to serialise any data in that model. This is particularly useful
for inter-process communication, saving/restoring state, and describing values
in plugin data files.
### Custom Atom Types
While it is possible to define new Atom types for any binary format, the
standard types defined here are powerful enough to describe almost anything.
Implementations SHOULD build structures out of the types provided here, rather
than define new binary formats (for example, using atom:Object rather than a
new C `struct` type). Host and tool implementations have support for
serialising all standard types, so new binary formats are an implementation
burden which harms interoperabilty. In particular, plugins SHOULD NOT expect
UI communication or state saving with custom binary types to work. In general,
new Atom types should only be defined where absolutely necessary due to
performance reasons and serialisation is not a concern.
"""^^lv2:Markdown .
atom:Atom
lv2:documentation """
An LV2_Atom has a 32-bit `size` and `type`, followed by a body of `size` bytes.
Atoms MUST be 64-bit aligned.
All concrete Atom types (subclasses of this class) MUST define a precise binary
layout for their body.
The `type` field is the URI of an Atom type mapped to an integer.
Implementations SHOULD gracefully pass through, or ignore, atoms with unknown
types.
All atoms are POD by definition except references, which as a special case have
`type` 0. An Atom MUST NOT contain a Reference. It is safe to copy any
non-reference Atom with a simple `memcpy`, even if the implementation does not
understand `type`. Though this extension reserves the type 0 for references,
the details of reference handling are currently unspecified. A future revision
of this extension, or a different extension, may define how to use non-POD data
and references. Implementations MUST NOT send references to another
implementation unless the receiver is explicitly known to support references
(e.g. by supporting a feature).
The special case of a null atom with both `type` and `size` 0 is not considered
a reference.
"""^^lv2:Markdown .
atom:Chunk
lv2:documentation """
This type is used to indicate a certain amount of space is available. For
example, output ports with a variably sized type are connected to a Chunk so
the plugin knows the size of the buffer available for writing.
The use of a Chunk should be constrained to a local scope, since
interpreting it is impossible without context. However, if serialised to RDF,
a Chunk may be represented directly as an xsd:base64Binary string, for example:
:::turtle
[] eg:someChunk "vu/erQ=="^^xsd:base64Binary .
"""^^lv2:Markdown .
atom:String
lv2:documentation """
The body of an LV2_Atom_String is a C string in UTF-8 encoding, i.e. an array
of bytes (`uint8_t`) terminated with a NULL byte (`'\\0'`).
This type is for free-form strings, but SHOULD NOT be used for typed data or
text in any language. Use atom:Literal unless translating the string does not
make sense and the string has no meaningful datatype.
"""^^lv2:Markdown .
atom:Literal
lv2:documentation """
This type is compatible with rdfs:Literal and is capable of expressing a
string in any language or a value of any type. A Literal has a
`datatype` and `lang` followed by string data in UTF-8
encoding. The length of the string data in bytes is `size -
sizeof(LV2_Atom_Literal)`, including the terminating NULL character. The
`lang` field SHOULD be a URI of the form
`http://lexvo.org/id/iso639-3/LANG` or
`http://lexvo.org/id/iso639-1/LANG` where LANG is a 3-character ISO 693-3
language code, or a 2-character ISO 693-1 language code, respectively.
A Literal may have a `datatype` or a `lang`, but never both.
For example, a Literal can be <q>Hello</q> in English:
:::c
void set_to_hello_in_english(LV2_Atom_Literal* lit) {
lit->atom.type = map(expand("atom:Literal"));
lit->atom.size = 14;
lit->body.datatype = 0;
lit->body.lang = map("http://lexvo.org/id/iso639-1/en");
memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit),
"Hello",
sizeof("Hello")); // Assumes enough space
}
or a Turtle string:
:::c
void set_to_turtle_string(LV2_Atom_Literal* lit, const char* ttl) {
lit->atom.type = map(expand("atom:Literal"));
lit->atom.size = 64;
lit->body.datatype = map("http://www.w3.org/2008/turtle#turtle");
lit->body.lang = 0;
memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit),
ttl,
strlen(ttl) + 1); // Assumes enough space
}
"""^^lv2:Markdown .
atom:Path
lv2:documentation """
A Path is a URI reference with only a path component: no scheme, authority,
query, or fragment. In particular, paths to files in the same bundle may be
cleanly written in Turtle files as a relative URI. However, implementations
may assume any binary Path (e.g. in an event payload) is a valid file path
which can passed to system functions like fopen() directly, without any
character encoding or escape expansion required.
Any implemenation that creates a Path atom to transmit to another is
responsible for ensuring it is valid. A Path SHOULD always be absolute, unless
there is some mechanism in place that defines a base path. Since this is not
the case for plugin instances, effectively any Path sent to or received from a
plugin instance MUST be absolute.
"""^^lv2:Markdown .
atom:URI
lv2:documentation """
This is useful when a URI is needed but mapping is inappropriate, for example
with temporary or relative URIs. Since the ability to distinguish URIs from
plain strings is often necessary, URIs MUST NOT be transmitted as atom:String.
This is not strictly a URI, since UTF-8 is allowed. Escaping and related
issues are the host's responsibility.
"""^^lv2:Markdown .
atom:URID
lv2:documentation """
A URID is typically generated with the LV2_URID_Map provided by the host .
"""^^lv2:Markdown .
atom:Vector
lv2:documentation """
A homogeneous series of atom bodies with equivalent type and size.
An LV2_Atom_Vector is a 32-bit `child_size` and `child_type` followed by `size
/ child_size` atom bodies.
For example, an atom:Vector containing 42 elements of type atom:Float:
:::c
struct VectorOf42Floats {
uint32_t size; // sizeof(LV2_Atom_Vector_Body) + (42 * sizeof(float);
uint32_t type; // map(expand("atom:Vector"))
uint32_t child_size; // sizeof(float)
uint32_t child_type; // map(expand("atom:Float"))
float elems[42];
};
Note that it is possible to construct a valid Atom for each element of the
vector, even by an implementation which does not understand `child_type`.
If serialised to RDF, a Vector SHOULD have the form:
:::turtle
eg:someVector
a atom:Vector ;
atom:childType atom:Int ;
rdf:value (
"1"^^xsd:int
"2"^^xsd:int
"3"^^xsd:int
"4"^^xsd:int
) .
"""^^lv2:Markdown .
atom:Tuple
lv2:documentation """
The body of a Tuple is simply a series of complete atoms, each aligned to
64 bits.
If serialised to RDF, a Tuple SHOULD have the form:
:::turtle
eg:someVector
a atom:Tuple ;
rdf:value (
"1"^^xsd:int
"3.5"^^xsd:float
"etc"
) .
"""^^lv2:Markdown .
atom:Property
lv2:documentation """
An LV2_Atom_Property has a URID `key` and `context`, and an Atom `value`. This
corresponds to an RDF Property, where the <q>key</q> is the <q>predicate</q>
and the <q>value</q> is the object.
The `context` field can be used to specify a different context for each
property, where this is useful. Otherwise, it may be 0.
Properties generally only exist as part of an atom:Object. Accordingly,
they will typically be represented directly as properties in RDF (see
atom:Object). If this is not possible, they may be expressed as partial
reified statements, for example:
:::turtle
eg:someProperty
rdf:predicate eg:theKey ;
rdf:object eg:theValue .
"""^^lv2:Markdown .
atom:Object
lv2:documentation """
An <q>Object</q> is an atom with a set of properties. This corresponds to an
RDF Resource, and can be thought of as a dictionary with URID keys.
An LV2_Atom_Object body has a uint32_t `id` and `type`, followed by a series of
atom:Property bodies (LV2_Atom_Property_Body). The LV2_Atom_Object_Body::otype
field is equivalent to a property with key rdf:type, but is included in the
structure to allow for fast dispatching.
Code SHOULD check for objects using lv2_atom_forge_is_object() or
lv2_atom_forge_is_blank() if a forge is available, rather than checking the
atom type directly. This will correctly handle the deprecated atom:Resource
and atom:Blank types.
When serialised to RDF, an Object is represented as a resource, for example:
:::turtle
eg:someObject
eg:firstPropertyKey "first property value" ;
eg:secondPropertyKey "first loser" ;
eg:andSoOn "and so on" .
"""^^lv2:Markdown .
atom:Resource
lv2:documentation """
This class is deprecated. Use atom:Object directly instead.
An atom:Object where the <code>id</code> field is a URID, that is, an Object
with a URI.
"""^^lv2:Markdown .
atom:Blank
lv2:documentation """
This class is deprecated. Use atom:Object with ID 0 instead.
An atom:Object where the LV2_Atom_Object::id is a blank node ID (NOT a URI).
The ID of a Blank is valid only within the context the Blank appears in. For
ports this is the context of the associated run() call, i.e. all ports share
the same context so outputs can contain IDs that correspond to IDs of blanks in
the input.
"""^^lv2:Markdown .
atom:Sound
lv2:documentation """
The format of a atom:Sound is the same as the buffer format for lv2:AudioPort
(except the size may be arbitrary). An atom:Sound inherently depends on the
sample rate, which is assumed to be known from context. Because of this,
directly serialising an atom:Sound is probably a bad idea, use a standard
format like WAV instead.
"""^^lv2:Markdown .
atom:Event
lv2:documentation """
An Event is typically an element of an atom:Sequence. Note that this is not an Atom type since it begins with a timestamp, not an atom header.
"""^^lv2:Markdown .
atom:Sequence
lv2:documentation """
A flat sequence of atom:Event, that is, a series of time-stamped Atoms.
LV2_Atom_Sequence_Body.unit describes the time unit for the contained atoms.
If the unit is known from context (e.g. run() stamps are always audio frames),
this field may be zero. Otherwise, it SHOULD be either units:frame or
units:beat, in which case ev.time.frames or ev.time.beats is valid,
respectively.
If serialised to RDF, a Sequence has a similar form to atom:Vector, but for
brevity the elements may be assumed to be atom:Event, for example:
:::turtle
eg:someSequence
a atom:Sequence ;
rdf:value (
[
atom:frameTime 1 ;
rdf:value "901A01"^^midi:MidiEvent
] [
atom:frameTime 3 ;
rdf:value "902B02"^^midi:MidiEvent
]
) .
"""^^lv2:Markdown .
atom:AtomPort
lv2:documentation """
Ports of this type are connected to an LV2_Atom with a type specified by
atom:bufferType.
Output ports with a variably sized type MUST be initialised by the host before
every run() to an atom:Chunk with size set to the available space. The plugin
reads this size to know how much space is available for writing. In all cases,
the plugin MUST write a complete atom (including header) to outputs. However,
to be robust, hosts SHOULD initialise output ports to a safe sentinel (e.g. the
null Atom) before calling run().
"""^^lv2:Markdown .
atom:bufferType
lv2:documentation """
Indicates that an AtomPort may be connected to a certain Atom type. A port MAY
support several buffer types. The host MUST NOT connect a port to an Atom with
a type not explicitly listed with this property. The value of this property
MUST be a sub-class of atom:Atom. For example, an input port that is connected
directly to an LV2_Atom_Double value is described like so:
:::turtle
<plugin>
lv2:port [
a lv2:InputPort , atom:AtomPort ;
atom:bufferType atom:Double ;
] .
This property only describes the types a port may be directly connected to. It
says nothing about the expected contents of containers. For that, use
atom:supports.
"""^^lv2:Markdown .
atom:supports
lv2:documentation """
This property is defined loosely, it may be used to indicate that anything
<q>supports</q> an Atom type, wherever that may be useful. It applies
<q>recursively</q> where collections are involved.
In particular, this property can be used to describe which event types are
expected by a port. For example, a port that receives MIDI events is described
like so:
:::turtle
<plugin>
lv2:port [
a lv2:InputPort , atom:AtomPort ;
atom:bufferType atom:Sequence ;
atom:supports midi:MidiEvent ;
] .
"""^^lv2:Markdown .
atom:eventTransfer
lv2:documentation """
Transfer of individual events in a port buffer. Useful as the `format` for a
LV2UI_Write_Function.
This protocol applies to ports which contain events, usually in an
atom:Sequence. The host must transfer each individual event to the recipient.
The format of the received data is an LV2_Atom, there is no timestamp header.
"""^^lv2:Markdown .
atom:atomTransfer
lv2:documentation """
Transfer of the complete atom in a port buffer. Useful as the `format` for a
LV2UI_Write_Function.
This protocol applies to atom ports. The host must transfer the complete atom
contained in the port, including header.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,247 @@
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/atom>
a owl:Ontology ;
rdfs:seeAlso <atom.h> ,
<util.h> ,
<forge.h> ,
<atom.meta.ttl> ;
rdfs:label "LV2 Atom" ;
rdfs:comment "A generic value container and several data types." .
atom:cType
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "C type" ;
rdfs:comment "The C type that describes the binary representation of an Atom type." ;
rdfs:domain rdfs:Class ;
rdfs:range lv2:Symbol .
atom:Atom
a rdfs:Class ;
rdfs:label "Atom" ;
rdfs:comment "Abstract base class for all atoms." ;
atom:cType "LV2_Atom" .
atom:Chunk
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Chunk" ;
rdfs:comment "A chunk of memory with undefined contents." ;
owl:onDatatype xsd:base64Binary .
atom:Number
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Number" ;
rdfs:comment "Base class for numeric types." .
atom:Int
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:Number ;
rdfs:label "Int" ;
rdfs:comment "A native `int32_t`." ;
atom:cType "LV2_Atom_Int" ;
owl:onDatatype xsd:int .
atom:Long
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:Number ;
rdfs:label "Long" ;
rdfs:comment "A native `int64_t`." ;
atom:cType "LV2_Atom_Long" ;
owl:onDatatype xsd:long .
atom:Float
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:Number ;
rdfs:label "Float" ;
rdfs:comment "A native `float`." ;
atom:cType "LV2_Atom_Float" ;
owl:onDatatype xsd:float .
atom:Double
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:Number ;
rdfs:label "Double" ;
rdfs:comment "A native `double`." ;
atom:cType "LV2_Atom_Double" ;
owl:onDatatype xsd:double .
atom:Bool
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Bool" ;
rdfs:comment "An atom:Int where 0 is false and any other value is true." ;
atom:cType "LV2_Atom_Bool" ;
owl:onDatatype xsd:boolean .
atom:String
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:Atom ;
rdfs:label "String" ;
rdfs:comment "A UTF-8 string." ;
atom:cType "LV2_Atom_String" ;
owl:onDatatype xsd:string .
atom:Literal
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Literal" ;
rdfs:comment "A UTF-8 string literal with optional datatype or language." ;
atom:cType "LV2_Atom_Literal" .
atom:Path
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:URI ;
owl:onDatatype atom:URI ;
rdfs:label "Path" ;
rdfs:comment "A local file path." .
atom:URI
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf atom:String ;
owl:onDatatype xsd:anyURI ;
rdfs:label "URI" ;
rdfs:comment "A URI string." .
atom:URID
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "URID" ;
rdfs:comment "An unsigned 32-bit integer ID for a URI." ;
atom:cType "LV2_Atom_URID" .
atom:Vector
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Vector" ;
rdfs:comment "A homogeneous sequence of atom bodies with equivalent type and size." ;
atom:cType "LV2_Atom_Vector" .
atom:Tuple
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Tuple" ;
rdfs:comment "A sequence of atoms with varying type and size." .
atom:Property
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Property" ;
rdfs:comment "A property of an atom:Object." ;
atom:cType "LV2_Atom_Property" .
atom:Object
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Object" ;
rdfs:comment "A collection of properties." ;
atom:cType "LV2_Atom_Object" .
atom:Resource
a rdfs:Class ;
rdfs:subClassOf atom:Object ;
rdfs:label "Resource" ;
rdfs:comment "A named collection of properties with a URI." ;
owl:deprecated "true"^^xsd:boolean ;
atom:cType "LV2_Atom_Object" .
atom:Blank
a rdfs:Class ;
rdfs:subClassOf atom:Object ;
rdfs:label "Blank" ;
rdfs:comment "An anonymous collection of properties without a URI." ;
owl:deprecated "true"^^xsd:boolean ;
atom:cType "LV2_Atom_Object" .
atom:Sound
a rdfs:Class ;
rdfs:subClassOf atom:Vector ;
rdfs:label "Sound" ;
rdfs:comment "A atom:Vector of atom:Float which represents an audio waveform." ;
atom:cType "LV2_Atom_Vector" .
atom:frameTime
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:range xsd:decimal ;
rdfs:label "frame time" ;
rdfs:comment "A time stamp in audio frames." .
atom:beatTime
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:range xsd:decimal ;
rdfs:label "beat time" ;
rdfs:comment "A time stamp in beats." .
atom:Event
a rdfs:Class ;
rdfs:label "Event" ;
atom:cType "LV2_Atom_Event" ;
rdfs:comment "An atom with a time stamp prefix in a sequence." .
atom:Sequence
a rdfs:Class ;
rdfs:subClassOf atom:Atom ;
rdfs:label "Sequence" ;
atom:cType "LV2_Atom_Sequence" ;
rdfs:comment "A sequence of events." .
atom:AtomPort
a rdfs:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "Atom Port" ;
rdfs:comment "A port which contains an atom:Atom." .
atom:bufferType
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain atom:AtomPort ;
rdfs:range rdfs:Class ;
rdfs:label "buffer type" ;
rdfs:comment "An atom type that a port may be connected to." .
atom:childType
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "child type" ;
rdfs:comment "The type of children in a container." .
atom:supports
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "supports" ;
rdfs:comment "A supported atom type." ;
rdfs:range rdfs:Class .
atom:eventTransfer
a ui:PortProtocol ;
rdfs:label "event transfer" ;
rdfs:comment "A port protocol for transferring events." .
atom:atomTransfer
a ui:PortProtocol ;
rdfs:label "atom transfer" ;
rdfs:comment "A port protocol for transferring atoms." .

View File

@@ -0,0 +1,235 @@
/*
Copyright 2019 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lv2/atom/atom-test-utils.c"
#include "lv2/atom/atom.h"
#include "lv2/atom/forge.h"
#include "lv2/urid/urid.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
static int
test_string_overflow(void)
{
#define MAX_CHARS 15
static const size_t capacity = sizeof(LV2_Atom_String) + MAX_CHARS + 1;
static const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
uint8_t* buf = (uint8_t*)malloc(capacity);
LV2_URID_Map map = {NULL, urid_map};
LV2_Atom_Forge forge;
lv2_atom_forge_init(&forge, &map);
// Check that writing increasingly long strings fails at the right point
for (size_t count = 0; count < MAX_CHARS; ++count) {
lv2_atom_forge_set_buffer(&forge, buf, capacity);
const LV2_Atom_Forge_Ref ref = lv2_atom_forge_string(&forge, str, count);
if (!ref) {
return test_fail("Failed to write %zu byte string\n", count);
}
}
// Failure writing to an exactly full forge
if (lv2_atom_forge_string(&forge, str, MAX_CHARS + 1)) {
return test_fail("Successfully wrote past end of buffer\n");
}
// Failure writing body after successfully writing header
lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1);
if (lv2_atom_forge_string(&forge, "AB", 2)) {
return test_fail("Successfully wrote atom header past end\n");
}
free(buf);
return 0;
}
static int
test_literal_overflow(void)
{
static const size_t capacity = sizeof(LV2_Atom_Literal) + 2;
uint8_t* buf = (uint8_t*)malloc(capacity);
LV2_URID_Map map = {NULL, urid_map};
LV2_Atom_Forge forge;
lv2_atom_forge_init(&forge, &map);
// Failure in atom header
lv2_atom_forge_set_buffer(&forge, buf, 1);
if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) {
return test_fail("Successfully wrote atom header past end\n");
}
// Failure in literal header
lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1);
if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) {
return test_fail("Successfully wrote literal header past end\n");
}
// Success (only room for one character + null terminator)
lv2_atom_forge_set_buffer(&forge, buf, capacity);
if (!lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) {
return test_fail("Failed to write small enough literal\n");
}
// Failure in body
lv2_atom_forge_set_buffer(&forge, buf, capacity);
if (lv2_atom_forge_literal(&forge, "AB", 2, 0, 0)) {
return test_fail("Successfully wrote literal body past end\n");
}
free(buf);
return 0;
}
static int
test_sequence_overflow(void)
{
static const size_t size = sizeof(LV2_Atom_Sequence) + 6 * sizeof(LV2_Atom);
LV2_URID_Map map = {NULL, urid_map};
// Test over a range that fails in the sequence header and event components
for (size_t capacity = 1; capacity < size; ++capacity) {
uint8_t* buf = (uint8_t*)malloc(capacity);
LV2_Atom_Forge forge;
lv2_atom_forge_init(&forge, &map);
lv2_atom_forge_set_buffer(&forge, buf, capacity);
LV2_Atom_Forge_Frame frame;
LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(&forge, &frame, 0);
assert(capacity >= sizeof(LV2_Atom_Sequence) || !frame.ref);
assert(capacity >= sizeof(LV2_Atom_Sequence) || !ref);
(void)ref;
lv2_atom_forge_frame_time(&forge, 0);
lv2_atom_forge_int(&forge, 42);
lv2_atom_forge_pop(&forge, &frame);
free(buf);
}
return 0;
}
static int
test_vector_head_overflow(void)
{
static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom);
LV2_URID_Map map = {NULL, urid_map};
// Test over a range that fails in the vector header and elements
for (size_t capacity = 1; capacity < size; ++capacity) {
uint8_t* buf = (uint8_t*)malloc(capacity);
LV2_Atom_Forge forge;
lv2_atom_forge_init(&forge, &map);
lv2_atom_forge_set_buffer(&forge, buf, capacity);
LV2_Atom_Forge_Frame frame;
LV2_Atom_Forge_Ref ref =
lv2_atom_forge_vector_head(&forge, &frame, sizeof(int32_t), forge.Int);
assert(capacity >= sizeof(LV2_Atom_Vector) || !frame.ref);
assert(capacity >= sizeof(LV2_Atom_Vector) || !ref);
(void)ref;
lv2_atom_forge_int(&forge, 1);
lv2_atom_forge_int(&forge, 2);
lv2_atom_forge_int(&forge, 3);
lv2_atom_forge_pop(&forge, &frame);
free(buf);
}
return 0;
}
static int
test_vector_overflow(void)
{
static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom);
static const int32_t vec[] = {1, 2, 3};
LV2_URID_Map map = {NULL, urid_map};
// Test over a range that fails in the vector header and elements
for (size_t capacity = 1; capacity < size; ++capacity) {
uint8_t* buf = (uint8_t*)malloc(capacity);
LV2_Atom_Forge forge;
lv2_atom_forge_init(&forge, &map);
lv2_atom_forge_set_buffer(&forge, buf, capacity);
LV2_Atom_Forge_Ref ref =
lv2_atom_forge_vector(&forge, sizeof(int32_t), forge.Int, 3, vec);
assert(capacity >= sizeof(LV2_Atom_Vector) || !ref);
(void)ref;
free(buf);
}
return 0;
}
static int
test_tuple_overflow(void)
{
static const size_t size = sizeof(LV2_Atom_Tuple) + 3 * sizeof(LV2_Atom);
LV2_URID_Map map = {NULL, urid_map};
// Test over a range that fails in the tuple header and elements
for (size_t capacity = 1; capacity < size; ++capacity) {
uint8_t* buf = (uint8_t*)malloc(capacity);
LV2_Atom_Forge forge;
lv2_atom_forge_init(&forge, &map);
lv2_atom_forge_set_buffer(&forge, buf, capacity);
LV2_Atom_Forge_Frame frame;
LV2_Atom_Forge_Ref ref = lv2_atom_forge_tuple(&forge, &frame);
assert(capacity >= sizeof(LV2_Atom_Tuple) || !frame.ref);
assert(capacity >= sizeof(LV2_Atom_Tuple) || !ref);
(void)ref;
lv2_atom_forge_int(&forge, 1);
lv2_atom_forge_float(&forge, 2.0f);
lv2_atom_forge_string(&forge, "three", 5);
lv2_atom_forge_pop(&forge, &frame);
free(buf);
}
return 0;
}
int
main(void)
{
const int ret = test_string_overflow() || test_literal_overflow() ||
test_sequence_overflow() || test_vector_head_overflow() ||
test_vector_overflow() || test_tuple_overflow();
free_urid_map();
return ret;
}

View File

@@ -0,0 +1,683 @@
/*
Copyright 2008-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
@file forge.h An API for constructing LV2 atoms.
This file provides an API for constructing Atoms which makes it relatively
simple to build nested atoms of arbitrary complexity without requiring
dynamic memory allocation.
The API is based on successively appending the appropriate pieces to build a
complete Atom. The size of containers is automatically updated. Functions
that begin a container return (via their frame argument) a stack frame which
must be popped when the container is finished.
All output is written to a user-provided buffer or sink function. This
makes it popssible to create create atoms on the stack, on the heap, in LV2
port buffers, in a ringbuffer, or elsewhere, all using the same API.
This entire API is realtime safe if used with a buffer or a realtime safe
sink, except lv2_atom_forge_init() which is only realtime safe if the URI
map function is.
Note these functions are all static inline, do not take their address.
This header is non-normative, it is provided for convenience.
*/
#ifndef LV2_ATOM_FORGE_H
#define LV2_ATOM_FORGE_H
/**
@defgroup forge Forge
@ingroup atom
An API for constructing LV2 atoms.
@{
*/
#include "lv2/atom/atom.h"
#include "lv2/atom/util.h"
#include "lv2/core/attributes.h"
#include "lv2/urid/urid.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
// Disable deprecation warnings for Blank and Resource
LV2_DISABLE_DEPRECATION_WARNINGS
/** Handle for LV2_Atom_Forge_Sink. */
typedef void* LV2_Atom_Forge_Sink_Handle;
/** A reference to a chunk of written output. */
typedef intptr_t LV2_Atom_Forge_Ref;
/** Sink function for writing output. See lv2_atom_forge_set_sink(). */
typedef LV2_Atom_Forge_Ref (*LV2_Atom_Forge_Sink)(
LV2_Atom_Forge_Sink_Handle handle,
const void* buf,
uint32_t size);
/** Function for resolving a reference. See lv2_atom_forge_set_sink(). */
typedef LV2_Atom* (*LV2_Atom_Forge_Deref_Func)(
LV2_Atom_Forge_Sink_Handle handle,
LV2_Atom_Forge_Ref ref);
/** A stack frame used for keeping track of nested Atom containers. */
typedef struct LV2_Atom_Forge_Frame {
struct LV2_Atom_Forge_Frame* parent;
LV2_Atom_Forge_Ref ref;
} LV2_Atom_Forge_Frame;
/** A "forge" for creating atoms by appending to a buffer. */
typedef struct {
uint8_t* buf;
uint32_t offset;
uint32_t size;
LV2_Atom_Forge_Sink sink;
LV2_Atom_Forge_Deref_Func deref;
LV2_Atom_Forge_Sink_Handle handle;
LV2_Atom_Forge_Frame* stack;
LV2_URID Blank LV2_DEPRECATED;
LV2_URID Bool;
LV2_URID Chunk;
LV2_URID Double;
LV2_URID Float;
LV2_URID Int;
LV2_URID Long;
LV2_URID Literal;
LV2_URID Object;
LV2_URID Path;
LV2_URID Property;
LV2_URID Resource LV2_DEPRECATED;
LV2_URID Sequence;
LV2_URID String;
LV2_URID Tuple;
LV2_URID URI;
LV2_URID URID;
LV2_URID Vector;
} LV2_Atom_Forge;
static inline void
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size);
/**
Initialise `forge`.
URIs will be mapped using `map` and stored, a reference to `map` itself is
not held.
*/
static inline void
lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
{
lv2_atom_forge_set_buffer(forge, NULL, 0);
forge->Blank = map->map(map->handle, LV2_ATOM__Blank);
forge->Bool = map->map(map->handle, LV2_ATOM__Bool);
forge->Chunk = map->map(map->handle, LV2_ATOM__Chunk);
forge->Double = map->map(map->handle, LV2_ATOM__Double);
forge->Float = map->map(map->handle, LV2_ATOM__Float);
forge->Int = map->map(map->handle, LV2_ATOM__Int);
forge->Long = map->map(map->handle, LV2_ATOM__Long);
forge->Literal = map->map(map->handle, LV2_ATOM__Literal);
forge->Object = map->map(map->handle, LV2_ATOM__Object);
forge->Path = map->map(map->handle, LV2_ATOM__Path);
forge->Property = map->map(map->handle, LV2_ATOM__Property);
forge->Resource = map->map(map->handle, LV2_ATOM__Resource);
forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence);
forge->String = map->map(map->handle, LV2_ATOM__String);
forge->Tuple = map->map(map->handle, LV2_ATOM__Tuple);
forge->URI = map->map(map->handle, LV2_ATOM__URI);
forge->URID = map->map(map->handle, LV2_ATOM__URID);
forge->Vector = map->map(map->handle, LV2_ATOM__Vector);
}
/** Access the Atom pointed to by a reference. */
static inline LV2_Atom*
lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref)
{
return forge->buf ? (LV2_Atom*)ref : forge->deref(forge->handle, ref);
}
/**
@name Object Stack
@{
*/
/**
Push a stack frame.
This is done automatically by container functions (which take a stack frame
pointer), but may be called by the user to push the top level container when
writing to an existing Atom.
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_push(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Frame* frame,
LV2_Atom_Forge_Ref ref)
{
frame->parent = forge->stack;
frame->ref = ref;
if (ref) {
forge->stack = frame; // Don't push, so walking the stack is always safe
}
return ref;
}
/** Pop a stack frame. This must be called when a container is finished. */
static inline void
lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
{
if (frame->ref) {
// If frame has a valid ref, it must be the top of the stack
assert(frame == forge->stack);
forge->stack = frame->parent;
}
// Otherwise, frame was not pushed because of overflow, do nothing
}
/** Return true iff the top of the stack has the given type. */
static inline bool
lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type)
{
return forge->stack && forge->stack->ref &&
(lv2_atom_forge_deref(forge, forge->stack->ref)->type == type);
}
/** Return true iff `type` is an atom:Object. */
static inline bool
lv2_atom_forge_is_object_type(const LV2_Atom_Forge* forge, uint32_t type)
{
return (type == forge->Object || type == forge->Blank ||
type == forge->Resource);
}
/** Return true iff `type` is an atom:Object with a blank ID. */
static inline bool
lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge,
uint32_t type,
const LV2_Atom_Object_Body* body)
{
return (type == forge->Blank || (type == forge->Object && body->id == 0));
}
/**
@}
@name Output Configuration
@{
*/
/** Set the output buffer where `forge` will write atoms. */
static inline void
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
{
forge->buf = buf;
forge->size = (uint32_t)size;
forge->offset = 0;
forge->deref = NULL;
forge->sink = NULL;
forge->handle = NULL;
forge->stack = NULL;
}
/**
Set the sink function where `forge` will write output.
The return value of forge functions is an LV2_Atom_Forge_Ref which is an
integer type safe to use as a pointer but is otherwise opaque. The sink
function must return a ref that can be dereferenced to access as least
sizeof(LV2_Atom) bytes of the written data, so sizes can be updated. For
ringbuffers, this should be possible as long as the size of the buffer is a
multiple of sizeof(LV2_Atom), since atoms are always aligned.
Note that 0 is an invalid reference, so if you are using a buffer offset be
sure to offset it such that 0 is never a valid reference. You will get
confusing errors otherwise.
*/
static inline void
lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Sink sink,
LV2_Atom_Forge_Deref_Func deref,
LV2_Atom_Forge_Sink_Handle handle)
{
forge->buf = NULL;
forge->size = forge->offset = 0;
forge->deref = deref;
forge->sink = sink;
forge->handle = handle;
forge->stack = NULL;
}
/**
@}
@name Low Level Output
@{
*/
/**
Write raw output. This is used internally, but is also useful for writing
atom types not explicitly supported by the forge API. Note the caller is
responsible for ensuring the output is approriately padded.
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size)
{
LV2_Atom_Forge_Ref out = 0;
if (forge->sink) {
out = forge->sink(forge->handle, data, size);
} else {
out = (LV2_Atom_Forge_Ref)forge->buf + forge->offset;
uint8_t* mem = forge->buf + forge->offset;
if (forge->offset + size > forge->size) {
return 0;
}
forge->offset += size;
memcpy(mem, data, size);
}
for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) {
lv2_atom_forge_deref(forge, f->ref)->size += size;
}
return out;
}
/** Pad output accordingly so next write is 64-bit aligned. */
static inline void
lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written)
{
const uint64_t pad = 0;
const uint32_t pad_size = lv2_atom_pad_size(written) - written;
lv2_atom_forge_raw(forge, &pad, pad_size);
}
/** Write raw output, padding to 64-bits as necessary. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size)
{
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size);
if (out) {
lv2_atom_forge_pad(forge, size);
}
return out;
}
/** Write a null-terminated string body. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_string_body(LV2_Atom_Forge* forge, const char* str, uint32_t len)
{
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len);
if (out && (out = lv2_atom_forge_raw(forge, "", 1))) {
lv2_atom_forge_pad(forge, len + 1);
}
return out;
}
/**
@}
@name Atom Output
@{
*/
/** Write an atom:Atom header. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type)
{
const LV2_Atom a = {size, type};
return lv2_atom_forge_raw(forge, &a, sizeof(a));
}
/** Write a primitive (fixed-size) atom. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a)
{
return (
lv2_atom_forge_top_is(forge, forge->Vector)
? lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size)
: lv2_atom_forge_write(forge, a, (uint32_t)sizeof(LV2_Atom) + a->size));
}
/** Write an atom:Int. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val)
{
const LV2_Atom_Int a = {{sizeof(val), forge->Int}, val};
return lv2_atom_forge_primitive(forge, &a.atom);
}
/** Write an atom:Long. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val)
{
const LV2_Atom_Long a = {{sizeof(val), forge->Long}, val};
return lv2_atom_forge_primitive(forge, &a.atom);
}
/** Write an atom:Float. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_float(LV2_Atom_Forge* forge, float val)
{
const LV2_Atom_Float a = {{sizeof(val), forge->Float}, val};
return lv2_atom_forge_primitive(forge, &a.atom);
}
/** Write an atom:Double. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_double(LV2_Atom_Forge* forge, double val)
{
const LV2_Atom_Double a = {{sizeof(val), forge->Double}, val};
return lv2_atom_forge_primitive(forge, &a.atom);
}
/** Write an atom:Bool. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val)
{
const LV2_Atom_Bool a = {{sizeof(int32_t), forge->Bool}, val ? 1 : 0};
return lv2_atom_forge_primitive(forge, &a.atom);
}
/** Write an atom:URID. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id)
{
const LV2_Atom_URID a = {{sizeof(id), forge->URID}, id};
return lv2_atom_forge_primitive(forge, &a.atom);
}
/** Write an atom compatible with atom:String. Used internally. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_typed_string(LV2_Atom_Forge* forge,
uint32_t type,
const char* str,
uint32_t len)
{
const LV2_Atom_String a = {{len + 1, type}};
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
if (out) {
if (!lv2_atom_forge_string_body(forge, str, len)) {
LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
atom->size = atom->type = 0;
out = 0;
}
}
return out;
}
/** Write an atom:String. Note that `str` need not be NULL terminated. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len)
{
return lv2_atom_forge_typed_string(forge, forge->String, str, len);
}
/**
Write an atom:URI. Note that `uri` need not be NULL terminated.
This does not map the URI, but writes the complete URI string. To write
a mapped URI, use lv2_atom_forge_urid().
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len)
{
return lv2_atom_forge_typed_string(forge, forge->URI, uri, len);
}
/** Write an atom:Path. Note that `path` need not be NULL terminated. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len)
{
return lv2_atom_forge_typed_string(forge, forge->Path, path, len);
}
/** Write an atom:Literal. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_literal(LV2_Atom_Forge* forge,
const char* str,
uint32_t len,
uint32_t datatype,
uint32_t lang)
{
const LV2_Atom_Literal a = {
{(uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1),
forge->Literal},
{datatype, lang}};
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
if (out) {
if (!lv2_atom_forge_string_body(forge, str, len)) {
LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
atom->size = atom->type = 0;
out = 0;
}
}
return out;
}
/** Start an atom:Vector. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_vector_head(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Frame* frame,
uint32_t child_size,
uint32_t child_type)
{
const LV2_Atom_Vector a = {{sizeof(LV2_Atom_Vector_Body), forge->Vector},
{child_size, child_type}};
return lv2_atom_forge_push(
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
}
/** Write a complete atom:Vector. */
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_vector(LV2_Atom_Forge* forge,
uint32_t child_size,
uint32_t child_type,
uint32_t n_elems,
const void* elems)
{
const LV2_Atom_Vector a = {
{(uint32_t)(sizeof(LV2_Atom_Vector_Body) + n_elems * child_size),
forge->Vector},
{child_size, child_type}};
LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
if (out) {
lv2_atom_forge_write(forge, elems, child_size * n_elems);
}
return out;
}
/**
Write the header of an atom:Tuple.
The passed frame will be initialised to represent this tuple. To complete
the tuple, write a sequence of atoms, then pop the frame with
lv2_atom_forge_pop().
For example:
@code
// Write tuple (1, 2.0)
LV2_Atom_Forge_Frame frame;
LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame);
lv2_atom_forge_int(forge, 1);
lv2_atom_forge_float(forge, 2.0);
lv2_atom_forge_pop(forge, &frame);
@endcode
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
{
const LV2_Atom_Tuple a = {{0, forge->Tuple}};
return lv2_atom_forge_push(
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
}
/**
Write the header of an atom:Object.
The passed frame will be initialised to represent this object. To complete
the object, write a sequence of properties, then pop the frame with
lv2_atom_forge_pop().
For example:
@code
LV2_URID eg_Cat = map("http://example.org/Cat");
LV2_URID eg_name = map("http://example.org/name");
// Start object with type eg_Cat and blank ID
LV2_Atom_Forge_Frame frame;
lv2_atom_forge_object(forge, &frame, 0, eg_Cat);
// Append property eg:name = "Hobbes"
lv2_atom_forge_key(forge, eg_name);
lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes"));
// Finish object
lv2_atom_forge_pop(forge, &frame);
@endcode
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_object(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Frame* frame,
LV2_URID id,
LV2_URID otype)
{
const LV2_Atom_Object a = {
{(uint32_t)sizeof(LV2_Atom_Object_Body), forge->Object}, {id, otype}};
return lv2_atom_forge_push(
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
}
/**
The same as lv2_atom_forge_object(), but for object:Resource.
This function is deprecated and should not be used in new code.
Use lv2_atom_forge_object() directly instead.
*/
LV2_DEPRECATED
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_resource(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Frame* frame,
LV2_URID id,
LV2_URID otype)
{
const LV2_Atom_Object a = {
{(uint32_t)sizeof(LV2_Atom_Object_Body), forge->Resource}, {id, otype}};
return lv2_atom_forge_push(
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
}
/**
The same as lv2_atom_forge_object(), but for object:Blank.
This function is deprecated and should not be used in new code.
Use lv2_atom_forge_object() directly instead.
*/
LV2_DEPRECATED
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_blank(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Frame* frame,
uint32_t id,
LV2_URID otype)
{
const LV2_Atom_Object a = {
{(uint32_t)sizeof(LV2_Atom_Object_Body), forge->Blank}, {id, otype}};
return lv2_atom_forge_push(
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
}
/**
Write a property key in an Object, to be followed by the value.
See lv2_atom_forge_object() documentation for an example.
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_key(LV2_Atom_Forge* forge, LV2_URID key)
{
const LV2_Atom_Property_Body a = {key, 0, {0, 0}};
return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
}
/**
Write the header for a property body in an object, with context.
If you do not need the context, which is almost certainly the case,
use the simpler lv2_atom_forge_key() instead.
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
LV2_URID key,
LV2_URID context)
{
const LV2_Atom_Property_Body a = {key, context, {0, 0}};
return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
}
/**
Write the header for a Sequence.
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Frame* frame,
uint32_t unit)
{
const LV2_Atom_Sequence a = {
{(uint32_t)sizeof(LV2_Atom_Sequence_Body), forge->Sequence}, {unit, 0}};
return lv2_atom_forge_push(
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
}
/**
Write the time stamp header of an Event (in a Sequence) in audio frames.
After this, call the appropriate forge method(s) to write the body. Note
the returned reference is to an LV2_Event which is NOT an Atom.
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames)
{
return lv2_atom_forge_write(forge, &frames, sizeof(frames));
}
/**
Write the time stamp header of an Event (in a Sequence) in beats. After
this, call the appropriate forge method(s) to write the body. Note the
returned reference is to an LV2_Event which is NOT an Atom.
*/
static inline LV2_Atom_Forge_Ref
lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats)
{
return lv2_atom_forge_write(forge, &beats, sizeof(beats));
}
LV2_RESTORE_WARNINGS
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
@}
*/
#endif /* LV2_ATOM_FORGE_H */

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/atom>
a lv2:Specification ;
lv2:minorVersion 2 ;
lv2:microVersion 2 ;
rdfs:seeAlso <atom.ttl> .

View File

@@ -0,0 +1,523 @@
/*
Copyright 2008-2015 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_ATOM_UTIL_H
#define LV2_ATOM_UTIL_H
/**
@file util.h Helper functions for the LV2 Atom extension.
Note these functions are all static inline, do not take their address.
This header is non-normative, it is provided for convenience.
*/
/**
@defgroup util Utilities
@ingroup atom
Utilities for working with atoms.
@{
*/
#include "lv2/atom/atom.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Pad a size to 64 bits. */
static inline uint32_t
lv2_atom_pad_size(uint32_t size)
{
return (size + 7U) & (~7U);
}
/** Return the total size of `atom`, including the header. */
static inline uint32_t
lv2_atom_total_size(const LV2_Atom* atom)
{
return (uint32_t)sizeof(LV2_Atom) + atom->size;
}
/** Return true iff `atom` is null. */
static inline bool
lv2_atom_is_null(const LV2_Atom* atom)
{
return !atom || (atom->type == 0 && atom->size == 0);
}
/** Return true iff `a` is equal to `b`. */
static inline bool
lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b)
{
return (a == b) || ((a->type == b->type) && (a->size == b->size) &&
!memcmp(a + 1, b + 1, a->size));
}
/**
@name Sequence Iterator
@{
*/
/** Get an iterator pointing to the first event in a Sequence body. */
static inline LV2_Atom_Event*
lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body)
{
return (LV2_Atom_Event*)(body + 1);
}
/** Get an iterator pointing to the end of a Sequence body. */
static inline LV2_Atom_Event*
lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body, uint32_t size)
{
return (LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size));
}
/** Return true iff `i` has reached the end of `body`. */
static inline bool
lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body,
uint32_t size,
const LV2_Atom_Event* i)
{
return (const uint8_t*)i >= ((const uint8_t*)body + size);
}
/** Return an iterator to the element following `i`. */
static inline LV2_Atom_Event*
lv2_atom_sequence_next(const LV2_Atom_Event* i)
{
return (LV2_Atom_Event*)((const uint8_t*)i + sizeof(LV2_Atom_Event) +
lv2_atom_pad_size(i->body.size));
}
/**
A macro for iterating over all events in a Sequence.
@param seq The sequence to iterate over
@param iter The name of the iterator
This macro is used similarly to a for loop (which it expands to), for
example:
@code
LV2_ATOM_SEQUENCE_FOREACH(sequence, ev) {
// Do something with ev (an LV2_Atom_Event*) here...
}
@endcode
*/
#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \
for (LV2_Atom_Event * (iter) = lv2_atom_sequence_begin(&(seq)->body); \
!lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \
(iter) = lv2_atom_sequence_next(iter))
/** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */
#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \
for (LV2_Atom_Event * (iter) = lv2_atom_sequence_begin(body); \
!lv2_atom_sequence_is_end(body, size, (iter)); \
(iter) = lv2_atom_sequence_next(iter))
/**
@}
@name Sequence Utilities
@{
*/
/**
Clear all events from `sequence`.
This simply resets the size field, the other fields are left untouched.
*/
static inline void
lv2_atom_sequence_clear(LV2_Atom_Sequence* seq)
{
seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
}
/**
Append an event at the end of `sequence`.
@param seq Sequence to append to.
@param capacity Total capacity of the sequence atom
(as set by the host for sequence output ports).
@param event Event to write.
@return A pointer to the newly written event in `seq`,
or NULL on failure (insufficient space).
*/
static inline LV2_Atom_Event*
lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq,
uint32_t capacity,
const LV2_Atom_Event* event)
{
const uint32_t total_size = (uint32_t)sizeof(*event) + event->body.size;
if (capacity - seq->atom.size < total_size) {
return NULL;
}
LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size);
memcpy(e, event, total_size);
seq->atom.size += lv2_atom_pad_size(total_size);
return e;
}
/**
@}
@name Tuple Iterator
@{
*/
/** Get an iterator pointing to the first element in `tup`. */
static inline LV2_Atom*
lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup)
{
return (LV2_Atom*)(LV2_ATOM_BODY(tup));
}
/** Return true iff `i` has reached the end of `body`. */
static inline bool
lv2_atom_tuple_is_end(const void* body, uint32_t size, const LV2_Atom* i)
{
return (const uint8_t*)i >= ((const uint8_t*)body + size);
}
/** Return an iterator to the element following `i`. */
static inline LV2_Atom*
lv2_atom_tuple_next(const LV2_Atom* i)
{
return (LV2_Atom*)((const uint8_t*)i + sizeof(LV2_Atom) +
lv2_atom_pad_size(i->size));
}
/**
A macro for iterating over all properties of a Tuple.
@param tuple The tuple to iterate over
@param iter The name of the iterator
This macro is used similarly to a for loop (which it expands to), for
example:
@code
LV2_ATOM_TUPLE_FOREACH(tuple, elem) {
// Do something with elem (an LV2_Atom*) here...
}
@endcode
*/
#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \
for (LV2_Atom * (iter) = lv2_atom_tuple_begin(tuple); \
!lv2_atom_tuple_is_end( \
LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \
(iter) = lv2_atom_tuple_next(iter))
/** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */
#define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \
for (LV2_Atom * (iter) = (LV2_Atom*)(body); \
!lv2_atom_tuple_is_end(body, size, (iter)); \
(iter) = lv2_atom_tuple_next(iter))
/**
@}
@name Object Iterator
@{
*/
/** Return a pointer to the first property in `body`. */
static inline LV2_Atom_Property_Body*
lv2_atom_object_begin(const LV2_Atom_Object_Body* body)
{
return (LV2_Atom_Property_Body*)(body + 1);
}
/** Return true iff `i` has reached the end of `obj`. */
static inline bool
lv2_atom_object_is_end(const LV2_Atom_Object_Body* body,
uint32_t size,
const LV2_Atom_Property_Body* i)
{
return (const uint8_t*)i >= ((const uint8_t*)body + size);
}
/** Return an iterator to the property following `i`. */
static inline LV2_Atom_Property_Body*
lv2_atom_object_next(const LV2_Atom_Property_Body* i)
{
const LV2_Atom* const value =
(const LV2_Atom*)((const uint8_t*)i + 2 * sizeof(uint32_t));
return (LV2_Atom_Property_Body*)((const uint8_t*)i +
lv2_atom_pad_size(
(uint32_t)sizeof(LV2_Atom_Property_Body) +
value->size));
}
/**
A macro for iterating over all properties of an Object.
@param obj The object to iterate over
@param iter The name of the iterator
This macro is used similarly to a for loop (which it expands to), for
example:
@code
LV2_ATOM_OBJECT_FOREACH(object, i) {
// Do something with i (an LV2_Atom_Property_Body*) here...
}
@endcode
*/
#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \
for (LV2_Atom_Property_Body * (iter) = lv2_atom_object_begin(&(obj)->body); \
!lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \
(iter) = lv2_atom_object_next(iter))
/** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */
#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \
for (LV2_Atom_Property_Body * (iter) = lv2_atom_object_begin(body); \
!lv2_atom_object_is_end(body, size, (iter)); \
(iter) = lv2_atom_object_next(iter))
/**
@}
@name Object Query
@{
*/
/** A single entry in an Object query. */
typedef struct {
uint32_t key; /**< Key to query (input set by user) */
const LV2_Atom** value; /**< Found value (output set by query function) */
} LV2_Atom_Object_Query;
/** Sentinel for lv2_atom_object_query(). */
static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = {0, NULL};
/**
Get an object's values for various keys.
The value pointer of each item in `query` will be set to the location of
the corresponding value in `object`. Every value pointer in `query` MUST
be initialised to NULL. This function reads `object` in a single linear
sweep. By allocating `query` on the stack, objects can be "queried"
quickly without allocating any memory. This function is realtime safe.
This function can only do "flat" queries, it is not smart enough to match
variables in nested objects.
For example:
@code
const LV2_Atom* name = NULL;
const LV2_Atom* age = NULL;
LV2_Atom_Object_Query q[] = {
{ urids.eg_name, &name },
{ urids.eg_age, &age },
LV2_ATOM_OBJECT_QUERY_END
};
lv2_atom_object_query(obj, q);
// name and age are now set to the appropriate values in obj, or NULL.
@endcode
*/
static inline int
lv2_atom_object_query(const LV2_Atom_Object* object,
LV2_Atom_Object_Query* query)
{
int matches = 0;
int n_queries = 0;
/* Count number of query keys so we can short-circuit when done */
for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
++n_queries;
}
LV2_ATOM_OBJECT_FOREACH (object, prop) {
for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
if (q->key == prop->key && !*q->value) {
*q->value = &prop->value;
if (++matches == n_queries) {
return matches;
}
break;
}
}
}
return matches;
}
/**
Body only version of lv2_atom_object_get().
*/
static inline int
lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...)
{
int matches = 0;
int n_queries = 0;
/* Count number of keys so we can short-circuit when done */
va_list args;
va_start(args, body);
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
if (!va_arg(args, const LV2_Atom**)) {
va_end(args);
return -1;
}
}
va_end(args);
LV2_ATOM_OBJECT_BODY_FOREACH (body, size, prop) {
va_start(args, body);
for (int i = 0; i < n_queries; ++i) {
uint32_t qkey = va_arg(args, uint32_t);
const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
if (qkey == prop->key && !*qval) {
*qval = &prop->value;
if (++matches == n_queries) {
va_end(args);
return matches;
}
break;
}
}
va_end(args);
}
return matches;
}
/**
Variable argument version of lv2_atom_object_query().
This is nicer-looking in code, but a bit more error-prone since it is not
type safe and the argument list must be terminated.
The arguments should be a series of uint32_t key and const LV2_Atom** value
pairs, terminated by a zero key. The value pointers MUST be initialized to
NULL. For example:
@code
const LV2_Atom* name = NULL;
const LV2_Atom* age = NULL;
lv2_atom_object_get(obj,
uris.name_key, &name,
uris.age_key, &age,
0);
@endcode
*/
static inline int
lv2_atom_object_get(const LV2_Atom_Object* object, ...)
{
int matches = 0;
int n_queries = 0;
/* Count number of keys so we can short-circuit when done */
va_list args;
va_start(args, object);
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
if (!va_arg(args, const LV2_Atom**)) {
va_end(args);
return -1;
}
}
va_end(args);
LV2_ATOM_OBJECT_FOREACH (object, prop) {
va_start(args, object);
for (int i = 0; i < n_queries; ++i) {
uint32_t qkey = va_arg(args, uint32_t);
const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
if (qkey == prop->key && !*qval) {
*qval = &prop->value;
if (++matches == n_queries) {
va_end(args);
return matches;
}
break;
}
}
va_end(args);
}
return matches;
}
/**
Variable argument version of lv2_atom_object_query() with types.
This is like lv2_atom_object_get(), but each entry has an additional
parameter to specify the required type. Only atoms with a matching type
will be selected.
The arguments should be a series of uint32_t key, const LV2_Atom**, uint32_t
type triples, terminated by a zero key. The value pointers MUST be
initialized to NULL. For example:
@code
const LV2_Atom_String* name = NULL;
const LV2_Atom_Int* age = NULL;
lv2_atom_object_get(obj,
uris.name_key, &name, uris.atom_String,
uris.age_key, &age, uris.atom_Int
0);
@endcode
*/
static inline int
lv2_atom_object_get_typed(const LV2_Atom_Object* object, ...)
{
int matches = 0;
int n_queries = 0;
/* Count number of keys so we can short-circuit when done */
va_list args;
va_start(args, object);
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
if (!va_arg(args, const LV2_Atom**) || !va_arg(args, uint32_t)) {
va_end(args);
return -1;
}
}
va_end(args);
LV2_ATOM_OBJECT_FOREACH (object, prop) {
va_start(args, object);
for (int i = 0; i < n_queries; ++i) {
const uint32_t qkey = va_arg(args, uint32_t);
const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
const uint32_t qtype = va_arg(args, uint32_t);
if (!*qval && qkey == prop->key && qtype == prop->value.type) {
*qval = &prop->value;
if (++matches == n_queries) {
va_end(args);
return matches;
}
break;
}
}
va_end(args);
}
return matches;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
@}
*/
#endif /* LV2_ATOM_UTIL_H */

View File

@@ -0,0 +1,51 @@
/*
Copyright 2007-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_BUF_SIZE_H
#define LV2_BUF_SIZE_H
/**
@defgroup buf-size Buffer Size
@ingroup lv2
Access to, and restrictions on, buffer sizes.
See <http://lv2plug.in/ns/ext/buf-size> for details.
@{
*/
// clang-format off
#define LV2_BUF_SIZE_URI "http://lv2plug.in/ns/ext/buf-size" ///< http://lv2plug.in/ns/ext/buf-size
#define LV2_BUF_SIZE_PREFIX LV2_BUF_SIZE_URI "#" ///< http://lv2plug.in/ns/ext/buf-size#
#define LV2_BUF_SIZE__boundedBlockLength LV2_BUF_SIZE_PREFIX "boundedBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#boundedBlockLength
#define LV2_BUF_SIZE__coarseBlockLength LV2_BUF_SIZE_PREFIX "coarseBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#coarseBlockLength
#define LV2_BUF_SIZE__fixedBlockLength LV2_BUF_SIZE_PREFIX "fixedBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#fixedBlockLength
#define LV2_BUF_SIZE__maxBlockLength LV2_BUF_SIZE_PREFIX "maxBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#maxBlockLength
#define LV2_BUF_SIZE__minBlockLength LV2_BUF_SIZE_PREFIX "minBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#minBlockLength
#define LV2_BUF_SIZE__nominalBlockLength LV2_BUF_SIZE_PREFIX "nominalBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#nominalBlockLength
#define LV2_BUF_SIZE__powerOf2BlockLength LV2_BUF_SIZE_PREFIX "powerOf2BlockLength" ///< http://lv2plug.in/ns/ext/buf-size#powerOf2BlockLength
#define LV2_BUF_SIZE__sequenceSize LV2_BUF_SIZE_PREFIX "sequenceSize" ///< http://lv2plug.in/ns/ext/buf-size#sequenceSize
// clang-format on
/**
@}
*/
#endif /* LV2_BUF_SIZE_H */

View File

@@ -0,0 +1,157 @@
@prefix bufsz: <http://lv2plug.in/ns/ext/buf-size#> .
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/buf-size>
a doap:Project ;
doap:name "LV2 Buf Size" ;
doap:shortdesc "Access to, and restrictions on, buffer sizes." ;
doap:created "2012-08-07" ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "1.4" ;
doap:created "2015-09-18" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.14.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add bufsz:nominalBlockLength option."
] , [
rdfs:label "Add bufsz:coarseBlockLength feature."
]
]
] , [
doap:revision "1.2" ;
doap:created "2012-12-21" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix typo in bufsz:sequenceSize label."
]
]
] , [
doap:revision "1.0" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This extension defines a facility for plugins to get information about the
block length (the sample_count parameter of LV2_Descriptor::run) and port
buffer sizes, as well as several features which can be used to restrict the
block length.
This extension defines features and properties but has no special purpose
API of its own. The host provides all the relevant information to the plugin
as [options](options.html).
To require restrictions on the block length, plugins can require additional
features: bufsz:boundedBlockLength, bufsz:powerOf2BlockLength, and
bufsz:fixedBlockLength. These features are data-only, that is they merely
indicate a restriction and do not carry any data or API.
"""^^lv2:Markdown .
bufsz:boundedBlockLength
lv2:documentation """
A feature that indicates the host will provide both the bufsz:minBlockLength
and bufsz:maxBlockLength options to the plugin. Plugins that copy data from
audio inputs can require this feature to ensure they know how much space is
required for auxiliary buffers. Note the minimum may be zero, this feature is
mainly useful to ensure a maximum is available.
All hosts SHOULD support this feature, since it is simple to support and
necessary for any plugins that may need to copy the input.
"""^^lv2:Markdown .
bufsz:fixedBlockLength
lv2:documentation """
A feature that indicates the host will always call LV2_Descriptor::run() with
the same value for sample_count. This length MUST be provided as the value of
both the bufsz:minBlockLength and bufsz:maxBlockLength options.
Note that requiring this feature may severely limit the number of hosts capable
of running the plugin.
"""^^lv2:Markdown .
bufsz:powerOf2BlockLength
lv2:documentation """
A feature that indicates the host will always call LV2_Descriptor::run() with a
power of two sample_count. Note that this feature does not guarantee the value
is the same each call, to guarantee a fixed power of two block length plugins
must require both this feature and bufsz:fixedBlockLength.
Note that requiring this feature may severely limit the number of hosts capable
of running the plugin.
"""^^lv2:Markdown .
bufsz:coarseBlockLength
lv2:documentation """
A feature that indicates the plugin prefers coarse, regular block lengths. For
example, plugins that do not implement sample-accurate control use this feature
to indicate that the host should not split the run cycle because controls have
changed.
Note that this feature is merely a hint, and does not guarantee a fixed block
length. The run cycle may be split for other reasons, and the blocksize itself
may change anytime.
"""^^lv2:Markdown .
bufsz:maxBlockLength
lv2:documentation """
The maximum block length the host will ever request the plugin to process at
once, that is, the maximum `sample_count` parameter that will ever be passed to
LV2_Descriptor::run().
"""^^lv2:Markdown .
bufsz:minBlockLength
lv2:documentation """
The minimum block length the host will ever request the plugin to process at
once, that is, the minimum `sample_count` parameter that will ever be passed to
LV2_Descriptor::run().
"""^^lv2:Markdown .
bufsz:nominalBlockLength
lv2:documentation """
The typical block length the host will request the plugin to process at once,
that is, the typical `sample_count` parameter that will be passed to
LV2_Descriptor::run(). This will usually be equivalent, or close to, the
maximum block length, but there are no strong guarantees about this value
whatsoever. Plugins may use this length for optimization purposes, but MUST
NOT assume the host will always process blocks of this length. In particular,
the host MAY process longer blocks.
"""^^lv2:Markdown .
bufsz:sequenceSize
lv2:documentation """
This should be provided as an option by hosts that support event ports
(including but not limited to MIDI), so plugins have the ability to allocate
auxiliary buffers large enough to copy the input.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,67 @@
@prefix bufsz: <http://lv2plug.in/ns/ext/buf-size#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/buf-size>
a owl:Ontology ;
rdfs:label "LV2 Buf Size" ;
rdfs:comment "Access to, and restrictions on, buffer sizes." ;
rdfs:seeAlso <buf-size.h> ,
<buf-size.meta.ttl> .
bufsz:boundedBlockLength
a lv2:Feature ;
rdfs:label "bounded block length" ;
rdfs:comment "Block length has lower and upper bounds." .
bufsz:fixedBlockLength
a lv2:Feature ;
rdfs:label "fixed block length" ;
rdfs:comment "Block length never changes." .
bufsz:powerOf2BlockLength
a lv2:Feature ;
rdfs:label "power of 2 block length" ;
rdfs:comment "Block length is a power of 2." .
bufsz:coarseBlockLength
a lv2:Feature ;
rdfs:label "coarse block length" ;
rdfs:comment "Plugin prefers coarse block length without buffer splitting." .
bufsz:maxBlockLength
a rdf:Property ,
owl:DatatypeProperty ,
opts:Option ;
rdfs:label "maximum block length" ;
rdfs:comment "Block length has an upper bound." ;
rdfs:range xsd:nonNegativeInteger .
bufsz:minBlockLength
a rdf:Property ,
owl:DatatypeProperty ,
opts:Option ;
rdfs:label "minimum block length" ;
rdfs:comment "Block length has a lower bound." ;
rdfs:range xsd:nonNegativeInteger .
bufsz:nominalBlockLength
a rdf:Property ,
owl:DatatypeProperty ,
opts:Option ;
rdfs:label "nominal block length" ;
rdfs:comment "Typical block length that will most often be processed." ;
rdfs:range xsd:nonNegativeInteger .
bufsz:sequenceSize
a rdf:Property ,
owl:DatatypeProperty ,
opts:Option ;
rdfs:label "sequence size" ;
rdfs:comment "The maximum size of a sequence, in bytes." ;
rdfs:range xsd:nonNegativeInteger .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/buf-size>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 4 ;
rdfs:seeAlso <buf-size.ttl> .

View File

@@ -0,0 +1,59 @@
/*
Copyright 2018 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_CORE_ATTRIBUTES_H
#define LV2_CORE_ATTRIBUTES_H
/**
@defgroup attributes Attributes
@ingroup lv2
Macros for source code attributes.
@{
*/
#if defined(__GNUC__) && __GNUC__ > 3
# define LV2_DEPRECATED __attribute__((__deprecated__))
#else
# define LV2_DEPRECATED
#endif
#if defined(__clang__)
# define LV2_DISABLE_DEPRECATION_WARNINGS \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
#elif defined(__GNUC__) && __GNUC__ > 4
# define LV2_DISABLE_DEPRECATION_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#else
# define LV2_DISABLE_DEPRECATION_WARNINGS
#endif
#if defined(__clang__)
# define LV2_RESTORE_WARNINGS _Pragma("clang diagnostic pop")
#elif defined(__GNUC__) && __GNUC__ > 4
# define LV2_RESTORE_WARNINGS _Pragma("GCC diagnostic pop")
#else
# define LV2_RESTORE_WARNINGS
#endif
/**
@}
*/
#endif /* LV2_CORE_ATTRIBUTES_H */

View File

@@ -0,0 +1,484 @@
/*
LV2 - An audio plugin interface specification.
Copyright 2007-2012 Steve Harris, David Robillard.
Based on LADSPA, Copyright 2000-2002 Richard W.E. Furse,
Paul Barton-Davis, Stefan Westerfeld.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_H_INCLUDED
#define LV2_H_INCLUDED
/**
@defgroup lv2 LV2
The LV2 specification.
@{
*/
/**
@defgroup lv2core LV2 Core
Core LV2 specification.
See <http://lv2plug.in/ns/lv2core> for details.
@{
*/
#include <stdint.h>
// clang-format off
#define LV2_CORE_URI "http://lv2plug.in/ns/lv2core" ///< http://lv2plug.in/ns/lv2core
#define LV2_CORE_PREFIX LV2_CORE_URI "#" ///< http://lv2plug.in/ns/lv2core#
#define LV2_CORE__AllpassPlugin LV2_CORE_PREFIX "AllpassPlugin" ///< http://lv2plug.in/ns/lv2core#AllpassPlugin
#define LV2_CORE__AmplifierPlugin LV2_CORE_PREFIX "AmplifierPlugin" ///< http://lv2plug.in/ns/lv2core#AmplifierPlugin
#define LV2_CORE__AnalyserPlugin LV2_CORE_PREFIX "AnalyserPlugin" ///< http://lv2plug.in/ns/lv2core#AnalyserPlugin
#define LV2_CORE__AudioPort LV2_CORE_PREFIX "AudioPort" ///< http://lv2plug.in/ns/lv2core#AudioPort
#define LV2_CORE__BandpassPlugin LV2_CORE_PREFIX "BandpassPlugin" ///< http://lv2plug.in/ns/lv2core#BandpassPlugin
#define LV2_CORE__CVPort LV2_CORE_PREFIX "CVPort" ///< http://lv2plug.in/ns/lv2core#CVPort
#define LV2_CORE__ChorusPlugin LV2_CORE_PREFIX "ChorusPlugin" ///< http://lv2plug.in/ns/lv2core#ChorusPlugin
#define LV2_CORE__CombPlugin LV2_CORE_PREFIX "CombPlugin" ///< http://lv2plug.in/ns/lv2core#CombPlugin
#define LV2_CORE__CompressorPlugin LV2_CORE_PREFIX "CompressorPlugin" ///< http://lv2plug.in/ns/lv2core#CompressorPlugin
#define LV2_CORE__ConstantPlugin LV2_CORE_PREFIX "ConstantPlugin" ///< http://lv2plug.in/ns/lv2core#ConstantPlugin
#define LV2_CORE__ControlPort LV2_CORE_PREFIX "ControlPort" ///< http://lv2plug.in/ns/lv2core#ControlPort
#define LV2_CORE__ConverterPlugin LV2_CORE_PREFIX "ConverterPlugin" ///< http://lv2plug.in/ns/lv2core#ConverterPlugin
#define LV2_CORE__DelayPlugin LV2_CORE_PREFIX "DelayPlugin" ///< http://lv2plug.in/ns/lv2core#DelayPlugin
#define LV2_CORE__DistortionPlugin LV2_CORE_PREFIX "DistortionPlugin" ///< http://lv2plug.in/ns/lv2core#DistortionPlugin
#define LV2_CORE__DynamicsPlugin LV2_CORE_PREFIX "DynamicsPlugin" ///< http://lv2plug.in/ns/lv2core#DynamicsPlugin
#define LV2_CORE__EQPlugin LV2_CORE_PREFIX "EQPlugin" ///< http://lv2plug.in/ns/lv2core#EQPlugin
#define LV2_CORE__EnvelopePlugin LV2_CORE_PREFIX "EnvelopePlugin" ///< http://lv2plug.in/ns/lv2core#EnvelopePlugin
#define LV2_CORE__ExpanderPlugin LV2_CORE_PREFIX "ExpanderPlugin" ///< http://lv2plug.in/ns/lv2core#ExpanderPlugin
#define LV2_CORE__ExtensionData LV2_CORE_PREFIX "ExtensionData" ///< http://lv2plug.in/ns/lv2core#ExtensionData
#define LV2_CORE__Feature LV2_CORE_PREFIX "Feature" ///< http://lv2plug.in/ns/lv2core#Feature
#define LV2_CORE__FilterPlugin LV2_CORE_PREFIX "FilterPlugin" ///< http://lv2plug.in/ns/lv2core#FilterPlugin
#define LV2_CORE__FlangerPlugin LV2_CORE_PREFIX "FlangerPlugin" ///< http://lv2plug.in/ns/lv2core#FlangerPlugin
#define LV2_CORE__FunctionPlugin LV2_CORE_PREFIX "FunctionPlugin" ///< http://lv2plug.in/ns/lv2core#FunctionPlugin
#define LV2_CORE__GatePlugin LV2_CORE_PREFIX "GatePlugin" ///< http://lv2plug.in/ns/lv2core#GatePlugin
#define LV2_CORE__GeneratorPlugin LV2_CORE_PREFIX "GeneratorPlugin" ///< http://lv2plug.in/ns/lv2core#GeneratorPlugin
#define LV2_CORE__HighpassPlugin LV2_CORE_PREFIX "HighpassPlugin" ///< http://lv2plug.in/ns/lv2core#HighpassPlugin
#define LV2_CORE__InputPort LV2_CORE_PREFIX "InputPort" ///< http://lv2plug.in/ns/lv2core#InputPort
#define LV2_CORE__InstrumentPlugin LV2_CORE_PREFIX "InstrumentPlugin" ///< http://lv2plug.in/ns/lv2core#InstrumentPlugin
#define LV2_CORE__LimiterPlugin LV2_CORE_PREFIX "LimiterPlugin" ///< http://lv2plug.in/ns/lv2core#LimiterPlugin
#define LV2_CORE__LowpassPlugin LV2_CORE_PREFIX "LowpassPlugin" ///< http://lv2plug.in/ns/lv2core#LowpassPlugin
#define LV2_CORE__MixerPlugin LV2_CORE_PREFIX "MixerPlugin" ///< http://lv2plug.in/ns/lv2core#MixerPlugin
#define LV2_CORE__ModulatorPlugin LV2_CORE_PREFIX "ModulatorPlugin" ///< http://lv2plug.in/ns/lv2core#ModulatorPlugin
#define LV2_CORE__MultiEQPlugin LV2_CORE_PREFIX "MultiEQPlugin" ///< http://lv2plug.in/ns/lv2core#MultiEQPlugin
#define LV2_CORE__OscillatorPlugin LV2_CORE_PREFIX "OscillatorPlugin" ///< http://lv2plug.in/ns/lv2core#OscillatorPlugin
#define LV2_CORE__OutputPort LV2_CORE_PREFIX "OutputPort" ///< http://lv2plug.in/ns/lv2core#OutputPort
#define LV2_CORE__ParaEQPlugin LV2_CORE_PREFIX "ParaEQPlugin" ///< http://lv2plug.in/ns/lv2core#ParaEQPlugin
#define LV2_CORE__PhaserPlugin LV2_CORE_PREFIX "PhaserPlugin" ///< http://lv2plug.in/ns/lv2core#PhaserPlugin
#define LV2_CORE__PitchPlugin LV2_CORE_PREFIX "PitchPlugin" ///< http://lv2plug.in/ns/lv2core#PitchPlugin
#define LV2_CORE__Plugin LV2_CORE_PREFIX "Plugin" ///< http://lv2plug.in/ns/lv2core#Plugin
#define LV2_CORE__PluginBase LV2_CORE_PREFIX "PluginBase" ///< http://lv2plug.in/ns/lv2core#PluginBase
#define LV2_CORE__Point LV2_CORE_PREFIX "Point" ///< http://lv2plug.in/ns/lv2core#Point
#define LV2_CORE__Port LV2_CORE_PREFIX "Port" ///< http://lv2plug.in/ns/lv2core#Port
#define LV2_CORE__PortProperty LV2_CORE_PREFIX "PortProperty" ///< http://lv2plug.in/ns/lv2core#PortProperty
#define LV2_CORE__Resource LV2_CORE_PREFIX "Resource" ///< http://lv2plug.in/ns/lv2core#Resource
#define LV2_CORE__ReverbPlugin LV2_CORE_PREFIX "ReverbPlugin" ///< http://lv2plug.in/ns/lv2core#ReverbPlugin
#define LV2_CORE__ScalePoint LV2_CORE_PREFIX "ScalePoint" ///< http://lv2plug.in/ns/lv2core#ScalePoint
#define LV2_CORE__SimulatorPlugin LV2_CORE_PREFIX "SimulatorPlugin" ///< http://lv2plug.in/ns/lv2core#SimulatorPlugin
#define LV2_CORE__SpatialPlugin LV2_CORE_PREFIX "SpatialPlugin" ///< http://lv2plug.in/ns/lv2core#SpatialPlugin
#define LV2_CORE__Specification LV2_CORE_PREFIX "Specification" ///< http://lv2plug.in/ns/lv2core#Specification
#define LV2_CORE__SpectralPlugin LV2_CORE_PREFIX "SpectralPlugin" ///< http://lv2plug.in/ns/lv2core#SpectralPlugin
#define LV2_CORE__UtilityPlugin LV2_CORE_PREFIX "UtilityPlugin" ///< http://lv2plug.in/ns/lv2core#UtilityPlugin
#define LV2_CORE__WaveshaperPlugin LV2_CORE_PREFIX "WaveshaperPlugin" ///< http://lv2plug.in/ns/lv2core#WaveshaperPlugin
#define LV2_CORE__appliesTo LV2_CORE_PREFIX "appliesTo" ///< http://lv2plug.in/ns/lv2core#appliesTo
#define LV2_CORE__binary LV2_CORE_PREFIX "binary" ///< http://lv2plug.in/ns/lv2core#binary
#define LV2_CORE__connectionOptional LV2_CORE_PREFIX "connectionOptional" ///< http://lv2plug.in/ns/lv2core#connectionOptional
#define LV2_CORE__control LV2_CORE_PREFIX "control" ///< http://lv2plug.in/ns/lv2core#control
#define LV2_CORE__default LV2_CORE_PREFIX "default" ///< http://lv2plug.in/ns/lv2core#default
#define LV2_CORE__designation LV2_CORE_PREFIX "designation" ///< http://lv2plug.in/ns/lv2core#designation
#define LV2_CORE__documentation LV2_CORE_PREFIX "documentation" ///< http://lv2plug.in/ns/lv2core#documentation
#define LV2_CORE__enumeration LV2_CORE_PREFIX "enumeration" ///< http://lv2plug.in/ns/lv2core#enumeration
#define LV2_CORE__extensionData LV2_CORE_PREFIX "extensionData" ///< http://lv2plug.in/ns/lv2core#extensionData
#define LV2_CORE__freeWheeling LV2_CORE_PREFIX "freeWheeling" ///< http://lv2plug.in/ns/lv2core#freeWheeling
#define LV2_CORE__hardRTCapable LV2_CORE_PREFIX "hardRTCapable" ///< http://lv2plug.in/ns/lv2core#hardRTCapable
#define LV2_CORE__inPlaceBroken LV2_CORE_PREFIX "inPlaceBroken" ///< http://lv2plug.in/ns/lv2core#inPlaceBroken
#define LV2_CORE__index LV2_CORE_PREFIX "index" ///< http://lv2plug.in/ns/lv2core#index
#define LV2_CORE__integer LV2_CORE_PREFIX "integer" ///< http://lv2plug.in/ns/lv2core#integer
#define LV2_CORE__isLive LV2_CORE_PREFIX "isLive" ///< http://lv2plug.in/ns/lv2core#isLive
#define LV2_CORE__latency LV2_CORE_PREFIX "latency" ///< http://lv2plug.in/ns/lv2core#latency
#define LV2_CORE__maximum LV2_CORE_PREFIX "maximum" ///< http://lv2plug.in/ns/lv2core#maximum
#define LV2_CORE__microVersion LV2_CORE_PREFIX "microVersion" ///< http://lv2plug.in/ns/lv2core#microVersion
#define LV2_CORE__minimum LV2_CORE_PREFIX "minimum" ///< http://lv2plug.in/ns/lv2core#minimum
#define LV2_CORE__minorVersion LV2_CORE_PREFIX "minorVersion" ///< http://lv2plug.in/ns/lv2core#minorVersion
#define LV2_CORE__name LV2_CORE_PREFIX "name" ///< http://lv2plug.in/ns/lv2core#name
#define LV2_CORE__optionalFeature LV2_CORE_PREFIX "optionalFeature" ///< http://lv2plug.in/ns/lv2core#optionalFeature
#define LV2_CORE__port LV2_CORE_PREFIX "port" ///< http://lv2plug.in/ns/lv2core#port
#define LV2_CORE__portProperty LV2_CORE_PREFIX "portProperty" ///< http://lv2plug.in/ns/lv2core#portProperty
#define LV2_CORE__project LV2_CORE_PREFIX "project" ///< http://lv2plug.in/ns/lv2core#project
#define LV2_CORE__prototype LV2_CORE_PREFIX "prototype" ///< http://lv2plug.in/ns/lv2core#prototype
#define LV2_CORE__reportsLatency LV2_CORE_PREFIX "reportsLatency" ///< http://lv2plug.in/ns/lv2core#reportsLatency
#define LV2_CORE__requiredFeature LV2_CORE_PREFIX "requiredFeature" ///< http://lv2plug.in/ns/lv2core#requiredFeature
#define LV2_CORE__sampleRate LV2_CORE_PREFIX "sampleRate" ///< http://lv2plug.in/ns/lv2core#sampleRate
#define LV2_CORE__scalePoint LV2_CORE_PREFIX "scalePoint" ///< http://lv2plug.in/ns/lv2core#scalePoint
#define LV2_CORE__symbol LV2_CORE_PREFIX "symbol" ///< http://lv2plug.in/ns/lv2core#symbol
#define LV2_CORE__toggled LV2_CORE_PREFIX "toggled" ///< http://lv2plug.in/ns/lv2core#toggled
// clang-format on
#ifdef __cplusplus
extern "C" {
#endif
/**
Plugin Instance Handle.
This is a handle for one particular instance of a plugin. It is valid to
compare to NULL (or 0 for C++) but otherwise the host MUST NOT attempt to
interpret it.
*/
typedef void* LV2_Handle;
/**
Feature.
Features allow hosts to make additional functionality available to plugins
without requiring modification to the LV2 API. Extensions may define new
features and specify the `URI` and `data` to be used if necessary.
Some features, such as lv2:isLive, do not require the host to pass data.
*/
typedef struct {
/**
A globally unique, case-sensitive identifier (URI) for this feature.
This MUST be a valid URI string as defined by RFC 3986.
*/
const char* URI;
/**
Pointer to arbitrary data.
The format of this data is defined by the extension which describes the
feature with the given `URI`.
*/
void* data;
} LV2_Feature;
/**
Plugin Descriptor.
This structure provides the core functions necessary to instantiate and use
a plugin.
*/
typedef struct LV2_Descriptor {
/**
A globally unique, case-sensitive identifier for this plugin.
This MUST be a valid URI string as defined by RFC 3986. All plugins with
the same URI MUST be compatible to some degree, see
http://lv2plug.in/ns/lv2core for details.
*/
const char* URI;
/**
Instantiate the plugin.
Note that instance initialisation should generally occur in activate()
rather than here. If a host calls instantiate(), it MUST call cleanup()
at some point in the future.
@param descriptor Descriptor of the plugin to instantiate.
@param sample_rate Sample rate, in Hz, for the new plugin instance.
@param bundle_path Path to the LV2 bundle which contains this plugin
binary. It MUST include the trailing directory separator so that simply
appending a filename will yield the path to that file in the bundle.
@param features A NULL terminated array of LV2_Feature structs which
represent the features the host supports. Plugins may refuse to
instantiate if required features are not found here. However, hosts MUST
NOT use this as a discovery mechanism: instead, use the RDF data to
determine which features are required and do not attempt to instantiate
unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host
that supports no features MUST pass a single element array containing
NULL.
@return A handle for the new plugin instance, or NULL if instantiation
has failed.
*/
LV2_Handle (*instantiate)(const struct LV2_Descriptor* descriptor,
double sample_rate,
const char* bundle_path,
const LV2_Feature* const* features);
/**
Connect a port on a plugin instance to a memory location.
Plugin writers should be aware that the host may elect to use the same
buffer for more than one port and even use the same buffer for both
input and output (see lv2:inPlaceBroken in lv2.ttl).
If the plugin has the feature lv2:hardRTCapable then there are various
things that the plugin MUST NOT do within the connect_port() function;
see lv2core.ttl for details.
connect_port() MUST be called at least once for each port before run()
is called, unless that port is lv2:connectionOptional. The plugin must
pay careful attention to the block size passed to run() since the block
allocated may only just be large enough to contain the data, and is not
guaranteed to remain constant between run() calls.
connect_port() may be called more than once for a plugin instance to
allow the host to change the buffers that the plugin is reading or
writing. These calls may be made before or after activate() or
deactivate() calls.
@param instance Plugin instance containing the port.
@param port Index of the port to connect. The host MUST NOT try to
connect a port index that is not defined in the plugin's RDF data. If
it does, the plugin's behaviour is undefined (a crash is likely).
@param data_location Pointer to data of the type defined by the port
type in the plugin's RDF data (for example, an array of float for an
lv2:AudioPort). This pointer must be stored by the plugin instance and
used to read/write data when run() is called. Data present at the time
of the connect_port() call MUST NOT be considered meaningful.
*/
void (*connect_port)(LV2_Handle instance, uint32_t port, void* data_location);
/**
Initialise a plugin instance and activate it for use.
This is separated from instantiate() to aid real-time support and so
that hosts can reinitialise a plugin instance by calling deactivate()
and then activate(). In this case the plugin instance MUST reset all
state information dependent on the history of the plugin instance except
for any data locations provided by connect_port(). If there is nothing
for activate() to do then this field may be NULL.
When present, hosts MUST call this function once before run() is called
for the first time. This call SHOULD be made as close to the run() call
as possible and indicates to real-time plugins that they are now live,
however plugins MUST NOT rely on a prompt call to run() after
activate().
The host MUST NOT call activate() again until deactivate() has been
called first. If a host calls activate(), it MUST call deactivate() at
some point in the future. Note that connect_port() may be called before
or after activate().
*/
void (*activate)(LV2_Handle instance);
/**
Run a plugin instance for a block.
Note that if an activate() function exists then it must be called before
run(). If deactivate() is called for a plugin instance then run() may
not be called until activate() has been called again.
If the plugin has the feature lv2:hardRTCapable then there are various
things that the plugin MUST NOT do within the run() function (see
lv2core.ttl for details).
As a special case, when `sample_count` is 0, the plugin should update
any output ports that represent a single instant in time (for example,
control ports, but not audio ports). This is particularly useful for
latent plugins, which should update their latency output port so hosts
can pre-roll plugins to compute latency. Plugins MUST NOT crash when
`sample_count` is 0.
@param instance Instance to be run.
@param sample_count The block size (in samples) for which the plugin
instance must run.
*/
void (*run)(LV2_Handle instance, uint32_t sample_count);
/**
Deactivate a plugin instance (counterpart to activate()).
Hosts MUST deactivate all activated instances after they have been run()
for the last time. This call SHOULD be made as close to the last run()
call as possible and indicates to real-time plugins that they are no
longer live, however plugins MUST NOT rely on prompt deactivation. If
there is nothing for deactivate() to do then this field may be NULL
Deactivation is not similar to pausing since the plugin instance will be
reinitialised by activate(). However, deactivate() itself MUST NOT fully
reset plugin state. For example, the host may deactivate a plugin, then
store its state (using some extension to do so).
Hosts MUST NOT call deactivate() unless activate() was previously
called. Note that connect_port() may be called before or after
deactivate().
*/
void (*deactivate)(LV2_Handle instance);
/**
Clean up a plugin instance (counterpart to instantiate()).
Once an instance of a plugin has been finished with it must be deleted
using this function. The instance handle passed ceases to be valid after
this call.
If activate() was called for a plugin instance then a corresponding call
to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT
call cleanup() unless instantiate() was previously called.
*/
void (*cleanup)(LV2_Handle instance);
/**
Return additional plugin data defined by some extenion.
A typical use of this facility is to return a struct containing function
pointers to extend the LV2_Descriptor API.
The actual type and meaning of the returned object MUST be specified
precisely by the extension. This function MUST return NULL for any
unsupported URI. If a plugin does not support any extension data, this
field may be NULL.
The host is never responsible for freeing the returned value.
*/
const void* (*extension_data)(const char* uri);
} LV2_Descriptor;
/**
Helper macro needed for LV2_SYMBOL_EXPORT when using C++.
*/
#ifdef __cplusplus
# define LV2_SYMBOL_EXTERN extern "C"
#else
# define LV2_SYMBOL_EXTERN
#endif
/**
Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded
by the host as a symbol from the dynamic library.
*/
#ifdef _WIN32
# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __declspec(dllexport)
#else
# define LV2_SYMBOL_EXPORT \
LV2_SYMBOL_EXTERN __attribute__((visibility("default")))
#endif
/**
Prototype for plugin accessor function.
Plugins are discovered by hosts using RDF data (not by loading libraries).
See http://lv2plug.in for details on the discovery process, though most
hosts should use an existing library to implement this functionality.
This is the simple plugin discovery API, suitable for most statically
defined plugins. Advanced plugins that need access to their bundle during
discovery can use lv2_lib_descriptor() instead. Plugin libraries MUST
include a function called "lv2_descriptor" or "lv2_lib_descriptor" with
C-style linkage, but SHOULD provide "lv2_descriptor" wherever possible.
When it is time to load a plugin (designated by its URI), the host loads the
plugin's library, gets the lv2_descriptor() function from it, and uses this
function to find the LV2_Descriptor for the desired plugin. Plugins are
accessed by index using values from 0 upwards. This function MUST return
NULL for out of range indices, so the host can enumerate plugins by
increasing `index` until NULL is returned.
Note that `index` has no meaning, hosts MUST NOT depend on it remaining
consistent between loads of the plugin library.
*/
LV2_SYMBOL_EXPORT
const LV2_Descriptor*
lv2_descriptor(uint32_t index);
/**
Type of the lv2_descriptor() function in a library (old discovery API).
*/
typedef const LV2_Descriptor* (*LV2_Descriptor_Function)(uint32_t index);
/**
Handle for a library descriptor.
*/
typedef void* LV2_Lib_Handle;
/**
Descriptor for a plugin library.
To access a plugin library, the host creates an LV2_Lib_Descriptor via the
lv2_lib_descriptor() function in the shared object.
*/
typedef struct {
/**
Opaque library data which must be passed as the first parameter to all
the methods of this struct.
*/
LV2_Lib_Handle handle;
/**
The total size of this struct. This allows for this struct to be
expanded in the future if necessary. This MUST be set by the library to
sizeof(LV2_Lib_Descriptor). The host MUST NOT access any fields of this
struct beyond get_plugin() unless this field indicates they are present.
*/
uint32_t size;
/**
Destroy this library descriptor and free all related resources.
*/
void (*cleanup)(LV2_Lib_Handle handle);
/**
Plugin accessor.
Plugins are accessed by index using values from 0 upwards. Out of range
indices MUST result in this function returning NULL, so the host can
enumerate plugins by increasing `index` until NULL is returned.
*/
const LV2_Descriptor* (*get_plugin)(LV2_Lib_Handle handle, uint32_t index);
} LV2_Lib_Descriptor;
/**
Prototype for library accessor function.
This is the more advanced discovery API, which allows plugin libraries to
access their bundles during discovery, which makes it possible for plugins to
be dynamically defined by files in their bundle. This API also has an
explicit cleanup function, removing any need for non-portable shared library
destructors. Simple plugins that do not require these features may use
lv2_descriptor() instead.
This is the entry point for a plugin library. Hosts load this symbol from
the library and call this function to obtain a library descriptor which can
be used to access all the contained plugins. The returned object must not
be destroyed (using LV2_Lib_Descriptor::cleanup()) until all plugins loaded
from that library have been destroyed.
*/
LV2_SYMBOL_EXPORT
const LV2_Lib_Descriptor*
lv2_lib_descriptor(const char* bundle_path, const LV2_Feature* const* features);
/**
Type of the lv2_lib_descriptor() function in an LV2 library.
*/
typedef const LV2_Lib_Descriptor* (*LV2_Lib_Descriptor_Function)(
const char* bundle_path,
const LV2_Feature* const* features);
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
@}
*/
#endif /* LV2_H_INCLUDED */

View File

@@ -0,0 +1,103 @@
/*
Copyright 2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
@defgroup util Utilities
@ingroup lv2core
@{
*/
#include "lv2/core/lv2.h"
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
Return the data for a feature in a features array.
If the feature is not found, NULL is returned. Note that this function is
only useful for features with data, and can not detect features that are
present but have NULL data.
*/
static inline void*
lv2_features_data(const LV2_Feature* const* features, const char* const uri)
{
if (features) {
for (const LV2_Feature* const* f = features; *f; ++f) {
if (!strcmp(uri, (*f)->URI)) {
return (*f)->data;
}
}
}
return NULL;
}
/**
Query a features array.
This function allows getting several features in one call, and detect
missing required features, with the same caveat of lv2_features_data().
The arguments should be a series of const char* uri, void** data, bool
required, terminated by a NULL URI. The data pointers MUST be initialized
to NULL. For example:
@code
LV2_URID_Log* log = NULL;
LV2_URID_Map* map = NULL;
const char* missing = lv2_features_query(
features,
LV2_LOG__log, &log, false,
LV2_URID__map, &map, true,
NULL);
@endcode
@return NULL on success, otherwise the URI of this missing feature.
*/
static inline const char*
lv2_features_query(const LV2_Feature* const* features, ...)
{
va_list args;
va_start(args, features);
const char* uri = NULL;
while ((uri = va_arg(args, const char*))) {
void** data = va_arg(args, void**);
bool required = va_arg(args, int);
*data = lv2_features_data(features, uri);
if (required && !*data) {
va_end(args);
return uri;
}
}
va_end(args);
return NULL;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
*/

View File

@@ -0,0 +1,905 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/lv2core>
a doap:Project ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2" ;
doap:homepage <http://lv2plug.in> ;
doap:created "2004-04-21" ;
doap:shortdesc "An extensible open standard for audio plugins" ;
doap:programming-language "C" ;
doap:developer <http://plugin.org.uk/swh.xrdf#me> ,
<http://drobilla.net/drobilla#me> ;
doap:maintainer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "18.0" ;
doap:created "2020-04-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.18.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add lv2:Markdown datatype."
] , [
rdfs:label "Deprecate lv2:reportsLatency."
]
]
] , [
doap:revision "16.0" ;
doap:created "2019-02-03" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add lv2:MIDIPlugin class."
] , [
rdfs:label "Rework port restrictions so that presets can be validated."
]
]
] , [
doap:revision "14.0" ;
doap:created "2016-09-18" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.14.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add lv2_util.h with lv2_features_data() and lv2_features_query()."
] , [
rdfs:label "Add lv2:enabled designation."
]
]
] , [
doap:revision "12.4" ;
doap:created "2015-04-07" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.12.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Relax domain of lv2:minimum lv2:maximum and lv2:default so they can be used to describe properties/parameters as well."
] , [
rdfs:label "Add extern C and visibility attribute to LV2_SYMBOL_EXPORT."
] , [
rdfs:label "Add lv2:isSideChain port property."
]
]
] , [
doap:revision "12.2" ;
doap:created "2014-08-08" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Clarify lv2_descriptor() and lv2_lib_descriptor() documentation."
]
]
] , [
doap:revision "12.0" ;
doap:created "2014-01-04" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.8.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add lv2:prototype for property inheritance."
]
]
] , [
doap:revision "10.0" ;
doap:created "2013-02-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add lv2:EnvelopePlugin class."
] , [
rdfs:label "Add lv2:control for designating primary event-based control ports."
] , [
rdfs:label "Set range of lv2:designation to lv2:Designation."
] , [
rdfs:label "Make lv2:Parameter rdfs:subClassOf rdf:Property."
] , [
rdfs:label "Reserve minor version 0 for unstable development plugins."
]
]
] , [
doap:revision "8.2" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Use consistent label style."
]
]
] , [
doap:revision "8.0" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix LV2_SYMBOL_EXPORT and lv2_descriptor prototype for Windows."
] , [
rdfs:label "Add metadata concept of a designation, a channel or parameter description which can be assigned to ports for more intelligent use by hosts."
] , [
rdfs:label "Add new discovery API which allows libraries to read bundle files during discovery, makes library construction/destruction explicit, and adds extensibility to prevent future breakage."
] , [
rdfs:label "Relax the range of lv2:index so it can be used for things other than ports."
] , [
rdfs:label "Remove lv2:Resource, which turned out to be meaningless."
] , [
rdfs:label "Add lv2:CVPort."
] , [
rdfs:label "Merge with unified LV2 package."
]
]
] , [
doap:revision "6.0" ;
doap:created "2011-11-21" ;
doap:file-release <http://lv2plug.in/spec/lv2core-6.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Rename core.lv2 and lv2.ttl to lv2core.lv2 and lv2core.ttl to adhere to modern conventions."
] , [
rdfs:label "Add lv2:extensionData and lv2:ExtensionData for plugins to indicate that they support some URI for extension_data()."
] , [
rdfs:label "Remove lv2config in favour of the simple convention that specifications install headers to standard URI-based paths."
] , [
rdfs:label "Switch to the ISC license, a simple BSD-style license (with permission of all contributors to lv2.h and its ancestor, ladspa.h)."
] , [
rdfs:label "Make lv2core.ttl a valid OWL 2 DL ontology."
] , [
rdfs:label "Improve documentation."
]
]
] , [
doap:revision "4.0" ;
doap:created "2011-03-18" ;
doap:file-release <http://lv2plug.in/spec/lv2core-4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Make doap:license suggested, but not required (for wrappers)."
] , [
rdfs:label "Define lv2:binary (MUST be in manifest.ttl)."
] , [
rdfs:label "Define lv2:minorVersion and lv2:microVersion (MUST be in manifest.ttl)."
] , [
rdfs:label "Define lv2:documentation and use it to document lv2core."
] , [
rdfs:label "Add lv2:FunctionPlugin and lv2:ConstantPlugin classes."
] , [
rdfs:label "Move lv2:AmplifierPlugin under lv2:DynamicsPlugin."
] , [
rdfs:label "Loosen domain of lv2:optionalFeature and lv2:requiredFeature (to allow re-use in extensions)."
] , [
rdfs:label "Add generic lv2:Resource and lv2:PluginBase classes."
] , [
rdfs:label "Fix definition of lv2:minimum etc. (used for values, not scale points)."
] , [
rdfs:label "More precisely define properties with OWL."
] , [
rdfs:label "Move project metadata to manifest."
] , [
rdfs:label "Add lv2:enumeration port property."
] , [
rdfs:label "Define run() pre-roll special case (sample_count == 0)."
]
]
] , [
doap:revision "3.0" ;
doap:created "2008-11-08" ;
doap:file-release <http://lv2plug.in/spec/lv2core-3.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Require that serialisations refer to ports by symbol rather than index."
] , [
rdfs:label "Minor stylistic changes to lv2.ttl."
] , [
rdfs:label "No header changes."
]
]
] , [
doap:revision "2.0" ;
doap:created "2008-02-10" ;
doap:file-release <http://lv2plug.in/spec/lv2core-2.0.tar.gz> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
LV2 is an interface for writing audio plugins in C or compatible languages,
which can be dynamically loaded into many _host_ applications. This core
specification is simple and minimal, but is designed so that _extensions_ can
be defined to add more advanced features, making it possible to implement
nearly any feature.
LV2 maintains a strong distinction between code and data. Plugin code is in a
shared library, while data is in a companion data file written in
[Turtle](https://www.w3.org/TR/turtle/). Code, data, and any other resources
(such as waveforms) are shipped together in a bundle directory. The code
contains only the executable portions of the plugin. All other data is
provided in the data file(s). This makes plugin data flexible and extensible,
and allows the host to do everything but run the plugin without loading or
executing any code. Among other advantages, this makes hosts more robust
(broken plugins can't crash a host during discovery) and allows generic tools
written in any language to work with LV2 data. The LV2 specification itself is
distributed in a similar way.
An LV2 plugin library is suitable for dynamic loading (for example with
`dlopen()`) and provides one or more plugin descriptors via `lv2_descriptor()`
or `lv2_lib_descriptor()`. These can be instantiated to create plugin
instances, which can be run directly on data or connected together to perform
advanced signal processing tasks.
Plugins communicate via _ports_, which can transmit any type of data. Data is
processed by first connecting each port to a buffer, then repeatedly calling
the `run()` method to process blocks of data.
This core specification defines two types of port, equivalent to those in
[LADSPA](http://www.ladspa.org/), lv2:ControlPort and lv2:AudioPort, as well as
lv2:CVPort which has the same format as an audio port but is interpreted as
non-audible control data. Audio ports contain arrays with one `float` element
per sample, allowing a block of audio to be processed in a single call to
`run()`. Control ports contain single `float` values, which are fixed and
valid for the duration of the call to `run()`. Thus the _control rate_ is
determined by the block size, which is controlled by the host (and not
necessarily constant).
### Threading Rules
To faciliate use in multi-threaded programs, LV2 functions are partitioned into
several threading classes:
| Discovery Class | Instantiation Class | Audio Class |
|----------------------------------|-------------------------------|------------------------------- |
| lv2_descriptor() | LV2_Descriptor::instantiate() | LV2_Descriptor::run() |
| lv2_lib_descriptor() | LV2_Descriptor::cleanup() | LV2_Descriptor::connect_port() |
| LV2_Descriptor::extension_data() | LV2_Descriptor::activate() | |
| | LV2_Descriptor::deactivate() | |
Hosts MUST guarantee that:
* A function in any class is never called concurrently with another function
in that class.
* A _Discovery_ function is never called concurrently with any other fuction
in the same shared object file.
* An _Instantiation_ function for an instance is never called concurrently
with any other function for that instance.
Any simultaneous calls that are not explicitly forbidden by these rules are
allowed. For example, a host may call `run()` for two different plugin
instances simultaneously.
Plugin functions in any class MUST NOT manipulate any state which might affect
other plugins or the host (beyond the contract of that function), for example
by using non-reentrant global functions.
Extensions to this specification which add new functions MUST declare in which
of these classes the functions belong, define new classes for them, or
otherwise precisely describe their threading rules.
"""^^lv2:Markdown .
lv2:Specification
lv2:documentation """
An LV2 specification typically contains a vocabulary description, C headers to
define an API, and any other resources that may be useful. Specifications,
like plugins, are distributed and installed as bundles so that hosts may
discover them.
"""^^lv2:Markdown .
lv2:Markdown
lv2:documentation """
This datatype is typically used for documentation in
[Markdown](https://daringfireball.net/projects/markdown/syntax) syntax.
Generally, documentation with this datatype should stay as close to readable
plain text as possible, but may use core Markdown syntax for nicer
presentation. Documentation can assume that basic extensions like codehilite
and tables are available.
"""^^lv2:Markdown .
lv2:documentation
lv2:documentation """
Relates a Resource to extended documentation.
LV2 specifications are documented using this property with an lv2:Markdown
datatype.
If the value has no explicit datatype, it is assumed to be a valid XHTML Basic
1.1 fragment suitable for use as the content of the `body` element of a page.
XHTML Basic is a W3C Recommendation which defines a simplified subset of XHTML
intended to be reasonable to implement with limited resources, for exampe on
embedded devices. See [XHTML Basic, Section
3](http://www.w3.org/TR/xhtml-basic/#s_xhtmlmodules) for a list of valid tags.
"""^^lv2:Markdown .
lv2:PluginBase
lv2:documentation """
An abstract plugin-like resource that may not actually be an LV2 plugin, for
example that may not have a lv2:binary. This is useful for describing things
that share common structure with a plugin, but are not themselves an actul
plugin, such as presets.
"""^^lv2:Markdown .
lv2:Plugin
lv2:documentation """
To be discovered by hosts, plugins MUST explicitly have an rdf:type of lv2:Plugin
in their bundle's manifest, for example:
:::turtle
<http://example.org/my-plugin> a lv2:Plugin .
Plugins should have a doap:name property that is at most a few words in length
using title capitalization, for example <q>Tape Delay Unit</q>.
"""^^lv2:Markdown .
lv2:PortBase
lv2:documentation """
Similar to lv2:PluginBase, this is an abstract port-like resource that may not
be a fully specified LV2 port. For example, this is used for preset "ports"
which do not specify an index.
"""^^lv2:Markdown .
lv2:Port
lv2:documentation """
All LV2 port descriptions MUST have a rdf:type that is one of lv2:Port,
lv2:InputPort or lv2:OutputPort. Additionally, there MUST be at least one
other rdf:type which more precisely describes type of the port, for example
lv2:AudioPort.
Hosts that do not support a specific port class MUST NOT instantiate the
plugin, unless that port has the lv2:connectionOptional property set.
A port has two identifiers: a (numeric) index, and a (textual) symbol. The
index can be used as an identifier at run-time, but persistent references to
ports (for example in presets or save files) MUST use the symbol. Only the
symbol is guaranteed to refer to the same port on all plugins with a given URI,
that is the index for a port may differ between plugin binaries.
"""^^lv2:Markdown .
lv2:AudioPort
lv2:documentation """
Ports of this type are connected to a buffer of `float` audio samples, which
the host guarantees have `sample_count` elements in any call to
LV2_Descriptor::run().
Audio samples are normalized between -1.0 and 1.0, though there is no
requirement for samples to be strictly within this range.
"""^^lv2:Markdown .
lv2:CVPort
lv2:documentation """
Ports of this type have the same buffer format as an lv2:AudioPort, except the
buffer represents audio-rate control data rather than audio. Like a
lv2:ControlPort, a CV port SHOULD have properties describing its value, in
particular lv2:minimum, lv2:maximum, and lv2:default.
Hosts may present CV ports to users as controls in the same way as control
ports. Conceptually, aside from the buffer format, a CV port is the same as a
control port, so hosts can use all the same properties and expectations.
In particular, this port type does not imply any range, unit, or meaning for
its values. However, if there is no inherent unit to the values, for example
if the port is used to modulate some other value, then plugins SHOULD use a
normalized range, either from -1.0 to 1.0, or from 0.0 to 1.0.
It is generally safe to connect an audio output to a CV input, but not
vice-versa. Hosts must take care to prevent data from a CVPort port from being
used as audio.
"""^^lv2:Markdown .
lv2:project
lv2:documentation """
This property provides a way to group plugins and/or related resources. A
project may have useful metadata common to all plugins (such as homepage,
author, version history) which would be wasteful to list separately for each
plugin.
Grouping via projects also allows users to find plugins in hosts by project,
which is often how they are remembered. For this reason, a project that
contains plugins SHOULD always have a doap:name. It is also a good idea for
each plugin and the project itself to have an lv2:symbol property, which allows
nice quasi-global identifiers for plugins, for example `myproj.superamp` which
can be useful for display or fast user entry.
"""^^lv2:Markdown .
lv2:prototype
lv2:documentation """
This property can be used to <q>include</q> common properties in several
descriptions, serving as a sort of template mechanism. If a plugin has a
prototype, then the host must load all the properties for the prototype as if
they were properties of the plugin. That is, if `:plug lv2:prototype :prot`,
then for each triple `:prot p o`, the triple `:plug p o` should be loaded.
This facility is useful for distributing data-only plugins that rely on a
common binary, for example those where the internal state is loaded from some
other file. Such plugins can refer to a prototype in a template LV2 bundle
which is installed by the corresponding software.
"""^^lv2:Markdown .
lv2:minorVersion
lv2:documentation """
This, along with lv2:microVersion, is used to distinguish between different
versions of the <q>same</q> resource, for example to load only the bundle with
the most recent version of a plugin. An LV2 version has a minor and micro
number with the usual semantics:
* The minor version MUST be incremented when backwards (but not forwards)
compatible additions are made, for example the addition of a port to a
plugin.
* The micro version is incremented for changes which do not affect
compatibility at all, for example bug fixes or documentation updates.
Note that there is deliberately no major version: all versions with the same
URI are compatible by definition. Replacing a resource with a newer version of
that resource MUST NOT break anything. If a change violates this rule, then
the URI of the resource (which serves as the major version) MUST be changed.
Plugins and extensions MUST adhere to at least the following rules:
* All versions of a plugin with a given URI MUST have the <q>same</q> set of
mandatory (not lv2:connectionOptional) ports with respect to lv2:symbol and
rdf:type. In other words, every port on a particular version is guaranteed
to exist on a future version with same lv2:symbol and at least those
rdf:types.
* New ports MAY be added without changing the plugin URI if and only if they
are lv2:connectionOptional and the minor version is incremented.
* The minor version MUST be incremented if the index of any port (identified
by its symbol) is changed.
* All versions of a specification MUST be compatible in the sense that an
implementation of the new version can interoperate with an implementation
of any previous version.
Anything that depends on a specific version of a plugin (including referencing
ports by index) MUST refer to the plugin by both URI and version. However,
implementations should be tolerant where possible.
When hosts discover several installed versions of a resource, they SHOULD warn
the user and load only the most recent version.
An odd minor _or_ micro version, or minor version zero, indicates that the
resource is a development version. Hosts and tools SHOULD clearly indicate
this wherever appropriate. Minor version zero is a special case for
pre-release development of plugins, or experimental plugins that are not
intended for stable use at all. Hosts SHOULD NOT expect such a plugin to
remain compatible with any future version. Where feasible, hosts SHOULD NOT
expose such plugins to users by default, but may provide an option to display
them.
"""^^lv2:Markdown .
lv2:microVersion
lv2:documentation """
Releases of plugins and extensions MUST be explicitly versioned. Correct
version numbers MUST always be maintained for any versioned resource that is
published. For example, after a release, if a change is made in the development
version in source control, the micro version MUST be incremented (to an odd
number) to distinguish this modified version from the previous release.
This property describes half of a resource version. For detailed documentation
on LV2 resource versioning, see lv2:minorVersion.
"""^^lv2:Markdown .
lv2:binary
lv2:documentation """
The value of this property must be the URI of a shared library object,
typically in the same bundle as the data file which contains this property.
The actual type of the library is platform specific.
This is a required property of a lv2:Plugin which MUST be included in the
bundle's `manifest.ttl` file. The lv2:binary of a lv2:Plugin is the shared
object containing the lv2_descriptor() or lv2_lib_descriptor() function. This
probably may also be used similarly by extensions to relate other resources to
their implementations (it is not implied that a lv2:binary on an arbitrary
resource is an LV2 plugin library).
"""^^lv2:Markdown .
lv2:appliesTo
lv2:documentation """
This is primarily intended for discovery purposes: bundles that describe
resources that work with particular plugins (like presets or user interfaces)
SHOULD specify this in their `manifest.ttl` so the host can associate them with
the correct plugin. For example:
:::turtle
<thing>
a ext:Thing ;
lv2:appliesTo <plugin> ;
rdfs:seeAlso <thing.ttl> .
Using this pattern is preferable for large amounts of data, since the host may
choose whether/when to load the data.
"""^^lv2:Markdown .
lv2:Symbol
lv2:documentation """
The first character of a symbol must be one of `_`, `a-z` or `A-Z`, and
subsequent characters may additionally be `0-9`. This is, among other things,
a valid C identifier, and generally compatible in most contexts which have
restrictions on string identifiers, such as file paths.
"""^^lv2:Markdown .
lv2:symbol
lv2:documentation """
The value of this property MUST be a valid lv2:Symbol, and MUST NOT have a
language tag.
A symbol is a unique identifier with respect to the parent, for example a
port's symbol is a unique identifiers with respect to its plugin. The plugin
author MUST change the plugin URI if any port symbol is changed or removed.
"""^^lv2:Markdown .
lv2:name
lv2:documentation """
Unlike lv2:symbol, this is unrestricted, may be translated, and is not relevant
for compatibility. The name is not necessarily unique and MUST NOT be used as
an identifier.
"""^^lv2:Markdown .
lv2:shortName
lv2:documentation """
This is the same as lv2:name, with the additional requirement that the value is
shorter than 16 characters.
"""^^lv2:Markdown .
lv2:Designation
lv2:documentation """
A designation is metadata that describes the meaning or role of something. By
assigning a designation to a port using lv2:designation, the port's content
becomes meaningful and can be used more intelligently by the host.
"""^^lv2:Markdown .
lv2:Channel
lv2:documentation """
A specific channel, for example the <q>left</q> channel of a stereo stream. A
channel may be audio, or another type such as a MIDI control stream.
"""^^lv2:Markdown .
lv2:Parameter
lv2:documentation """
A parameter is a designation for a control.
A parameter defines the meaning of a control, not the method of conveying its
value. For example, a parameter could be controlled via a lv2:ControlPort,
messages, or both.
A lv2:ControlPort can be associated with a parameter using lv2:designation.
"""^^lv2:Markdown .
lv2:designation
lv2:documentation """
This property is used to give a port's contents a well-defined meaning. For
example, if a port has the designation `eg:gain`, then the value of that port
represents the `eg:gain` of the plugin instance.
Ports should be given designations whenever possible, particularly if a
suitable designation is already defined. This allows the host to act more
intelligently and provide a more effective user interface. For example, if the
plugin has a BPM parameter, the host may automatically set that parameter to
the current tempo.
"""^^lv2:Markdown .
lv2:freeWheeling
lv2:documentation """
If true, this means that all processing is happening as quickly as possible,
not in real-time. When free-wheeling there is no relationship between the
passage of real wall-clock time and the passage of time in the data being
processed.
"""^^lv2:Markdown .
lv2:enabled
lv2:documentation """
If this value is greater than zero, the plugin processes normally. If this
value is zero, the plugin is expected to bypass all signals unmodified. The
plugin must provide a click-free transition between the enabled and disabled
(bypassed) states.
Values less than zero are reserved for future use (such as click-free
insertion/removal of latent plugins), and should be treated like zero
(bypassed) by current implementations.
"""^^lv2:Markdown .
lv2:control
lv2:documentation """
This should be used as the lv2:designation of ports that are used to send
commands and receive responses. Typically this will be an event port that
supports some protocol, for example MIDI or LV2 Atoms.
"""^^lv2:Markdown .
lv2:Point
lv2:documentation """
* A Point MUST have at least one rdfs:label which is a string.
* A Point MUST have exactly one rdf:value with a type that is compatible with
the type of the corresponding Port.
"""^^lv2:Markdown .
lv2:default
lv2:documentation """
The host SHOULD set the port to this value initially, and in any situation
where the port value should be cleared or reset.
"""^^lv2:Markdown .
lv2:minimum
lv2:documentation """
This is a soft limit: the plugin is required to gracefully accept all values in
the range of a port's data type.
"""^^lv2:Markdown .
lv2:maximum
lv2:documentation """
This is a soft limit: the plugin is required to gracefully accept all values in
the range of a port's data type.
"""^^lv2:Markdown .
lv2:optionalFeature
lv2:documentation """
To support this feature, the host MUST pass its URI and any additional data to
the plugin in LV2_Descriptor::instantiate().
The plugin MUST NOT fail to instantiate if an optional feature is not supported
by the host.
"""^^lv2:Markdown .
lv2:requiredFeature
lv2:documentation """
To support this feature, the host MUST pass its URI and any additional data to
the plugin in LV2_Descriptor::instantiate().
The host MUST check this property before attempting to instantiate a plugin,
and not attempt to instantiate plugins which require features it does not
support. The plugin MUST fail to instantiate if a required feature is not
supported by the host. Note that these rules are intentionally redundant for
resilience: neither host nor plugin should assume that the other does not
violate them.
"""^^lv2:Markdown .
lv2:ExtensionData
lv2:documentation """
This is additional data that a plugin may return from
LV2_Descriptor::extension_data(). This is generally used to add APIs to extend
that defined by LV2_Descriptor.
"""^^lv2:Markdown .
lv2:extensionData
lv2:documentation """
If a plugin has a value for this property, it must be a URI that defines the
extension data. The plugin should return the appropriate data when
LV2_Descriptor::extension_data() is called with that URI as a parameter.
"""^^lv2:Markdown .
lv2:isLive
lv2:documentation """
This feature is for plugins that have time-sensitive internals, for example
communicating in real time over a socket. It indicates to the host that its
input and output must not be cached or subject to significant latency, and that
calls to LV2_Descriptor::run() should be made at a rate that roughly
corresponds to wall clock time (according to the `sample_count` parameter).
Note that this feature is not related to <q>hard real-time</q> execution
requirements (see lv2:hardRTCapable).
"""^^lv2:Markdown .
lv2:inPlaceBroken
lv2:documentation """
This feature indicates that the plugin may not work correctly if the host
elects to use the same data location for both input and output. Plugins that
will fail to work correctly if ANY input port is connected to the same location
as ANY output port MUST require this feature. Doing so should be avoided
whenever possible since it prevents hosts from running the plugin on data
<q>in-place</q>.
"""^^lv2:Markdown .
lv2:hardRTCapable
lv2:documentation """
This feature indicates that the plugin is capable of running in a <q>hard
real-time</q> environment. This should be the case for most audio processors,
so most plugins are expected to have this feature.
To support this feature, plugins MUST adhere to the following in all of their
audio class functions (LV2_Descriptor::run() and
LV2_Descriptor::connect_port()):
* There is no use of `malloc()`, `free()` or any other heap memory management
functions.
* There is no use of any library functions which do not adhere to these
rules. The plugin may assume that the standard C math library functions
are safe.
* There is no access to files, devices, pipes, sockets, system calls, or any
other mechanism that might result in the process or thread blocking.
* The maximum amount of time for a `run()` call is bounded by some expression
of the form `A + B * sample_count`, where `A` and `B` are platform specific
constants. Note that this bound does not depend on input signals or plugin
state.
"""^^lv2:Markdown .
lv2:portProperty
lv2:documentation """
States that a port has a particular lv2:PortProperty. This may be ignored
without catastrophic effects, though it may be useful, for example to provide a
sensible user interface for the port.
"""^^lv2:Markdown .
lv2:connectionOptional
lv2:documentation """
This property means that the port does not have to be connected to valid data
by the host. To leave a port <q>unconnected</q>, the host MUST explicitly
connect the port to `NULL`.
"""^^lv2:Markdown .
lv2:reportsLatency
lv2:documentation """
This property indicates that the port is used to express the processing latency
incurred by the plugin, expressed in samples. The latency may be affected by
the current sample rate, plugin settings, or other factors, and may be changed
by the plugin at any time. Where the latency is frequency dependent the plugin
may choose any appropriate value. If a plugin introduces latency it MUST
provide EXACTLY ONE port with this property set. In <q>fuzzy</q> cases the
value should be the most reasonable one based on user expectation of
input/output alignment. For example, musical delay plugins should not report
their delay as latency, since it is an intentional effect that the host should
not compensate for.
This property is deprecated, use a lv2:designation of lv2:latency instead,
following the same rules as above:
:::turtle
<http://example.org/plugin>
lv2:port [
a lv2:OutputPort , lv2:ControlPort ;
lv2:designation lv2:latency ;
lv2:symbol "latency" ;
]
"""^^lv2:Markdown .
lv2:toggled
lv2:documentation """
Indicates that the data item should be considered a boolean toggle. Data less
than or equal to zero should be considered <q>off</q> or <q>false</q>, and data
above zero should be considered <q>on</q> or <q>true</q>.
"""^^lv2:Markdown .
lv2:sampleRate
lv2:documentation """
Indicates that any specified bounds should be interpreted as multiples of the
sample rate. For example, a frequency range from 0 Hz to the Nyquist frequency
(half the sample rate) can be specified by using this property with lv2:minimum
0.0 and lv2:maximum 0.5. Hosts that support bounds at all MUST support this
property.
"""^^lv2:Markdown .
lv2:integer
lv2:documentation """
Indicates that all the reasonable values for a port are integers. For such
ports, a user interface should provide a stepped control that only allows
choosing integer values.
Note that this is only a hint, and that the plugin MUST operate reasonably even
if such a port has a non-integer value.
"""^^lv2:Markdown .
lv2:enumeration
lv2:documentation """
Indicates that all the rasonable values for a port are defined by
lv2:scalePoint properties. For such ports, a user interface should provide a selector that allows the user to choose any of the scale point values by name. It is recommended to show the value as well if possible.
Note that this is only a hint, and that the plugin MUST operate reasonably even
if such a port has a value that does not correspond to a scale point.
"""^^lv2:Markdown .
lv2:isSideChain
lv2:documentation """
Indicates that a port is a <q>sidechain</q>, which affects the output somehow
but should not be considered a part of the main signal chain. Sidechain ports
SHOULD be lv2:connectionOptional, and may be ignored by hosts.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,674 @@
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/lv2core>
a owl:Ontology ;
rdfs:label "LV2" ;
rdfs:comment "An extensible open standard for audio plugins." ;
rdfs:seeAlso <lv2.h> ,
<lv2_util.h> ,
<lv2core.meta.ttl> .
lv2:Specification
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf doap:Project ;
rdfs:label "Specification" ;
rdfs:comment "An LV2 specifiation." .
lv2:Markdown
a rdfs:Datatype ;
owl:onDatatype xsd:string ;
rdfs:label "Markdown" ;
rdfs:comment "A string in Markdown syntax." .
lv2:documentation
a rdf:Property ,
owl:AnnotationProperty ;
rdfs:range rdfs:Literal ;
rdfs:label "documentation" ;
rdfs:comment "Extended documentation." ;
rdfs:seeAlso <http://www.w3.org/TR/xhtml-basic/> .
lv2:PluginBase
a rdfs:Class ,
owl:Class ;
rdfs:label "Plugin Base" ;
rdfs:comment "Base class for a plugin-like resource." .
lv2:Plugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:PluginBase ;
rdfs:label "Plugin" ;
rdfs:comment "An LV2 plugin." ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty doap:name ;
owl:someValuesFrom rdf:PlainLiteral ;
rdfs:comment "A plugin MUST have at least one untranslated doap:name."
] , [
a owl:Restriction ;
owl:onProperty lv2:port ;
owl:allValuesFrom lv2:Port ;
rdfs:comment "All ports on a plugin MUST be fully specified lv2:Port instances."
] .
lv2:PortBase
a rdfs:Class ,
owl:Class ;
rdfs:label "Port Base" ;
rdfs:comment "Base class for a port-like resource." ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty lv2:symbol ;
owl:cardinality 1 ;
rdfs:comment "A port MUST have exactly one lv2:symbol."
] .
lv2:Port
a rdfs:Class ,
owl:Class ;
rdfs:label "Port" ;
rdfs:comment "An LV2 plugin port." ;
rdfs:subClassOf lv2:PortBase ,
[
a owl:Restriction ;
owl:onProperty lv2:name ;
owl:minCardinality 1 ;
rdfs:comment "A port MUST have at least one lv2:name."
] .
lv2:InputPort
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "Input Port" ;
rdfs:comment "A port connected to constant data which is read during `run()`." .
lv2:OutputPort
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "Output Port" ;
rdfs:comment "A port connected to data which is written during `run()`." .
lv2:ControlPort
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "Control Port" ;
rdfs:comment "A port connected to a single `float`." .
lv2:AudioPort
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "Audio Port" ;
rdfs:comment "A port connected to an array of float audio samples." .
lv2:CVPort
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "CV Port" ;
rdfs:comment "A port connected to an array of float control values." .
lv2:port
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain lv2:PluginBase ;
rdfs:range lv2:PortBase ;
rdfs:label "port" ;
rdfs:comment "A port (input or output) on this plugin." .
lv2:project
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range doap:Project ;
rdfs:label "project" ;
rdfs:comment "The project this is a part of." .
lv2:prototype
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "prototype" ;
rdfs:comment "The prototype to inherit properties from." .
lv2:minorVersion
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:range xsd:nonNegativeInteger ;
rdfs:label "minor version" ;
rdfs:comment "The minor version of this resource." .
lv2:microVersion
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:range xsd:nonNegativeInteger ;
rdfs:label "micro version" ;
rdfs:comment "The micro version of this resource." .
lv2:binary
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range owl:Thing ;
rdfs:label "binary" ;
rdfs:comment "The binary of this resource." .
lv2:appliesTo
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range lv2:Plugin ;
rdfs:label "applies to" ;
rdfs:comment "The plugin this resource is related to." .
lv2:index
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:range xsd:unsignedInt ;
rdfs:label "index" ;
rdfs:comment "A non-negative zero-based 32-bit index." .
lv2:Symbol
a rdfs:Datatype ;
owl:onDatatype xsd:string ;
owl:withRestrictions (
[
xsd:pattern "[_a-zA-Z][_a-zA-Z0-9]*"
]
) ;
rdfs:label "Symbol" ;
rdfs:comment "A short restricted name used as a strong identifier." .
lv2:symbol
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "symbol" ;
rdfs:range lv2:Symbol ,
rdf:PlainLiteral ;
rdfs:comment "The symbol that identifies this resource in the context of its parent." .
lv2:name
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:label "name" ;
rdfs:range xsd:string ;
rdfs:comment "A display name for labeling in a user interface." .
lv2:shortName
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:label "short name" ;
rdfs:range xsd:string ;
rdfs:comment "A short display name for labeling in a user interface." .
lv2:Designation
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf rdf:Property ;
rdfs:label "Designation" ;
rdfs:comment "A designation which defines the meaning of some data." .
lv2:Channel
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Designation ;
rdfs:label "Channel" ;
rdfs:comment "An individual channel, such as left or right." .
lv2:Parameter
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Designation ,
rdf:Property ;
rdfs:label "Parameter" ;
rdfs:comment "A property that is a plugin parameter." .
lv2:designation
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:range rdf:Property ;
rdfs:label "designation" ;
rdfs:comment "The designation that defines the meaning of this input or output." .
lv2:latency
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:range xsd:nonNegativeInteger ;
rdfs:label "latency" ;
rdfs:comment "The latency introduced, in frames." .
lv2:freeWheeling
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:label "free-wheeling" ;
rdfs:range xsd:boolean ;
rdfs:comment "Whether processing is currently free-wheeling." .
lv2:enabled
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:label "enabled" ;
rdfs:range xsd:int ;
rdfs:comment "Whether processing is currently enabled (not bypassed)." .
lv2:control
a lv2:Channel ;
rdfs:label "control" ;
rdfs:comment "The primary control channel." .
lv2:Point
a rdfs:Class ,
owl:Class ;
rdfs:label "Point" ;
rdfs:comment "An interesting point in a value range." .
lv2:ScalePoint
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Point ;
rdfs:label "Scale Point" ;
rdfs:comment "A single `float` Point for control inputs." .
lv2:scalePoint
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range lv2:ScalePoint ;
rdfs:label "scale point" ;
rdfs:comment "A scale point of a port or parameter." .
lv2:default
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "default" ;
rdfs:comment "The default value for this control." .
lv2:minimum
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "minimum" ;
rdfs:comment "The minimum value for this control." .
lv2:maximum
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "maximum" ;
rdfs:comment "The maximum value for this control." .
lv2:Feature
a rdfs:Class ,
owl:Class ;
rdfs:label "Feature" ;
rdfs:comment "An additional feature which may be used or required." .
lv2:optionalFeature
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range lv2:Feature ;
rdfs:label "optional feature" ;
rdfs:comment "An optional feature that is supported if available." .
lv2:requiredFeature
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range lv2:Feature ;
rdfs:label "required feature" ;
rdfs:comment "A required feature that must be available to run." .
lv2:ExtensionData
a rdfs:Class ,
owl:Class ;
rdfs:label "Extension Data" ;
rdfs:comment "Additional data defined by an extension." .
lv2:extensionData
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range lv2:ExtensionData ;
rdfs:label "extension data" ;
rdfs:comment "Extension data provided by a plugin or other binary." .
lv2:isLive
a lv2:Feature ;
rdfs:label "is live" ;
rdfs:comment "Plugin has a real-time dependency." .
lv2:inPlaceBroken
a lv2:Feature ;
rdfs:label "in-place broken" ;
rdfs:comment "Plugin requires separate locations for input and output." .
lv2:hardRTCapable
a lv2:Feature ;
rdfs:label "hard real-time capable" ;
rdfs:comment "Plugin is capable of running in a hard real-time environment." .
lv2:PortProperty
a rdfs:Class ,
owl:Class ;
rdfs:label "Port Property" ;
rdfs:comment "A particular property that a port has." .
lv2:portProperty
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain lv2:Port ;
rdfs:range lv2:PortProperty ;
rdfs:label "port property" ;
rdfs:comment "A property of this port hosts may find useful." .
lv2:connectionOptional
a lv2:PortProperty ;
rdfs:label "connection optional" ;
rdfs:comment "The property that this port may be connected to NULL." .
lv2:reportsLatency
a lv2:PortProperty ;
owl:deprecated "true"^^xsd:boolean ;
rdfs:label "reports latency" ;
rdfs:comment "Control port value is the plugin latency in frames." .
lv2:toggled
a lv2:PortProperty ;
rdfs:label "toggled" ;
rdfs:comment "Control port value is considered a boolean toggle." .
lv2:sampleRate
a lv2:PortProperty ;
rdfs:label "sample rate" ;
rdfs:comment "Control port bounds are interpreted as multiples of the sample rate." .
lv2:integer
a lv2:PortProperty ;
rdfs:label "integer" ;
rdfs:comment "Control port values are treated as integers." .
lv2:enumeration
a lv2:PortProperty ;
rdfs:label "enumeration" ;
rdfs:comment "Control port scale points represent all useful values." .
lv2:isSideChain
a lv2:PortProperty ;
rdfs:label "is side-chain" ;
rdfs:comment "Signal for port should not be considered a main input or output." .
lv2:GeneratorPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Generator Plugin" ;
rdfs:comment "A plugin that generates new sound internally." .
lv2:InstrumentPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:GeneratorPlugin ;
rdfs:label "Instrument Plugin" ;
rdfs:comment "A plugin intended to be played as a musical instrument." .
lv2:OscillatorPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:GeneratorPlugin ;
rdfs:label "Oscillator Plugin" ;
rdfs:comment "A plugin that generates output with an oscillator." .
lv2:UtilityPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Utility Plugin" ;
rdfs:comment "A utility plugin that is not a typical audio effect or generator." .
lv2:ConverterPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:UtilityPlugin ;
rdfs:label "Converter Plugin" ;
rdfs:comment "A plugin that converts its input into a different form." .
lv2:AnalyserPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:UtilityPlugin ;
rdfs:label "Analyser Plugin" ;
rdfs:comment "A plugin that analyses its input and emits some useful information." .
lv2:MixerPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:UtilityPlugin ;
rdfs:label "Mixer Plugin" ;
rdfs:comment "A plugin that mixes some number of inputs into some number of outputs." .
lv2:SimulatorPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Simulator Plugin" ;
rdfs:comment "A plugin that aims to emulate some environmental effect or musical equipment." .
lv2:DelayPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Delay Plugin" ;
rdfs:comment "An effect that intentionally delays its input as an effect." .
lv2:ModulatorPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Modulator Plugin" ;
rdfs:comment "An effect that modulats its input as an effect." .
lv2:ReverbPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ,
lv2:SimulatorPlugin ,
lv2:DelayPlugin ;
rdfs:label "Reverb Plugin" ;
rdfs:comment "An effect that adds reverberation to its input." .
lv2:PhaserPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:ModulatorPlugin ;
rdfs:label "Phaser Plugin" ;
rdfs:comment "An effect that periodically sweeps a filter over its input." .
lv2:FlangerPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:ModulatorPlugin ;
rdfs:label "Flanger Plugin" ;
rdfs:comment "An effect that mixes slightly delayed copies of its input." .
lv2:ChorusPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:ModulatorPlugin ;
rdfs:label "Chorus Plugin" ;
rdfs:comment "An effect that mixes significantly delayed copies of its input." .
lv2:FilterPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Filter Plugin" ;
rdfs:comment "An effect that manipulates the frequency spectrum of its input." .
lv2:LowpassPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:FilterPlugin ;
rdfs:label "Lowpass Filter Plugin" ;
rdfs:comment "A filter that attenuates frequencies above some cutoff." .
lv2:BandpassPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:FilterPlugin ;
rdfs:label "Bandpass Filter Plugin" ;
rdfs:comment "A filter that attenuates frequencies outside of some band." .
lv2:HighpassPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:FilterPlugin ;
rdfs:label "Highpass Filter Plugin" ;
rdfs:comment "A filter that attenuates frequencies below some cutoff." .
lv2:CombPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:FilterPlugin ;
rdfs:label "Comb FilterPlugin" ;
rdfs:comment "A filter that adds a delayed version of its input to itself." .
lv2:AllpassPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:FilterPlugin ;
rdfs:label "Allpass Plugin" ;
rdfs:comment "A filter that changes the phase relationship between frequency components." .
lv2:EQPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:FilterPlugin ;
rdfs:label "Equaliser Plugin" ;
rdfs:comment "A plugin that adjusts the balance between frequency components." .
lv2:ParaEQPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:EQPlugin ;
rdfs:label "Parametric EQ Plugin" ;
rdfs:comment "A plugin that adjusts the balance between configurable frequency components." .
lv2:MultiEQPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:EQPlugin ;
rdfs:label "Multiband EQ Plugin" ;
rdfs:comment "A plugin that adjusts the balance between a fixed set of frequency components." .
lv2:SpatialPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Spatial Plugin" ;
rdfs:comment "A plugin that manipulates the position of audio in space." .
lv2:SpectralPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Spectral Plugin" ;
rdfs:comment "A plugin that alters the spectral properties of audio." .
lv2:PitchPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:SpectralPlugin ;
rdfs:label "Pitch Shifter Plugin" ;
rdfs:comment "A plugin that shifts the pitch of its input." .
lv2:AmplifierPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:DynamicsPlugin ;
rdfs:label "Amplifier Plugin" ;
rdfs:comment "A plugin that primarily changes the volume of its input." .
lv2:EnvelopePlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:DynamicsPlugin ;
rdfs:label "Envelope Plugin" ;
rdfs:comment "A plugin that applies an envelope to its input." .
lv2:DistortionPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Distortion Plugin" ;
rdfs:comment "A plugin that adds distortion to its input." .
lv2:WaveshaperPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:DistortionPlugin ;
rdfs:label "Waveshaper Plugin" ;
rdfs:comment "An effect that alters the shape of input waveforms." .
lv2:DynamicsPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "Dynamics Plugin" ;
rdfs:comment "A plugin that alters the envelope or dynamic range of its input." .
lv2:CompressorPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:DynamicsPlugin ;
rdfs:label "Compressor Plugin" ;
rdfs:comment "A plugin that reduces the dynamic range of its input." .
lv2:ExpanderPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:DynamicsPlugin ;
rdfs:label "Expander Plugin" ;
rdfs:comment "A plugin that expands the dynamic range of its input." .
lv2:LimiterPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:DynamicsPlugin ;
rdfs:label "Limiter Plugin" ;
rdfs:comment "A plugin that limits its input to some maximum level." .
lv2:GatePlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:DynamicsPlugin ;
rdfs:label "Gate Plugin" ;
rdfs:comment "A plugin that attenuates signals below some threshold." .
lv2:FunctionPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:UtilityPlugin ;
rdfs:label "Function Plugin" ;
rdfs:comment "A plugin whose output is a mathmatical function of its input." .
lv2:ConstantPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:GeneratorPlugin ;
rdfs:label "Constant Plugin" ;
rdfs:comment "A plugin that emits constant values." .
lv2:MIDIPlugin
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Plugin ;
rdfs:label "MIDI Plugin" ;
rdfs:comment "A plugin that primarily processes MIDI messages." .

View File

@@ -0,0 +1,15 @@
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/lv2core>
a lv2:Specification ;
lv2:minorVersion 18 ;
lv2:microVersion 0 ;
rdfs:seeAlso <lv2core.ttl> .
<http://lv2plug.in/ns/lv2>
a doap:Project ;
rdfs:seeAlso <meta.ttl> ,
<people.ttl> .

View File

@@ -0,0 +1,199 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix meta: <http://lv2plug.in/ns/meta#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://opensource.org/licenses/isc>
rdf:value """
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
""" .
<http://lv2plug.in/ns/lv2>
a doap:Project ;
lv2:symbol "lv2" ;
rdfs:label "LV2" ;
rdfs:comment "The LV2 Plugin Interface Project." ;
doap:name "LV2" ;
doap:license <http://opensource.org/licenses/isc> ;
doap:shortdesc "The LV2 Plugin Interface Project." ;
doap:description "LV2 is a plugin standard for audio systems. It defines a minimal yet extensible C API for plugin code and a format for plugin bundles" ;
doap:created "2006-05-10" ;
doap:homepage <http://lv2plug.in/> ;
doap:mailing-list <http://lists.lv2plug.in/listinfo.cgi/devel-lv2plug.in> ;
doap:programming-language "C" ;
doap:repository [
a doap:SVNRepository ;
doap:location <http://lv2plug.in/repo>
] ;
doap:developer <http://drobilla.net/drobilla#me> ,
<http://plugin.org.uk/swh.xrdf#me> ;
doap:helper meta:larsl ,
meta:bmwiedemann ,
meta:gabrbedd ,
meta:daste ,
meta:kfoltman ,
meta:paniq ;
doap:release [
doap:revision "1.18.2" ;
doap:created "2021-01-07" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.18.2.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "eg-sampler: Save and restore gain parameter value."
] , [
rdfs:label "Various code cleanups and infrastructure improvements."
]
]
] , [
doap:revision "1.18.0" ;
doap:created "2020-04-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.18.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Improve documentation."
] , [
rdfs:label "Separate extended documentation from primary data."
]
]
] , [
doap:revision "1.16.0" ;
doap:created "2019-02-03" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add core/attributes.h utility header."
] , [
rdfs:label "eg-sampler: Add waveform display to UI."
] , [
rdfs:label "eg-midigate: Respond to \"all notes off\" MIDI message."
] , [
rdfs:label "Simplify use of lv2specgen."
] , [
rdfs:label "Add lv2_validate utility."
] , [
rdfs:label "Install headers to simpler paths."
] , [
rdfs:label "Aggressively deprecate uri-map and event extensions."
] , [
rdfs:label "Upgrade build system and fix building with Python 3.7."
]
]
] , [
doap:revision "1.14.0" ;
doap:created "2016-09-19" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.14.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label """eg-scope: Don't feed back UI state updates."""
] , [
rdfs:label "eg-sampler: Fix handling of state file paths."
] , [
rdfs:label "eg-sampler: Support thread-safe state restoration."
]
]
] , [
doap:revision "1.12.0" ;
doap:created "2015-04-07" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.12.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "eg-sampler: Support patch:Get, and request initial state from UI."
] , [
rdfs:label "eg-sampler: Add gain parameter."
] , [
rdfs:label "Fix merging of version histories in specification documentation."
] , [
rdfs:label "Improve API documentation."
] , [
rdfs:label "Simplify property restrictions by removing redundancy."
]
]
] , [
doap:revision "1.10.0" ;
doap:created "2014-08-08" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "lv2specgen: Display deprecated warning on classes marked owl:deprecated."
] , [
rdfs:label "Fix -Wconversion warnings in headers."
] , [
rdfs:label "Upgrade to waf 1.7.16."
]
]
] , [
doap:revision "1.8.0" ;
doap:created "2014-01-04" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.8.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add scope example plugin from Robin Gareus."
] , [
rdfs:label "lv2specgen: Fix links to externally defined terms."
] , [
rdfs:label "Install lv2specgen for use by other projects."
]
]
] , [
doap:revision "1.6.0" ;
doap:created "2013-08-09" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.6.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix port indices of metronome example."
] , [
rdfs:label "Fix lv2specgen usage from command line."
] , [
rdfs:label "Upgrade to waf 1.7.11."
]
]
] , [
doap:revision "1.4.0" ;
doap:created "2013-02-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add metronome example plugin to demonstrate sample accurate tempo sync."
] , [
rdfs:label "Generate book-style HTML documentation from example plugins."
]
]
] , [
doap:revision "1.2.0" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Move all project metadata for extensions (e.g. change log) to separate files to spare hosts from loading them during discovery."
] , [
rdfs:label "Use stricter datatype definitions conformant with the XSD and OWL specifications for better validation."
]
]
] , [
doap:revision "1.0.0" ;
doap:created "2012-04-16" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label """Initial release as a unified project. Projects can now simply depend on the pkg-config package 'lv2' for all official LV2 APIs."""
] , [
rdfs:label "New extensions: atom, log, parameters, patch, port-groups, port-props, resize-port, state, time, worker."
]
]
] .

View File

@@ -0,0 +1,51 @@
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix meta: <http://lv2plug.in/ns/meta#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://drobilla.net/drobilla#me>
a foaf:Person ;
foaf:name "David Robillard" ;
foaf:mbox <mailto:d@drobilla.net> ;
rdfs:seeAlso <http://drobilla.net/drobilla> .
<http://plugin.org.uk/swh.xrdf#me>
a foaf:Person ;
foaf:name "Steve Harris" ;
foaf:mbox <mailto:steve@plugin.org.uk> ;
rdfs:seeAlso <http://plugin.org.uk/swh.xrdf> .
meta:larsl
a foaf:Person ;
foaf:name "Lars Luthman" ;
foaf:mbox <mailto:lars.luthman@gmail.com> .
meta:gabrbedd
a foaf:Person ;
foaf:name "Gabriel M. Beddingfield" ;
foaf:mbox <mailto:gabrbedd@gmail.com> .
meta:daste
a foaf:Person ;
foaf:name """Stefano D'Angelo""" ;
foaf:mbox <mailto:zanga.mail@gmail.com> .
meta:kfoltman
a foaf:Person ;
foaf:name "Krzysztof Foltman" ;
foaf:mbox <mailto:wdev@foltman.com> .
meta:paniq
a foaf:Person ;
foaf:name "Leonard Ritter" ;
foaf:mbox <mailto:paniq@paniq.org> .
meta:harry
a foaf:Person ;
foaf:name "Harry van Haaren" ;
foaf:mbox <harryhaaren@gmail.com> .
meta:bmwiedemann
a foaf:Person ;
foaf:name "Bernhard M. Wiedemann" ;
foaf:mbox <bwiedemann@suse.de> .

View File

@@ -0,0 +1,73 @@
/*
Copyright 2008-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_DATA_ACCESS_H
#define LV2_DATA_ACCESS_H
/**
@defgroup data-access Data Access
@ingroup lv2
Access to plugin extension_data() for UIs.
See <http://lv2plug.in/ns/ext/data-access> for details.
@{
*/
// clang-format off
#define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access" ///< http://lv2plug.in/ns/ext/data-access
#define LV2_DATA_ACCESS_PREFIX LV2_DATA_ACCESS_URI "#" ///< http://lv2plug.in/ns/ext/data-access#
// clang-format on
#ifdef __cplusplus
extern "C" {
#endif
/**
The data field of the LV2_Feature for this extension.
To support this feature the host must pass an LV2_Feature struct to the
instantiate method with URI "http://lv2plug.in/ns/ext/data-access"
and data pointed to an instance of this struct.
*/
typedef struct {
/**
A pointer to a method the UI can call to get data (of a type specified
by some other extension) from the plugin.
This call never is never guaranteed to return anything, UIs should
degrade gracefully if direct access to the plugin data is not possible
(in which case this function will return NULL).
This is for access to large data that can only possibly work if the UI
and plugin are running in the same process. For all other things, use
the normal LV2 UI communication system.
*/
const void* (*data_access)(const char* uri);
} LV2_Extension_Data_Feature;
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
*/
#endif /* LV2_DATA_ACCESS_H */

View File

@@ -0,0 +1,77 @@
@prefix da: <http://lv2plug.in/ns/ext/data-access#> .
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/data-access>
a doap:Project ;
rdfs:seeAlso <data-access.h> ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2 Data Access" ;
doap:shortdesc "Provides access to plugin extension data." ;
doap:created "2008-00-00" ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "1.6" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Merge with unified LV2 package."
]
]
] , [
doap:revision "1.4" ;
doap:created "2011-11-21" ;
doap:file-release <http://lv2plug.in/spec/lv2-data-access-1.4.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Update packaging."
] , [
rdfs:label "Improve documentation."
]
]
] , [
doap:revision "1.2" ;
doap:created "2011-05-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-data-access-1.2.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add build system for installation."
] , [
rdfs:label "Switch to ISC license."
]
]
] , [
doap:revision "1.0" ;
doap:created "2010-10-04" ;
doap:file-release <http://lv2plug.in/spec/lv2-data-access-1.0.tar.gz> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This extension defines a feature, LV2_Extension_Data_Feature, which provides
access to LV2_Descriptor::extension_data() for plugin UIs or other potentially
remote users of a plugin.
Note that the use of this extension by UIs violates the important principle of
UI/plugin separation, and is potentially a source of many problems.
Accordingly, **use of this extension is highly discouraged**, and plugins
should not expect hosts to support it, since it is often impossible to do so.
To support this feature the host must pass an LV2_Feature struct to
LV2_Descriptor::extension_data() with URI LV2_DATA_ACCESS_URI and data pointed
to an instance of LV2_Extension_Data_Feature.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,11 @@
@prefix da: <http://lv2plug.in/ns/ext/data-access#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/data-access>
a lv2:Feature ;
rdfs:label "data access" ;
rdfs:comment "A feature that provides access to plugin extension data." ;
rdfs:seeAlso <data-access.h> ,
<data-access.meta.ttl> .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/data-access>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 6 ;
rdfs:seeAlso <data-access.ttl> .

View File

@@ -0,0 +1,160 @@
/*
Dynamic manifest specification for LV2
Copyright 2008-2011 Stefano D'Angelo <zanga.mail@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_DYN_MANIFEST_H_INCLUDED
#define LV2_DYN_MANIFEST_H_INCLUDED
/**
@defgroup dynmanifest Dynamic Manifest
@ingroup lv2
Support for dynamic data generation.
See <http://lv2plug.in/ns/ext/dynmanifest> for details.
@{
*/
#include "lv2/core/lv2.h"
#include <stdio.h>
// clang-format off
#define LV2_DYN_MANIFEST_URI "http://lv2plug.in/ns/ext/dynmanifest" ///< http://lv2plug.in/ns/ext/dynmanifest
#define LV2_DYN_MANIFEST_PREFIX LV2_DYN_MANIFEST_URI "#" ///< http://lv2plug.in/ns/ext/dynmanifest#
// clang-format on
#ifdef __cplusplus
extern "C" {
#endif
/**
Dynamic manifest generator handle.
This handle indicates a particular status of a dynamic manifest generator.
The host MUST NOT attempt to interpret it and, unlikely LV2_Handle, it is
NOT even valid to compare this to NULL. The dynamic manifest generator MAY
use it to reference internal data.
*/
typedef void* LV2_Dyn_Manifest_Handle;
/**
Generate the dynamic manifest.
@param handle Pointer to an uninitialized dynamic manifest generator handle.
@param features NULL terminated array of LV2_Feature structs which represent
the features the host supports. The dynamic manifest generator may refuse to
(re)generate the dynamic manifest if required features are not found here
(however hosts SHOULD NOT use this as a discovery mechanism, instead of
reading the static manifest file). This array must always exist; if a host
has no features, it MUST pass a single element array containing NULL.
@return 0 on success, otherwise a non-zero error code. The host SHOULD
evaluate the result of the operation by examining the returned value and
MUST NOT try to interpret the value of handle.
*/
int
lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle* handle,
const LV2_Feature* const* features);
/**
Fetch a "list" of subject URIs described in the dynamic manifest.
The dynamic manifest generator has to fill the resource only with the needed
triples to make the host aware of the "objects" it wants to expose. For
example, if the plugin library exposes a regular LV2 plugin, it should
output only a triple like the following:
<http://example.org/plugin> a lv2:Plugin .
The objects that are elegible for exposure are those that would need to be
represented by a subject node in a static manifest.
@param handle Dynamic manifest generator handle.
@param fp FILE * identifying the resource the host has to set up for the
dynamic manifest generator. The host MUST pass a writable, empty resource to
this function, and the dynamic manifest generator MUST ONLY perform write
operations on it at the end of the stream (for example, using only
fprintf(), fwrite() and similar).
@return 0 on success, otherwise a non-zero error code.
*/
int
lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle, FILE* fp);
/**
Function that fetches data related to a specific URI.
The dynamic manifest generator has to fill the resource with data related to
object represented by the given URI. For example, if the library exposes a
regular LV2 plugin whose URI, as retrieved by the host using
lv2_dyn_manifest_get_subjects() is http://example.org/plugin then it
should output something like:
<pre>
<http://example.org/plugin>
a lv2:Plugin ;
doap:name "My Plugin" ;
lv2:binary <mylib.so> ;
etc:etc "..." .
</pre>
@param handle Dynamic manifest generator handle.
@param fp FILE * identifying the resource the host has to set up for the
dynamic manifest generator. The host MUST pass a writable resource to this
function, and the dynamic manifest generator MUST ONLY perform write
operations on it at the current position of the stream (for example, using
only fprintf(), fwrite() and similar).
@param uri URI to get data about (in the "plain" form, i.e., absolute URI
without Turtle prefixes).
@return 0 on success, otherwise a non-zero error code.
*/
int
lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,
FILE* fp,
const char* uri);
/**
Function that ends the operations on the dynamic manifest generator.
This function SHOULD be used by the dynamic manifest generator to perform
cleanup operations, etc.
Once this function is called, referring to handle will cause undefined
behavior.
@param handle Dynamic manifest generator handle.
*/
void
lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle);
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
*/
#endif /* LV2_DYN_MANIFEST_H_INCLUDED */

View File

@@ -0,0 +1,131 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix dman: <http://lv2plug.in/ns/ext/dynmanifest#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/dynmanifest>
a doap:Project ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2 Dynamic Manifest" ;
doap:homepage <http://naspro.atheme.org> ;
doap:created "2009-06-13" ;
doap:shortdesc "Support for dynamic manifest data generation." ;
doap:programming-language "C" ;
doap:developer <http://lv2plug.in/ns/meta#daste> ;
doap:release [
doap:revision "1.6" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Use consistent label style."
]
]
] , [
doap:revision "1.4" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Merge with unified LV2 package."
]
]
] , [
doap:revision "1.2" ;
doap:created "2011-11-21" ;
doap:file-release <http://lv2plug.in/spec/lv2-dynmanifest-1.2.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Improve documentation."
]
]
] , [
doap:revision "1.0" ;
doap:created "2010-04-10" ;
doap:file-release <http://lv2plug.in/spec/lv2-dyn-manifest-1.0.tar.gz> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
The LV2 API, on its own, cannot be used to write plugin libraries where data is
dynamically generated at runtime, since LV2 requires needed information to be
provided in one or more static data (RDF) files. This API addresses this
limitation by extending the LV2 API.
To detect that a plugin library implements a dynamic manifest generator, the
host checks its static manifest for a description like:
:::turtle
<http://example.org/my-dynamic-manifest>
a dman:DynManifest ;
lv2:binary <mydynmanifest.so> .
To load the data, the host loads the library (`mydynmanifest.so` in this
example) as usual and fetches the dynamic Turtle data from it using this API.
The host is allowed to request regeneration of the dynamic manifest multiple
times, and the plugin library is expected to provide updated data if/when
possible. All data and references provided via this API before the last
regeneration of the dynamic manifest is to be considered invalid by the host,
including plugin descriptors whose URIs were discovered using this API.
### Accessing Data
To access data using this API, the host must:
1. Call lv2_dyn_manifest_open().
2. Create a `FILE` for functions to write data to (for example with `tmpfile()`).
3. Get a list of exposed subject URIs using lv2_dyn_manifest_get_subjects().
4. Call lv2_dyn_manifest_get_data() for each URI of interest to write the
related data to the file.
5. Call lv2_dyn_manifest_close().
6. Parse the content of the file(s).
7. Remove the file(s).
Each call to the above mentioned dynamic manifest functions MUST write a
complete, valid Turtle document (including all needed prefix definitions) to
the output FILE.
Each call to lv2_dyn_manifest_open() causes the (re)generation of the dynamic
manifest data, and invalidates all data fetched before the call.
In case the plugin library uses this same API to access other dynamic
manifests, it MUST implement some mechanism to avoid potentially endless loops
(such as A loads B, B loads A, etc.) and, in case such a loop is detected, the
operation MUST fail. For this purpose, use of a static boolean flag is
suggested.
### Threading Rules
All of the functions defined by this specification belong to the Discovery
class.
"""^^lv2:Markdown .
dman:DynManifest
lv2:documentation """
There MUST NOT be any instances of dman:DynManifest in the generated manifest.
All relative URIs in the generated data MUST be relative to the base path that
would be used to parse a normal LV2 manifest (the bundle path).
"""^^lv2:Markdown .

View File

@@ -0,0 +1,25 @@
@prefix dman: <http://lv2plug.in/ns/ext/dynmanifest#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/dynmanifest>
a owl:Ontology ;
rdfs:label "LV2 Dyn Manifest" ;
rdfs:comment "Support for dynamic manifest data generation." ;
rdfs:seeAlso <dynmanifest.h> ,
<dynmanifest.meta.ttl> .
dman:DynManifest
a rdfs:Class ;
rdfs:label "Dynamic Manifest" ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty lv2:binary ;
owl:minCardinality 1 ;
rdfs:comment "A DynManifest MUST have at least one lv2:binary."
] ;
rdfs:comment "Dynamic manifest for an LV2 binary." .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/dynmanifest>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 6 ;
rdfs:seeAlso <dynmanifest.ttl> .

View File

@@ -0,0 +1,255 @@
/*
Copyright 2008-2015 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_EVENT_HELPERS_H
#define LV2_EVENT_HELPERS_H
/**
@file event-helpers.h Helper functions for the LV2 Event extension
<http://lv2plug.in/ns/ext/event>.
*/
#include "lv2/core/attributes.h"
#include "lv2/event/event.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
LV2_DISABLE_DEPRECATION_WARNINGS
/** @file
* Helper functions for the LV2 Event extension
* <http://lv2plug.in/ns/ext/event>.
*
* These functions are provided for convenience only, use of them is not
* required for supporting lv2ev (i.e. the events extension is defined by the
* raw buffer format described in lv2_event.h and NOT by this API).
*
* Note that these functions are all static inline which basically means:
* do not take the address of these functions. */
/** Pad a size to 64 bits (for event sizes) */
static inline uint16_t
lv2_event_pad_size(uint16_t size)
{
return (uint16_t)(size + 7U) & (uint16_t)(~7U);
}
/** Initialize (empty, reset..) an existing event buffer.
* The contents of buf are ignored entirely and overwritten, except capacity
* which is unmodified. */
static inline void
lv2_event_buffer_reset(LV2_Event_Buffer* buf,
uint16_t stamp_type,
uint8_t* data)
{
buf->data = data;
buf->header_size = sizeof(LV2_Event_Buffer);
buf->stamp_type = stamp_type;
buf->event_count = 0;
buf->size = 0;
}
/** Allocate a new, empty event buffer. */
static inline LV2_Event_Buffer*
lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type)
{
const size_t size = sizeof(LV2_Event_Buffer) + capacity;
LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(size);
if (buf != NULL) {
buf->capacity = capacity;
lv2_event_buffer_reset(buf, stamp_type, (uint8_t*)(buf + 1));
return buf;
}
return NULL;
}
/** An iterator over an LV2_Event_Buffer.
*
* Multiple simultaneous read iterators over a single buffer is fine,
* but changing the buffer invalidates all iterators. */
typedef struct {
LV2_Event_Buffer* buf;
uint32_t offset;
} LV2_Event_Iterator;
/** Reset an iterator to point to the start of `buf`.
* @return True if `iter` is valid, otherwise false (buffer is empty) */
static inline bool
lv2_event_begin(LV2_Event_Iterator* iter, LV2_Event_Buffer* buf)
{
iter->buf = buf;
iter->offset = 0;
return (buf->size > 0);
}
/** Check if `iter` is valid.
* @return True if `iter` is valid, otherwise false (past end of buffer) */
static inline bool
lv2_event_is_valid(LV2_Event_Iterator* iter)
{
return (iter->buf && (iter->offset < iter->buf->size));
}
/** Advance `iter` forward one event.
* `iter` must be valid.
* @return True if `iter` is valid, otherwise false (reached end of buffer) */
static inline bool
lv2_event_increment(LV2_Event_Iterator* iter)
{
if (!lv2_event_is_valid(iter)) {
return false;
}
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
iter->offset +=
lv2_event_pad_size((uint16_t)((uint16_t)sizeof(LV2_Event) + ev->size));
return true;
}
/** Dereference an event iterator (get the event currently pointed at).
* `iter` must be valid.
* `data` if non-NULL, will be set to point to the contents of the event
* returned.
* @return A Pointer to the event `iter` is currently pointing at, or NULL
* if the end of the buffer is reached (in which case `data` is
* also set to NULL). */
static inline LV2_Event*
lv2_event_get(LV2_Event_Iterator* iter, uint8_t** data)
{
if (!lv2_event_is_valid(iter)) {
return NULL;
}
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
if (data) {
*data = (uint8_t*)ev + sizeof(LV2_Event);
}
return ev;
}
/** Write an event at `iter`.
* The event (if any) pointed to by `iter` will be overwritten, and `iter`
* incremented to point to the following event (i.e. several calls to this
* function can be done in sequence without twiddling iter in-between).
* @return True if event was written, otherwise false (buffer is full). */
static inline bool
lv2_event_write(LV2_Event_Iterator* iter,
uint32_t frames,
uint32_t subframes,
uint16_t type,
uint16_t size,
const uint8_t* data)
{
if (!iter->buf) {
return false;
}
if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) {
return false;
}
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
ev->frames = frames;
ev->subframes = subframes;
ev->type = type;
ev->size = size;
memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
++iter->buf->event_count;
size = lv2_event_pad_size((uint16_t)(sizeof(LV2_Event) + size));
iter->buf->size += size;
iter->offset += size;
return true;
}
/** Reserve space for an event in the buffer and return a pointer to
the memory where the caller can write the event data, or NULL if there
is not enough room in the buffer. */
static inline uint8_t*
lv2_event_reserve(LV2_Event_Iterator* iter,
uint32_t frames,
uint32_t subframes,
uint16_t type,
uint16_t size)
{
const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + size);
if (iter->buf->capacity - iter->buf->size < total_size) {
return NULL;
}
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
ev->frames = frames;
ev->subframes = subframes;
ev->type = type;
ev->size = size;
++iter->buf->event_count;
const uint16_t padded_size = lv2_event_pad_size(total_size);
iter->buf->size += padded_size;
iter->offset += padded_size;
return (uint8_t*)ev + sizeof(LV2_Event);
}
/** Write an event at `iter`.
* The event (if any) pointed to by `iter` will be overwritten, and `iter`
* incremented to point to the following event (i.e. several calls to this
* function can be done in sequence without twiddling iter in-between).
* @return True if event was written, otherwise false (buffer is full). */
static inline bool
lv2_event_write_event(LV2_Event_Iterator* iter,
const LV2_Event* ev,
const uint8_t* data)
{
const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + ev->size);
if (iter->buf->capacity - iter->buf->size < total_size) {
return false;
}
LV2_Event* const write_ev = (LV2_Event*)(iter->buf->data + iter->offset);
*write_ev = *ev;
memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size);
++iter->buf->event_count;
const uint16_t padded_size = lv2_event_pad_size(total_size);
iter->buf->size += padded_size;
iter->offset += padded_size;
return true;
}
LV2_RESTORE_WARNINGS
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV2_EVENT_HELPERS_H */

View File

@@ -0,0 +1,306 @@
/*
Copyright 2008-2016 David Robillard <d@drobilla.net>
Copyright 2006-2007 Lars Luthman <lars.luthman@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_EVENT_H
#define LV2_EVENT_H
/**
@defgroup event Event
@ingroup lv2
Generic time-stamped events.
See <http://lv2plug.in/ns/ext/event> for details.
@{
*/
// clang-format off
#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event" ///< http://lv2plug.in/ns/ext/event
#define LV2_EVENT_PREFIX LV2_EVENT_URI "#" ///< http://lv2plug.in/ns/ext/event#
#define LV2_EVENT__Event LV2_EVENT_PREFIX "Event" ///< http://lv2plug.in/ns/ext/event#Event
#define LV2_EVENT__EventPort LV2_EVENT_PREFIX "EventPort" ///< http://lv2plug.in/ns/ext/event#EventPort
#define LV2_EVENT__FrameStamp LV2_EVENT_PREFIX "FrameStamp" ///< http://lv2plug.in/ns/ext/event#FrameStamp
#define LV2_EVENT__TimeStamp LV2_EVENT_PREFIX "TimeStamp" ///< http://lv2plug.in/ns/ext/event#TimeStamp
#define LV2_EVENT__generatesTimeStamp LV2_EVENT_PREFIX "generatesTimeStamp" ///< http://lv2plug.in/ns/ext/event#generatesTimeStamp
#define LV2_EVENT__generic LV2_EVENT_PREFIX "generic" ///< http://lv2plug.in/ns/ext/event#generic
#define LV2_EVENT__inheritsEvent LV2_EVENT_PREFIX "inheritsEvent" ///< http://lv2plug.in/ns/ext/event#inheritsEvent
#define LV2_EVENT__inheritsTimeStamp LV2_EVENT_PREFIX "inheritsTimeStamp" ///< http://lv2plug.in/ns/ext/event#inheritsTimeStamp
#define LV2_EVENT__supportsEvent LV2_EVENT_PREFIX "supportsEvent" ///< http://lv2plug.in/ns/ext/event#supportsEvent
#define LV2_EVENT__supportsTimeStamp LV2_EVENT_PREFIX "supportsTimeStamp" ///< http://lv2plug.in/ns/ext/event#supportsTimeStamp
// clang-format on
#define LV2_EVENT_AUDIO_STAMP 0 ///< Special timestamp type for audio frames
#include "lv2/core/attributes.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
LV2_DISABLE_DEPRECATION_WARNINGS
/**
The best Pulses Per Quarter Note for tempo-based uint32_t timestamps.
Equal to 2^12 * 5 * 7 * 9 * 11 * 13 * 17, which is evenly divisble
by all integers from 1 through 18 inclusive, and powers of 2 up to 2^12.
*/
LV2_DEPRECATED
static const uint32_t LV2_EVENT_PPQN = 3136573440U;
/**
An LV2 event (header only).
LV2 events are generic time-stamped containers for any type of event.
The type field defines the format of a given event's contents.
This struct defines the header of an LV2 event. An LV2 event is a single
chunk of POD (plain old data), usually contained in a flat buffer (see
LV2_EventBuffer below). Unless a required feature says otherwise, hosts may
assume a deep copy of an LV2 event can be created safely using a simple:
memcpy(ev_copy, ev, sizeof(LV2_Event) + ev->size); (or equivalent)
*/
LV2_DEPRECATED
typedef struct {
/**
The frames portion of timestamp. The units used here can optionally be
set for a port (with the lv2ev:timeUnits property), otherwise this is
audio frames, corresponding to the sample_count parameter of the LV2 run
method (frame 0 is the first frame for that call to run).
*/
uint32_t frames;
/**
The sub-frames portion of timestamp. The units used here can optionally
be set for a port (with the lv2ev:timeUnits property), otherwise this is
1/(2^32) of an audio frame.
*/
uint32_t subframes;
/**
The type of this event, as a number which represents some URI
defining an event type. This value MUST be some value previously
returned from a call to the uri_to_id function defined in the LV2
URI map extension (see lv2_uri_map.h).
There are special rules which must be followed depending on the type
of an event. If the plugin recognizes an event type, the definition
of that event type will describe how to interpret the event, and
any required behaviour. Otherwise, if the type is 0, this event is a
non-POD event and lv2_event_unref MUST be called if the event is
'dropped' (see above). Even if the plugin does not understand an event,
it may pass the event through to an output by simply copying (and NOT
calling lv2_event_unref). These rules are designed to allow for generic
event handling plugins and large non-POD events, but with minimal hassle
on simple plugins that "don't care" about these more advanced features.
*/
uint16_t type;
/**
The size of the data portion of this event in bytes, which immediately
follows. The header size (12 bytes) is not included in this value.
*/
uint16_t size;
/* size bytes of data follow here */
} LV2_Event;
/**
A buffer of LV2 events (header only).
Like events (which this contains) an event buffer is a single chunk of POD:
the entire buffer (including contents) can be copied with a single memcpy.
The first contained event begins sizeof(LV2_EventBuffer) bytes after the
start of this struct.
After this header, the buffer contains an event header (defined by struct
LV2_Event), followed by that event's contents (padded to 64 bits), followed
by another header, etc:
| | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | |
|FRAMES |SUBFRMS|TYP|LEN|DATA..DATA..PAD|FRAMES | ...
*/
LV2_DEPRECATED
typedef struct {
/**
The contents of the event buffer. This may or may not reside in the
same block of memory as this header, plugins must not assume either.
The host guarantees this points to at least capacity bytes of allocated
memory (though only size bytes of that are valid events).
*/
uint8_t* data;
/**
The size of this event header in bytes (including everything).
This is to allow for extending this header in the future without
breaking binary compatibility. Whenever this header is copied,
it MUST be done using this field (and NOT the sizeof this struct).
*/
uint16_t header_size;
/**
The type of the time stamps for events in this buffer.
As a special exception, '0' always means audio frames and subframes
(1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate.
INPUTS: The host must set this field to the numeric ID of some URI
defining the meaning of the frames/subframes fields of contained events
(obtained by the LV2 URI Map uri_to_id function with the URI of this
extension as the 'map' argument, see lv2_uri_map.h). The host must
never pass a plugin a buffer which uses a stamp type the plugin does not
'understand'. The value of this field must never change, except when
connect_port is called on the input port, at which time the host MUST
have set the stamp_type field to the value that will be used for all
subsequent run calls.
OUTPUTS: The plugin may set this to any value that has been returned
from uri_to_id with the URI of this extension for a 'map' argument.
When connected to a buffer with connect_port, output ports MUST set this
field to the type of time stamp they will be writing. On any call to
connect_port on an event input port, the plugin may change this field on
any output port, it is the responsibility of the host to check if any of
these values have changed and act accordingly.
*/
uint16_t stamp_type;
/**
The number of events in this buffer.
INPUTS: The host must set this field to the number of events contained
in the data buffer before calling run(). The plugin must not change
this field.
OUTPUTS: The plugin must set this field to the number of events it has
written to the buffer before returning from run(). Any initial value
should be ignored by the plugin.
*/
uint32_t event_count;
/**
The size of the data buffer in bytes.
This is set by the host and must not be changed by the plugin.
The host is allowed to change this between run() calls.
*/
uint32_t capacity;
/**
The size of the initial portion of the data buffer containing data.
INPUTS: The host must set this field to the number of bytes used
by all events it has written to the buffer (including headers)
before calling the plugin's run().
The plugin must not change this field.
OUTPUTS: The plugin must set this field to the number of bytes
used by all events it has written to the buffer (including headers)
before returning from run().
Any initial value should be ignored by the plugin.
*/
uint32_t size;
} LV2_Event_Buffer;
/**
Opaque pointer to host data.
*/
LV2_DEPRECATED
typedef void* LV2_Event_Callback_Data;
/**
Non-POD events feature.
To support this feature the host must pass an LV2_Feature struct to the
plugin's instantiate method with URI "http://lv2plug.in/ns/ext/event"
and data pointed to an instance of this struct. Note this feature
is not mandatory to support the event extension.
*/
LV2_DEPRECATED
typedef struct {
/**
Opaque pointer to host data.
The plugin MUST pass this to any call to functions in this struct.
Otherwise, it must not be interpreted in any way.
*/
LV2_Event_Callback_Data callback_data;
/**
Take a reference to a non-POD event.
If a plugin receives an event with type 0, it means the event is a
pointer to some object in memory and not a flat sequence of bytes
in the buffer. When receiving a non-POD event, the plugin already
has an implicit reference to the event. If the event is stored AND
passed to an output, lv2_event_ref MUST be called on that event.
If the event is only stored OR passed through, this is not necessary
(as the plugin already has 1 implicit reference).
@param event An event received at an input that will not be copied to
an output or stored in any way.
@param context The calling context. Like event types, this is a mapped
URI, see lv2_context.h. Simple plugin with just a run() method should
pass 0 here (the ID of the 'standard' LV2 run context). The host
guarantees that this function is realtime safe iff the context is
realtime safe.
PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
*/
uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data,
LV2_Event* event);
/**
Drop a reference to a non-POD event.
If a plugin receives an event with type 0, it means the event is a
pointer to some object in memory and not a flat sequence of bytes
in the buffer. If the plugin does not pass the event through to
an output or store it internally somehow, it MUST call this function
on the event (more information on using non-POD events below).
@param event An event received at an input that will not be copied to an
output or stored in any way.
@param context The calling context. Like event types, this is a mapped
URI, see lv2_context.h. Simple plugin with just a run() method should
pass 0 here (the ID of the 'standard' LV2 run context). The host
guarantees that this function is realtime safe iff the context is
realtime safe.
PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
*/
uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data,
LV2_Event* event);
} LV2_Event_Feature;
LV2_RESTORE_WARNINGS
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
*/
#endif /* LV2_EVENT_H */

View File

@@ -0,0 +1,246 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix ev: <http://lv2plug.in/ns/ext/event#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/event>
a doap:Project ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2 Event" ;
doap:shortdesc "A port-based real-time generic event interface." ;
doap:created "2008-00-00" ;
doap:developer <http://drobilla.net/drobilla#me> ,
<http://lv2plug.in/ns/meta#larsl> ;
doap:release [
doap:revision "1.12" ;
doap:created "2014-08-08" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Minor documentation improvements."
]
]
] , [
doap:revision "1.10" ;
doap:created "2013-01-13" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix incorrect return type in lv2_event_get()."
]
]
] , [
doap:revision "1.8" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Make event iterator gracefully handle optional ports."
] , [
rdfs:label "Remove asserts from event-helper.h."
] , [
rdfs:label "Use more precise domain and range for EventPort properties."
] , [
rdfs:label "Use consistent label style."
]
]
] , [
doap:revision "1.6" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix bug in lv2_event_reserve()."
] , [
rdfs:label "Fix incorrect ranges of some properties."
] , [
rdfs:label "Merge with unified LV2 package."
]
]
] , [
doap:revision "1.4" ;
doap:created "2011-11-21" ;
doap:file-release <http://lv2plug.in/spec/lv2-event-1.4.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Update packaging."
]
]
] , [
doap:revision "1.2" ;
doap:created "2011-05-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-event-1.2.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add build system (for installation)."
] , [
rdfs:label "Convert documentation to HTML and use lv2:documentation."
] , [
rdfs:label "Use lv2:Specification to be discovered as an extension."
]
]
] , [
doap:revision "1.0" ;
doap:created "2010-11-24" ;
doap:file-release <http://lv2plug.in/spec/lv2-event-1.0.tar.gz> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
<span class="warning">This extension is deprecated.</span> New implementations
should use <a href="atom.html">LV2 Atom</a> instead.
This extension defines a generic time-stamped event port type, which can be
used to create plugins that read and write real-time events, such as MIDI,
OSC, or any other type of event payload. The type(s) of event supported by
a port is defined in the data file for a plugin, for example:
:::turtle
<http://example.org/some-plugin>
lv2:port [
a ev:EventPort, lv2:InputPort ;
lv2:index 0 ;
ev:supportsEvent <http://lv2plug.in/ns/ext/midi#MidiEvent> ;
lv2:symbol "midi_input" ;
lv2:name "MIDI input" ;
] .
"""^^lv2:Markdown .
ev:EventPort
lv2:documentation """
Ports of this type will be connected to a struct of type LV2_Event_Buffer,
defined in event.h. These ports contain a sequence of generic events (possibly
several types mixed in a single stream), the specific types of which are
defined by some URI in another LV2 extension.
"""^^lv2:Markdown .
ev:Event
a rdfs:Class ;
rdfs:label "Event" ;
lv2:documentation """
An ev:EventPort contains an LV2_Event_Buffer which contains a sequence of these
events. The binary format of LV2 events is defined by the LV2_Event struct in
event.h.
Specific event types (such as MIDI or OSC) are defined by extensions, and
should be rdfs:subClassOf this class.
"""^^lv2:Markdown .
ev:TimeStamp
lv2:documentation """
This defines the meaning of the 'frames' and 'subframes' fields of an LV2_Event
(both unsigned 32-bit integers).
"""^^lv2:Markdown .
ev:FrameStamp
lv2:documentation """
The default time stamp unit for an LV2 event: the frames field represents audio
frames (in the sample rate passed to intantiate), and the subframes field is
1/UINT32_MAX of a frame.
"""^^lv2:Markdown .
ev:generic
lv2:documentation """
Indicates that this port does something meaningful for any event type. This is
useful for things like event mixers, delays, serialisers, and so on.
If this property is set, hosts should consider the port suitable for any type
of event. Otherwise, hosts should consider the port 'appropriate' only for the
specific event types listed with :supportsEvent. Note that plugins must
gracefully handle unknown event types whether or not this property is present.
"""^^lv2:Markdown .
ev:supportsEvent
lv2:documentation """
Indicates that this port supports or "understands" a certain event type.
For input ports, this means the plugin understands and does something useful
with events of this type. For output ports, this means the plugin may generate
events of this type. If the plugin never actually generates events of this
type, but might pass them through from an input, this property should not be
set (use ev:inheritsEvent for that).
Plugins with event input ports must always gracefully handle any type of event,
even if it does not 'support' it. This property should always be set for event
types the plugin understands/generates so hosts can discover plugins
appropriate for a given scenario (for example, plugins with a MIDI input).
Hosts are not expected to consider event ports suitable for some type of event
if the relevant :supportsEvent property is not set, unless the ev:generic
property for that port is also set.
"""^^lv2:Markdown .
ev:inheritsEvent
lv2:documentation """
Indicates that this output port might pass through events that arrived at some
other input port (or generate an event of the same type as events arriving at
that input). The host must always check the stamp type of all outputs when
connecting an input, but this property should be set whenever it applies.
"""^^lv2:Markdown .
ev:supportsTimeStamp
lv2:documentation """
Indicates that this port supports or "understands" a certain time stamp type.
Meaningful only for input ports, the host must never connect a port to an event
buffer with a time stamp type that isn't supported by the port.
"""^^lv2:Markdown .
ev:generatesTimeStamp
lv2:documentation """
Indicates that this port may output a certain time stamp type, regardless of
the time stamp type of any input ports.
If the port outputs stamps based on what type inputs are connected to, this
property should not be set (use the ev:inheritsTimeStamp property for that).
Hosts MUST check the time_stamp value of any output port buffers after a call
to connect_port on ANY event input port on the plugin.
If the plugin changes the stamp_type field of an output event buffer during a
call to run(), the plugin must call the stamp_type_changed function provided by
the host in the LV2_Event_Feature struct, if it is non-NULL.
"""^^lv2:Markdown .
ev:inheritsTimeStamp
lv2:documentation """
Indicates that this port follows the time stamp type of an input port.
This property is not necessary, but it should be set for outputs that base
their output type on an input port so the host can make more sense of the
plugin and provide a more sensible interface.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,86 @@
@prefix ev: <http://lv2plug.in/ns/ext/event#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/event>
a owl:Ontology ;
owl:deprecated true ;
rdfs:label "LV2 Event" ;
rdfs:comment "A port-based real-time generic event interface." ;
rdfs:seeAlso <event.h> ,
<event-helpers.h> ,
<event.meta.ttl> .
ev:EventPort
a rdfs:Class ;
rdfs:label "Event Port" ;
rdfs:subClassOf lv2:Port ;
rdfs:comment "An LV2 event port." .
ev:Event
a rdfs:Class ;
rdfs:label "Event" ;
rdfs:comment "A single generic time-stamped event." .
ev:TimeStamp
a rdfs:Class ;
rdfs:label "Event Time Stamp" ;
rdfs:comment "The time stamp of an Event." .
ev:FrameStamp
a rdfs:Class ;
rdfs:subClassOf ev:TimeStamp ;
rdfs:label "Audio Frame Time Stamp" ;
rdfs:comment "The default time stamp unit for an event." .
ev:generic
a lv2:PortProperty ;
rdfs:label "generic event port" ;
rdfs:comment "Port works with generic events." .
ev:supportsEvent
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain ev:EventPort ;
rdfs:range rdfs:Class ;
rdfs:label "supports event type" ;
rdfs:comment "An event type supported by this port." .
ev:inheritsEvent
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain ev:EventPort ,
lv2:OutputPort ;
rdfs:range lv2:Port ;
rdfs:label "inherits event type" ;
rdfs:comment "Output port inherits event types from an input port." .
ev:supportsTimeStamp
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain ev:EventPort ,
lv2:InputPort ;
rdfs:range rdfs:Class ;
rdfs:label "supports time stamp type" ;
rdfs:comment "A time stamp type suported by this input port." .
ev:generatesTimeStamp
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain ev:EventPort ,
lv2:OutputPort ;
rdfs:range rdfs:Class ;
rdfs:label "generates time stamp type" ;
rdfs:comment "A time stamp type generated by this input port." .
ev:inheritsTimeStamp
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain ev:EventPort ,
lv2:OutputPort ;
rdfs:range lv2:Port ;
rdfs:label "inherits time stamp type" ;
rdfs:comment "Output port inherits time stamp types from an input port." .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/event>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 12 ;
rdfs:seeAlso <event.ttl> .

View File

@@ -0,0 +1,41 @@
/*
Copyright 2008-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_INSTANCE_ACCESS_H
#define LV2_INSTANCE_ACCESS_H
/**
@defgroup instance-access Instance Access
@ingroup lv2
Access to the LV2_Handle of a plugin for UIs.
See <http://lv2plug.in/ns/ext/instance-access> for details.
@{
*/
// clang-format off
#define LV2_INSTANCE_ACCESS_URI "http://lv2plug.in/ns/ext/instance-access" ///< http://lv2plug.in/ns/ext/instance-access
// clang-format on
/**
@}
*/
#endif /* LV2_INSTANCE_ACCESS_H */

View File

@@ -0,0 +1,75 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ia: <http://lv2plug.in/ns/ext/instance-access#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/instance-access>
a doap:Project ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2 Instance Access" ;
doap:shortdesc "Provides access to the LV2_Handle of a plugin." ;
doap:created "2010-10-04" ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "1.6" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Merge with unified LV2 package."
]
]
] , [
doap:revision "1.4" ;
doap:created "2011-11-21" ;
doap:file-release <http://lv2plug.in/spec/lv2-instance-access-1.4.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Update packaging."
] , [
rdfs:label "Improve documentation."
]
]
] , [
doap:revision "1.2" ;
doap:created "2011-05-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-instance-access-1.2.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add build system for installation."
] , [
rdfs:label "Switch to ISC license."
]
]
] , [
doap:revision "1.0" ;
doap:created "2010-10-04" ;
doap:file-release <http://lv2plug.in/spec/lv2-instance-access-1.0.tar.gz> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This extension defines a feature which allows plugin UIs to get a direct handle
to an LV2 plugin instance (LV2_Handle), if possible.
Note that the use of this extension by UIs violates the important principle of
UI/plugin separation, and is potentially a source of many problems.
Accordingly, **use of this extension is highly discouraged**, and plugins
should not expect hosts to support it, since it is often impossible to do so.
To support this feature the host must pass an LV2_Feature struct to the UI
instantiate method with URI LV2_INSTANCE_ACCESS_URI and data pointed directly
to the LV2_Handle of the plugin instance.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,11 @@
@prefix ia: <http://lv2plug.in/ns/ext/instance-access#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/instance-access>
a lv2:Feature ;
rdfs:label "instance access" ;
rdfs:comment "A feature that provides access to a plugin instance." ;
rdfs:seeAlso <instance-access.h> ,
<instance-access.meta.ttl> .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/instance-access>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 6 ;
rdfs:seeAlso <instance-access.ttl> .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/midi>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 10 ;
rdfs:seeAlso <midi.ttl> .

View File

@@ -0,0 +1,248 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_MIDI_H
#define LV2_MIDI_H
/**
@defgroup midi MIDI
@ingroup lv2
Definitions of standard MIDI messages.
See <http://lv2plug.in/ns/ext/midi> for details.
@{
*/
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// clang-format off
#define LV2_MIDI_URI "http://lv2plug.in/ns/ext/midi" ///< http://lv2plug.in/ns/ext/midi
#define LV2_MIDI_PREFIX LV2_MIDI_URI "#" ///< http://lv2plug.in/ns/ext/midi#
#define LV2_MIDI__ActiveSense LV2_MIDI_PREFIX "ActiveSense" ///< http://lv2plug.in/ns/ext/midi#ActiveSense
#define LV2_MIDI__Aftertouch LV2_MIDI_PREFIX "Aftertouch" ///< http://lv2plug.in/ns/ext/midi#Aftertouch
#define LV2_MIDI__Bender LV2_MIDI_PREFIX "Bender" ///< http://lv2plug.in/ns/ext/midi#Bender
#define LV2_MIDI__ChannelPressure LV2_MIDI_PREFIX "ChannelPressure" ///< http://lv2plug.in/ns/ext/midi#ChannelPressure
#define LV2_MIDI__Chunk LV2_MIDI_PREFIX "Chunk" ///< http://lv2plug.in/ns/ext/midi#Chunk
#define LV2_MIDI__Clock LV2_MIDI_PREFIX "Clock" ///< http://lv2plug.in/ns/ext/midi#Clock
#define LV2_MIDI__Continue LV2_MIDI_PREFIX "Continue" ///< http://lv2plug.in/ns/ext/midi#Continue
#define LV2_MIDI__Controller LV2_MIDI_PREFIX "Controller" ///< http://lv2plug.in/ns/ext/midi#Controller
#define LV2_MIDI__MidiEvent LV2_MIDI_PREFIX "MidiEvent" ///< http://lv2plug.in/ns/ext/midi#MidiEvent
#define LV2_MIDI__NoteOff LV2_MIDI_PREFIX "NoteOff" ///< http://lv2plug.in/ns/ext/midi#NoteOff
#define LV2_MIDI__NoteOn LV2_MIDI_PREFIX "NoteOn" ///< http://lv2plug.in/ns/ext/midi#NoteOn
#define LV2_MIDI__ProgramChange LV2_MIDI_PREFIX "ProgramChange" ///< http://lv2plug.in/ns/ext/midi#ProgramChange
#define LV2_MIDI__QuarterFrame LV2_MIDI_PREFIX "QuarterFrame" ///< http://lv2plug.in/ns/ext/midi#QuarterFrame
#define LV2_MIDI__Reset LV2_MIDI_PREFIX "Reset" ///< http://lv2plug.in/ns/ext/midi#Reset
#define LV2_MIDI__SongPosition LV2_MIDI_PREFIX "SongPosition" ///< http://lv2plug.in/ns/ext/midi#SongPosition
#define LV2_MIDI__SongSelect LV2_MIDI_PREFIX "SongSelect" ///< http://lv2plug.in/ns/ext/midi#SongSelect
#define LV2_MIDI__Start LV2_MIDI_PREFIX "Start" ///< http://lv2plug.in/ns/ext/midi#Start
#define LV2_MIDI__Stop LV2_MIDI_PREFIX "Stop" ///< http://lv2plug.in/ns/ext/midi#Stop
#define LV2_MIDI__SystemCommon LV2_MIDI_PREFIX "SystemCommon" ///< http://lv2plug.in/ns/ext/midi#SystemCommon
#define LV2_MIDI__SystemExclusive LV2_MIDI_PREFIX "SystemExclusive" ///< http://lv2plug.in/ns/ext/midi#SystemExclusive
#define LV2_MIDI__SystemMessage LV2_MIDI_PREFIX "SystemMessage" ///< http://lv2plug.in/ns/ext/midi#SystemMessage
#define LV2_MIDI__SystemRealtime LV2_MIDI_PREFIX "SystemRealtime" ///< http://lv2plug.in/ns/ext/midi#SystemRealtime
#define LV2_MIDI__Tick LV2_MIDI_PREFIX "Tick" ///< http://lv2plug.in/ns/ext/midi#Tick
#define LV2_MIDI__TuneRequest LV2_MIDI_PREFIX "TuneRequest" ///< http://lv2plug.in/ns/ext/midi#TuneRequest
#define LV2_MIDI__VoiceMessage LV2_MIDI_PREFIX "VoiceMessage" ///< http://lv2plug.in/ns/ext/midi#VoiceMessage
#define LV2_MIDI__benderValue LV2_MIDI_PREFIX "benderValue" ///< http://lv2plug.in/ns/ext/midi#benderValue
#define LV2_MIDI__binding LV2_MIDI_PREFIX "binding" ///< http://lv2plug.in/ns/ext/midi#binding
#define LV2_MIDI__byteNumber LV2_MIDI_PREFIX "byteNumber" ///< http://lv2plug.in/ns/ext/midi#byteNumber
#define LV2_MIDI__channel LV2_MIDI_PREFIX "channel" ///< http://lv2plug.in/ns/ext/midi#channel
#define LV2_MIDI__chunk LV2_MIDI_PREFIX "chunk" ///< http://lv2plug.in/ns/ext/midi#chunk
#define LV2_MIDI__controllerNumber LV2_MIDI_PREFIX "controllerNumber" ///< http://lv2plug.in/ns/ext/midi#controllerNumber
#define LV2_MIDI__controllerValue LV2_MIDI_PREFIX "controllerValue" ///< http://lv2plug.in/ns/ext/midi#controllerValue
#define LV2_MIDI__noteNumber LV2_MIDI_PREFIX "noteNumber" ///< http://lv2plug.in/ns/ext/midi#noteNumber
#define LV2_MIDI__pressure LV2_MIDI_PREFIX "pressure" ///< http://lv2plug.in/ns/ext/midi#pressure
#define LV2_MIDI__programNumber LV2_MIDI_PREFIX "programNumber" ///< http://lv2plug.in/ns/ext/midi#programNumber
#define LV2_MIDI__property LV2_MIDI_PREFIX "property" ///< http://lv2plug.in/ns/ext/midi#property
#define LV2_MIDI__songNumber LV2_MIDI_PREFIX "songNumber" ///< http://lv2plug.in/ns/ext/midi#songNumber
#define LV2_MIDI__songPosition LV2_MIDI_PREFIX "songPosition" ///< http://lv2plug.in/ns/ext/midi#songPosition
#define LV2_MIDI__status LV2_MIDI_PREFIX "status" ///< http://lv2plug.in/ns/ext/midi#status
#define LV2_MIDI__statusMask LV2_MIDI_PREFIX "statusMask" ///< http://lv2plug.in/ns/ext/midi#statusMask
#define LV2_MIDI__velocity LV2_MIDI_PREFIX "velocity" ///< http://lv2plug.in/ns/ext/midi#velocity
// clang-format on
/**
MIDI Message Type.
This includes both voice messages (which have a channel) and system messages
(which do not), as well as a sentinel value for invalid messages. To get
the type of a message suitable for use in a switch statement, use
lv2_midi_get_type() on the status byte.
*/
typedef enum {
LV2_MIDI_MSG_INVALID = 0, /**< Invalid Message */
LV2_MIDI_MSG_NOTE_OFF = 0x80, /**< Note Off */
LV2_MIDI_MSG_NOTE_ON = 0x90, /**< Note On */
LV2_MIDI_MSG_NOTE_PRESSURE = 0xA0, /**< Note Pressure */
LV2_MIDI_MSG_CONTROLLER = 0xB0, /**< Controller */
LV2_MIDI_MSG_PGM_CHANGE = 0xC0, /**< Program Change */
LV2_MIDI_MSG_CHANNEL_PRESSURE = 0xD0, /**< Channel Pressure */
LV2_MIDI_MSG_BENDER = 0xE0, /**< Pitch Bender */
LV2_MIDI_MSG_SYSTEM_EXCLUSIVE = 0xF0, /**< System Exclusive Begin */
LV2_MIDI_MSG_MTC_QUARTER = 0xF1, /**< MTC Quarter Frame */
LV2_MIDI_MSG_SONG_POS = 0xF2, /**< Song Position */
LV2_MIDI_MSG_SONG_SELECT = 0xF3, /**< Song Select */
LV2_MIDI_MSG_TUNE_REQUEST = 0xF6, /**< Tune Request */
LV2_MIDI_MSG_CLOCK = 0xF8, /**< Clock */
LV2_MIDI_MSG_START = 0xFA, /**< Start */
LV2_MIDI_MSG_CONTINUE = 0xFB, /**< Continue */
LV2_MIDI_MSG_STOP = 0xFC, /**< Stop */
LV2_MIDI_MSG_ACTIVE_SENSE = 0xFE, /**< Active Sensing */
LV2_MIDI_MSG_RESET = 0xFF /**< Reset */
} LV2_Midi_Message_Type;
/**
Standard MIDI Controller Numbers.
*/
typedef enum {
LV2_MIDI_CTL_MSB_BANK = 0x00, /**< Bank Selection */
LV2_MIDI_CTL_MSB_MODWHEEL = 0x01, /**< Modulation */
LV2_MIDI_CTL_MSB_BREATH = 0x02, /**< Breath */
LV2_MIDI_CTL_MSB_FOOT = 0x04, /**< Foot */
LV2_MIDI_CTL_MSB_PORTAMENTO_TIME = 0x05, /**< Portamento Time */
LV2_MIDI_CTL_MSB_DATA_ENTRY = 0x06, /**< Data Entry */
LV2_MIDI_CTL_MSB_MAIN_VOLUME = 0x07, /**< Main Volume */
LV2_MIDI_CTL_MSB_BALANCE = 0x08, /**< Balance */
LV2_MIDI_CTL_MSB_PAN = 0x0A, /**< Panpot */
LV2_MIDI_CTL_MSB_EXPRESSION = 0x0B, /**< Expression */
LV2_MIDI_CTL_MSB_EFFECT1 = 0x0C, /**< Effect1 */
LV2_MIDI_CTL_MSB_EFFECT2 = 0x0D, /**< Effect2 */
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 = 0x10, /**< General Purpose 1 */
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 = 0x11, /**< General Purpose 2 */
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 = 0x12, /**< General Purpose 3 */
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 = 0x13, /**< General Purpose 4 */
LV2_MIDI_CTL_LSB_BANK = 0x20, /**< Bank Selection */
LV2_MIDI_CTL_LSB_MODWHEEL = 0x21, /**< Modulation */
LV2_MIDI_CTL_LSB_BREATH = 0x22, /**< Breath */
LV2_MIDI_CTL_LSB_FOOT = 0x24, /**< Foot */
LV2_MIDI_CTL_LSB_PORTAMENTO_TIME = 0x25, /**< Portamento Time */
LV2_MIDI_CTL_LSB_DATA_ENTRY = 0x26, /**< Data Entry */
LV2_MIDI_CTL_LSB_MAIN_VOLUME = 0x27, /**< Main Volume */
LV2_MIDI_CTL_LSB_BALANCE = 0x28, /**< Balance */
LV2_MIDI_CTL_LSB_PAN = 0x2A, /**< Panpot */
LV2_MIDI_CTL_LSB_EXPRESSION = 0x2B, /**< Expression */
LV2_MIDI_CTL_LSB_EFFECT1 = 0x2C, /**< Effect1 */
LV2_MIDI_CTL_LSB_EFFECT2 = 0x2D, /**< Effect2 */
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 = 0x30, /**< General Purpose 1 */
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 = 0x31, /**< General Purpose 2 */
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 = 0x32, /**< General Purpose 3 */
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 = 0x33, /**< General Purpose 4 */
LV2_MIDI_CTL_SUSTAIN = 0x40, /**< Sustain Pedal */
LV2_MIDI_CTL_PORTAMENTO = 0x41, /**< Portamento */
LV2_MIDI_CTL_SOSTENUTO = 0x42, /**< Sostenuto */
LV2_MIDI_CTL_SOFT_PEDAL = 0x43, /**< Soft Pedal */
LV2_MIDI_CTL_LEGATO_FOOTSWITCH = 0x44, /**< Legato Foot Switch */
LV2_MIDI_CTL_HOLD2 = 0x45, /**< Hold2 */
LV2_MIDI_CTL_SC1_SOUND_VARIATION = 0x46, /**< SC1 Sound Variation */
LV2_MIDI_CTL_SC2_TIMBRE = 0x47, /**< SC2 Timbre */
LV2_MIDI_CTL_SC3_RELEASE_TIME = 0x48, /**< SC3 Release Time */
LV2_MIDI_CTL_SC4_ATTACK_TIME = 0x49, /**< SC4 Attack Time */
LV2_MIDI_CTL_SC5_BRIGHTNESS = 0x4A, /**< SC5 Brightness */
LV2_MIDI_CTL_SC6 = 0x4B, /**< SC6 */
LV2_MIDI_CTL_SC7 = 0x4C, /**< SC7 */
LV2_MIDI_CTL_SC8 = 0x4D, /**< SC8 */
LV2_MIDI_CTL_SC9 = 0x4E, /**< SC9 */
LV2_MIDI_CTL_SC10 = 0x4F, /**< SC10 */
LV2_MIDI_CTL_GENERAL_PURPOSE5 = 0x50, /**< General Purpose 5 */
LV2_MIDI_CTL_GENERAL_PURPOSE6 = 0x51, /**< General Purpose 6 */
LV2_MIDI_CTL_GENERAL_PURPOSE7 = 0x52, /**< General Purpose 7 */
LV2_MIDI_CTL_GENERAL_PURPOSE8 = 0x53, /**< General Purpose 8 */
LV2_MIDI_CTL_PORTAMENTO_CONTROL = 0x54, /**< Portamento Control */
LV2_MIDI_CTL_E1_REVERB_DEPTH = 0x5B, /**< E1 Reverb Depth */
LV2_MIDI_CTL_E2_TREMOLO_DEPTH = 0x5C, /**< E2 Tremolo Depth */
LV2_MIDI_CTL_E3_CHORUS_DEPTH = 0x5D, /**< E3 Chorus Depth */
LV2_MIDI_CTL_E4_DETUNE_DEPTH = 0x5E, /**< E4 Detune Depth */
LV2_MIDI_CTL_E5_PHASER_DEPTH = 0x5F, /**< E5 Phaser Depth */
LV2_MIDI_CTL_DATA_INCREMENT = 0x60, /**< Data Increment */
LV2_MIDI_CTL_DATA_DECREMENT = 0x61, /**< Data Decrement */
LV2_MIDI_CTL_NRPN_LSB = 0x62, /**< Non-registered Parameter Number */
LV2_MIDI_CTL_NRPN_MSB = 0x63, /**< Non-registered Parameter Number */
LV2_MIDI_CTL_RPN_LSB = 0x64, /**< Registered Parameter Number */
LV2_MIDI_CTL_RPN_MSB = 0x65, /**< Registered Parameter Number */
LV2_MIDI_CTL_ALL_SOUNDS_OFF = 0x78, /**< All Sounds Off */
LV2_MIDI_CTL_RESET_CONTROLLERS = 0x79, /**< Reset Controllers */
LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH = 0x7A, /**< Local Control Switch */
LV2_MIDI_CTL_ALL_NOTES_OFF = 0x7B, /**< All Notes Off */
LV2_MIDI_CTL_OMNI_OFF = 0x7C, /**< Omni Off */
LV2_MIDI_CTL_OMNI_ON = 0x7D, /**< Omni On */
LV2_MIDI_CTL_MONO1 = 0x7E, /**< Mono1 */
LV2_MIDI_CTL_MONO2 = 0x7F /**< Mono2 */
} LV2_Midi_Controller;
/**
Return true iff `msg` is a MIDI voice message (which has a channel).
*/
static inline bool
lv2_midi_is_voice_message(const uint8_t* msg)
{
return msg[0] >= 0x80 && msg[0] < 0xF0;
}
/**
Return true iff `msg` is a MIDI system message (which has no channel).
*/
static inline bool
lv2_midi_is_system_message(const uint8_t* msg)
{
switch (msg[0]) {
case 0xF4:
case 0xF5:
case 0xF7:
case 0xF9:
case 0xFD:
return false;
default:
return (msg[0] & 0xF0) == 0xF0;
}
}
/**
Return the type of a MIDI message.
@param msg Pointer to the start (status byte) of a MIDI message.
*/
static inline LV2_Midi_Message_Type
lv2_midi_message_type(const uint8_t* msg)
{
if (lv2_midi_is_voice_message(msg)) {
return (LV2_Midi_Message_Type)(msg[0] & 0xF0);
}
if (lv2_midi_is_system_message(msg)) {
return (LV2_Midi_Message_Type)msg[0];
}
return LV2_MIDI_MSG_INVALID;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
*/
#endif /* LV2_MIDI_H */

View File

@@ -0,0 +1,153 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/midi>
a doap:Project ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2 MIDI" ;
doap:shortdesc "A normalised definition of raw MIDI." ;
doap:maintainer <http://drobilla.net/drobilla#me> ;
doap:created "2006-00-00" ;
doap:developer <http://lv2plug.in/ns/meta#larsl> ,
<http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "1.10" ;
doap:created "2019-02-03" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix incorrect range of midi:chunk."
]
]
] , [
doap:revision "1.8" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Use consistent label style."
] , [
rdfs:label "Add midi:binding and midi:channel predicates."
] , [
rdfs:label "Add midi:HexByte datatype for status bytes and masks."
] , [
rdfs:label "Remove non-standard midi:Tick message type."
] , [
rdfs:label "Add C definitions for message types and standard controllers."
] , [
rdfs:label "Fix definition of SystemExclusive status byte."
]
]
] , [
doap:revision "1.6" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add class definitions for various message types."
] , [
rdfs:label "Document how to serialise a MidiEvent to a string."
] , [
rdfs:label "Merge with unified LV2 package."
]
]
] , [
doap:revision "1.4" ;
doap:created "2011-11-21" ;
doap:file-release <http://lv2plug.in/spec/lv2-midi-1.4.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Update packaging."
] , [
rdfs:label "Improve documentation."
]
]
] , [
doap:revision "1.2" ;
doap:created "2011-05-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-midi-1.2.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add build system for installation."
] , [
rdfs:label "Switch to ISC license."
]
]
] , [
doap:revision "1.0" ;
doap:created "2010-10-04" ;
doap:file-release <http://lv2plug.in/spec/lv2-midi-1.0.tar.gz> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This specification defines a data type for a MIDI message, midi:MidiEvent,
which is normalised for fast and convenient real-time processing. MIDI is the
<q>Musical Instrument Digital Interface</q>, a ubiquitous binary standard for
controlling digital music devices.
For plugins that process MIDI (or other situations where MIDI is sent via a
generic transport) the main type defined here, midi:MidiEvent, can be mapped to
an integer and used as the type of an LV2 [Atom](atom.html#Atom) or
[Event](event.html#Event).
This specification also defines a complete vocabulary for the MIDI standard,
except for standard controller numbers. These descriptions are detailed enough
to express any MIDI message as properties.
"""^^lv2:Markdown .
midi:MidiEvent
lv2:documentation """
A single raw MIDI message (a sequence of bytes).
This is equivalent to a standard MIDI messages, except with the following
restrictions to simplify handling:
* Running status is not allowed, every message must have its own status byte.
* Note On messages with velocity 0 are not allowed. These messages are
equivalent to Note Off in standard MIDI streams, but here only proper Note
Off messages are allowed.
* "Realtime messages" (status bytes 0xF8 to 0xFF) are allowed, but may not
occur inside other messages like they can in standard MIDI streams.
* All messages are complete valid MIDI messages. This means, for example,
that only the first byte in each event (the status byte) may have the
eighth bit set, that Note On and Note Off events are always 3 bytes long,
etc.
Where messages are communicated, the writer is responsible for writing valid
messages, and the reader may assume that all events are valid.
If a midi:MidiEvent is serialised to a string, the format should be
xsd:hexBinary, for example:
:::turtle
[] eg:someEvent "901A01"^^midi:MidiEvent .
"""^^lv2:Markdown .
midi:statusMask
lv2:documentation """
This is a status byte with the lower nibble set to zero.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,366 @@
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix ev: <http://lv2plug.in/ns/ext/event#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/midi>
a owl:Ontology ;
rdfs:label "LV2 MIDI" ;
rdfs:comment "A normalised definition of raw MIDI." ;
rdfs:seeAlso <midi.h> ,
<midi.meta.ttl> .
midi:ActiveSense
a rdfs:Class ;
rdfs:subClassOf midi:SystemRealtime ;
rdfs:label "Active Sense" ;
rdfs:comment "MIDI active sense message." ;
midi:status "FE"^^xsd:hexBinary .
midi:Aftertouch
a rdfs:Class ;
rdfs:subClassOf midi:VoiceMessage ;
rdfs:label "Aftertouch" ;
rdfs:comment "MIDI aftertouch message." ;
midi:statusMask "A0"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ;
midi:property midi:noteNumber
] , [
midi:byteNumber 1 ;
midi:property midi:pressure
] .
midi:Bender
a rdfs:Class ;
rdfs:subClassOf midi:VoiceMessage ;
rdfs:label "Bender" ;
rdfs:comment "MIDI bender message." ;
midi:statusMask "E0"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ,
1 ;
midi:property midi:benderValue
] .
midi:ChannelPressure
a rdfs:Class ;
rdfs:subClassOf midi:VoiceMessage ;
rdfs:label "Channel Pressure" ;
rdfs:comment "MIDI channel pressure message." ;
midi:statusMask "D0"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ;
midi:property midi:pressure
] .
midi:Chunk
a rdfs:Class ;
rdfs:label "Chunk" ;
rdfs:comment "A sequence of contiguous bytes in a MIDI message." .
midi:Clock
a rdfs:Class ;
rdfs:subClassOf midi:SystemRealtime ;
rdfs:label "Clock" ;
rdfs:comment "MIDI clock message." ;
midi:status "F8"^^xsd:hexBinary .
midi:Continue
a rdfs:Class ;
rdfs:subClassOf midi:SystemRealtime ;
rdfs:label "Continue" ;
rdfs:comment "MIDI continue message." ;
midi:status "FB"^^xsd:hexBinary .
midi:Controller
a rdfs:Class ;
rdfs:subClassOf midi:VoiceMessage ;
rdfs:label "Controller" ;
rdfs:comment "MIDI controller change message." ;
midi:statusMask "B0"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ;
midi:property midi:controllerNumber
] , [
midi:byteNumber 1 ;
midi:property midi:controllerValue
] .
midi:HexByte
a rdfs:Datatype ;
owl:onDatatype xsd:hexBinary ;
owl:withRestrictions (
[
xsd:maxInclusive "FF"
]
) ;
rdfs:label "Hex Byte" ;
rdfs:comment "A hexadecimal byte, which has a value <= FF." .
midi:MidiEvent
a rdfs:Class ,
rdfs:Datatype ;
rdfs:subClassOf ev:Event ,
atom:Atom ;
owl:onDatatype xsd:hexBinary ;
rdfs:label "MIDI Message" ;
rdfs:comment "A single raw MIDI message." .
midi:NoteOff
a rdfs:Class ;
rdfs:subClassOf midi:VoiceMessage ;
rdfs:label "Note Off" ;
rdfs:comment "MIDI note off message." ;
midi:statusMask "80"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ;
midi:property midi:noteNumber
] , [
midi:byteNumber 1 ;
midi:property midi:velocity
] .
midi:NoteOn
a rdfs:Class ;
rdfs:subClassOf midi:VoiceMessage ;
rdfs:label "Note On" ;
rdfs:comment "MIDI note on message." ;
midi:statusMask "90"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ;
midi:property midi:noteNumber
] , [
midi:byteNumber 1 ;
midi:property midi:velocity
] .
midi:ProgramChange
a rdfs:Class ;
rdfs:subClassOf midi:VoiceMessage ;
rdfs:label "Program Change" ;
rdfs:comment "MIDI program change message." ;
midi:statusMask "C0"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ;
midi:property midi:programNumber
] .
midi:QuarterFrame
a rdfs:Class ;
rdfs:subClassOf midi:SystemCommon ;
rdfs:label "Quarter Frame" ;
rdfs:comment "MIDI quarter frame message." ;
midi:status "F1"^^xsd:hexBinary .
midi:Reset
a rdfs:Class ;
rdfs:subClassOf midi:SystemRealtime ;
rdfs:label "Reset" ;
rdfs:comment "MIDI reset message." ;
midi:status "FF"^^xsd:hexBinary .
midi:SongPosition
a rdfs:Class ;
rdfs:subClassOf midi:SystemCommon ;
rdfs:label "Song Position" ;
rdfs:comment "MIDI song position pointer message." ;
midi:status "F2"^^xsd:hexBinary ;
midi:chunk [
midi:byteNumber 0 ,
1 ;
midi:property midi:songPosition
] .
midi:SongSelect
a rdfs:Class ;
rdfs:subClassOf midi:SystemCommon ;
rdfs:label "Song Select" ;
rdfs:comment "MIDI song select message." ;
midi:status "F3"^^xsd:hexBinary .
midi:Start
a rdfs:Class ;
rdfs:subClassOf midi:SystemRealtime ;
rdfs:label "Start" ;
rdfs:comment "MIDI start message." ;
midi:status "FA"^^xsd:hexBinary .
midi:Stop
a rdfs:Class ;
rdfs:subClassOf midi:SystemRealtime ;
rdfs:label "Stop" ;
rdfs:comment "MIDI stop message." ;
midi:status "FC"^^xsd:hexBinary .
midi:SystemCommon
a rdfs:Class ;
rdfs:subClassOf midi:SystemMessage ;
rdfs:label "System Common" ;
rdfs:comment "MIDI system common message." .
midi:SystemExclusive
a rdfs:Class ;
rdfs:subClassOf midi:SystemMessage ;
rdfs:label "System Exclusive" ;
rdfs:comment "MIDI system exclusive message." ;
midi:status "F0"^^xsd:hexBinary .
midi:SystemMessage
a rdfs:Class ;
rdfs:subClassOf midi:MidiEvent ;
rdfs:label "System Message" ;
rdfs:comment "MIDI system message." ;
midi:statusMask "F0"^^xsd:hexBinary .
midi:SystemRealtime
a rdfs:Class ;
rdfs:subClassOf midi:SystemMessage ;
rdfs:label "System Realtime" ;
rdfs:comment "MIDI system realtime message." .
midi:TuneRequest
a rdfs:Class ;
rdfs:subClassOf midi:SystemCommon ;
rdfs:label "Tune Request" ;
rdfs:comment "MIDI tune request message." ;
midi:status "F6"^^xsd:hexBinary .
midi:VoiceMessage
a rdfs:Class ;
rdfs:subClassOf midi:MidiEvent ;
rdfs:label "Voice Message" ;
rdfs:comment "MIDI voice message." ;
midi:statusMask "F0"^^xsd:hexBinary .
midi:benderValue
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "bender value" ;
rdfs:range xsd:short ;
rdfs:comment "MIDI pitch bender message (-8192 to 8192)." .
midi:binding
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range midi:MidiEvent ;
rdfs:label "binding" ;
rdfs:comment "The MIDI event to bind a parameter to." .
midi:byteNumber
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:label "byte number" ;
rdfs:domain midi:Chunk ;
rdfs:range xsd:unsignedByte ;
rdfs:comment "The 0-based index of a byte which is part of this chunk." .
midi:channel
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "MIDI channel" ;
rdfs:range xsd:unsignedByte ;
rdfs:comment "The channel number of a MIDI message." .
midi:chunk
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range midi:Chunk ;
rdfs:label "MIDI chunk" ;
rdfs:comment "A chunk of a MIDI message." .
midi:controllerNumber
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "MIDI controller number" ;
rdfs:range xsd:byte ;
rdfs:comment "The numeric ID of a controller (0 to 127)." .
midi:controllerValue
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "MIDI controller value" ;
rdfs:range xsd:byte ;
rdfs:comment "The value of a controller (0 to 127)." .
midi:noteNumber
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "note number" ;
rdfs:range xsd:byte ;
rdfs:comment "The numeric ID of a note (0 to 127)." .
midi:pressure
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "key pressure" ;
rdfs:range xsd:byte ;
rdfs:comment "Key pressure (0 to 127)." .
midi:programNumber
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "program number" ;
rdfs:range xsd:byte ;
rdfs:comment "The numeric ID of a program (0 to 127)." .
midi:property
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:label "property" ;
rdfs:domain midi:Chunk ;
rdfs:range rdf:Property ;
rdfs:comment "The property this chunk represents." .
midi:songNumber
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "song number" ;
rdfs:range xsd:byte ;
rdfs:comment "The numeric ID of a song (0 to 127)." .
midi:songPosition
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "song position" ;
rdfs:range xsd:short ;
rdfs:comment "Song position in MIDI beats (16th notes) (-8192 to 8192)." .
midi:status
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "status byte" ;
rdfs:range midi:HexByte ;
rdfs:comment "The exact status byte for a message of this type." .
midi:statusMask
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "status mask" ;
rdfs:range midi:HexByte ;
rdfs:comment "The status byte for a message of this type on channel 1." .
midi:velocity
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "velocity" ;
rdfs:range midi:HexByte ;
rdfs:comment "The velocity of a note message (0 to 127)." .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/morph>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 0 ;
rdfs:seeAlso <morph.ttl> .

View File

@@ -0,0 +1,48 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_MORPH_H
#define LV2_MORPH_H
/**
@defgroup morph Morph
@ingroup lv2
Ports that can dynamically change type.
See <http://lv2plug.in/ns/ext/morph> for details.
@{
*/
// clang-format off
#define LV2_MORPH_URI "http://lv2plug.in/ns/ext/morph" ///< http://lv2plug.in/ns/ext/morph
#define LV2_MORPH_PREFIX LV2_MORPH_URI "#" ///< http://lv2plug.in/ns/ext/morph#
#define LV2_MORPH__AutoMorphPort LV2_MORPH_PREFIX "AutoMorphPort" ///< http://lv2plug.in/ns/ext/morph#AutoMorphPort
#define LV2_MORPH__MorphPort LV2_MORPH_PREFIX "MorphPort" ///< http://lv2plug.in/ns/ext/morph#MorphPort
#define LV2_MORPH__interface LV2_MORPH_PREFIX "interface" ///< http://lv2plug.in/ns/ext/morph#interface
#define LV2_MORPH__supportsType LV2_MORPH_PREFIX "supportsType" ///< http://lv2plug.in/ns/ext/morph#supportsType
#define LV2_MORPH__currentType LV2_MORPH_PREFIX "currentType" ///< http://lv2plug.in/ns/ext/morph#currentType
// clang-format on
/**
@}
*/
#endif /* LV2_MORPH_H */

View File

@@ -0,0 +1,90 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix morph: <http://lv2plug.in/ns/ext/morph#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/morph>
a doap:Project ;
doap:name "LV2 Morph" ;
doap:shortdesc "Ports that can dynamically change type." ;
doap:created "2012-05-22" ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "1.0" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This extension defines two port types: morph:MorphPort, which has a
host-configurable type, and morph:AutoMorphPort, which may automatically change
type when a MorphPort's type is changed. These ports always have a default
type and work normally work in hosts that are unaware of this extension. Thus,
this extension provides a backwards compatibility mechanism which allows
plugins to use new port types but gracefully fall back to a default type in
hosts that do not support them.
This extension only defines port types and properties for describing morph
ports. The actual run-time switching is done via the opts:interface API.
"""^^lv2:Markdown .
morph:MorphPort
lv2:documentation """
Ports of this type MUST have another type which defines the default buffer
format (for example lv2:ControlPort) but can be dynamically changed to a
different type in hosts that support opts:interface.
The host may change the type of a MorphPort by setting its morph:currentType
with LV2_Options_Interface::set(). If the plugin has any morph:AutoMorphPort
ports, the host MUST check their types after changing any port type since they
may have changed.
"""^^lv2:Markdown .
morph:AutoMorphPort
lv2:documentation """
Ports of this type MUST have another type which defines the default buffer
format (for example, lv2:ControlPort) but may dynamically change types based on
the configured types of any morph:MorphPort ports on the same plugin instance.
The type of a port may only change in response to a host call to
LV2_Options_Interface::set(). Whenever any port type on the instance changes,
the host MUST check the type of all morph:AutoMorphPort ports with
LV2_Options_Interface::get() before calling run() again, since they may have
changed. If the type of any port is zero, it means the current configuration
is invalid and the plugin may not be run (unless that port is
lv2:connectionOptional and connected to NULL).
This is mainly useful for outputs whose type depends on the type of
corresponding inputs.
"""^^lv2:Markdown .
morph:supportsType
lv2:documentation """
Indicates that a port supports being switched to a certain type. A MorphPort
MUST list each type it supports being switched to in the plugin data using this
property.
"""^^lv2:Markdown .
morph:currentType
lv2:documentation """
The currently active type of the port. This is for dynamic use as an option
and SHOULD NOT be listed in the static plugin data.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,46 @@
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix morph: <http://lv2plug.in/ns/ext/morph#> .
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/morph>
a owl:Ontology ;
rdfs:label "LV2 Morph" ;
rdfs:comment "Ports that can dynamically change type." ;
rdfs:seeAlso <morph.h> ,
<morph.meta.ttl> .
morph:MorphPort
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "Morph Port" ;
rdfs:comment "A port which can be switched to another type." .
morph:AutoMorphPort
a rdfs:Class ,
owl:Class ;
rdfs:subClassOf lv2:Port ;
rdfs:label "Auto Morph Port" ;
rdfs:comment "A port that can change its type based on that of another." .
morph:supportsType
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain morph:MorphPort ;
rdfs:label "supports type" ;
rdfs:comment "A type that a port supports being switched to." .
morph:currentType
a rdf:Property ,
opts:Option ,
owl:ObjectProperty ;
rdfs:domain morph:MorphPort ;
rdfs:label "current type" ;
rdfs:comment "The currently active type of the port." .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/options>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 4 ;
rdfs:seeAlso <options.ttl> .

View File

@@ -0,0 +1,149 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_OPTIONS_H
#define LV2_OPTIONS_H
/**
@defgroup options Options
@ingroup lv2
Instantiation time options.
See <http://lv2plug.in/ns/ext/options> for details.
@{
*/
#include "lv2/core/lv2.h"
#include "lv2/urid/urid.h"
#include <stdint.h>
// clang-format off
#define LV2_OPTIONS_URI "http://lv2plug.in/ns/ext/options" ///< http://lv2plug.in/ns/ext/options
#define LV2_OPTIONS_PREFIX LV2_OPTIONS_URI "#" ///< http://lv2plug.in/ns/ext/options#
#define LV2_OPTIONS__Option LV2_OPTIONS_PREFIX "Option" ///< http://lv2plug.in/ns/ext/options#Option
#define LV2_OPTIONS__interface LV2_OPTIONS_PREFIX "interface" ///< http://lv2plug.in/ns/ext/options#interface
#define LV2_OPTIONS__options LV2_OPTIONS_PREFIX "options" ///< http://lv2plug.in/ns/ext/options#options
#define LV2_OPTIONS__requiredOption LV2_OPTIONS_PREFIX "requiredOption" ///< http://lv2plug.in/ns/ext/options#requiredOption
#define LV2_OPTIONS__supportedOption LV2_OPTIONS_PREFIX "supportedOption" ///< http://lv2plug.in/ns/ext/options#supportedOption
// clang-format on
#ifdef __cplusplus
extern "C" {
#endif
/**
The context of an Option, which defines the subject it applies to.
*/
typedef enum {
/**
This option applies to the instance itself. The subject must be
ignored.
*/
LV2_OPTIONS_INSTANCE,
/**
This option applies to some named resource. The subject is a URI mapped
to an integer (a LV2_URID, like the key)
*/
LV2_OPTIONS_RESOURCE,
/**
This option applies to some blank node. The subject is a blank node
identifier, which is valid only within the current local scope.
*/
LV2_OPTIONS_BLANK,
/**
This option applies to a port on the instance. The subject is the
port's index.
*/
LV2_OPTIONS_PORT
} LV2_Options_Context;
/**
An option.
This is a property with a subject, also known as a triple or statement.
This struct is useful anywhere a statement needs to be passed where no
memory ownership issues are present (since the value is a const pointer).
Options can be passed to an instance via the feature LV2_OPTIONS__options
with data pointed to an array of options terminated by a zeroed option, or
accessed/manipulated using LV2_Options_Interface.
*/
typedef struct {
LV2_Options_Context context; /**< Context (type of subject). */
uint32_t subject; /**< Subject. */
LV2_URID key; /**< Key (property). */
uint32_t size; /**< Size of value in bytes. */
LV2_URID type; /**< Type of value (datatype). */
const void* value; /**< Pointer to value (object). */
} LV2_Options_Option;
/** A status code for option functions. */
typedef enum {
LV2_OPTIONS_SUCCESS = 0, /**< Completed successfully. */
LV2_OPTIONS_ERR_UNKNOWN = 1, /**< Unknown error. */
LV2_OPTIONS_ERR_BAD_SUBJECT = 1 << 1, /**< Invalid/unsupported subject. */
LV2_OPTIONS_ERR_BAD_KEY = 1 << 2, /**< Invalid/unsupported key. */
LV2_OPTIONS_ERR_BAD_VALUE = 1 << 3 /**< Invalid/unsupported value. */
} LV2_Options_Status;
/**
Interface for dynamically setting options (LV2_OPTIONS__interface).
*/
typedef struct {
/**
Get the given options.
Each element of the passed options array MUST have type, subject, and
key set. All other fields (size, type, value) MUST be initialised to
zero, and are set to the option value if such an option is found.
This function is in the "instantiation" LV2 threading class, so no other
instance functions may be called concurrently.
@return Bitwise OR of LV2_Options_Status values.
*/
uint32_t (*get)(LV2_Handle instance, LV2_Options_Option* options);
/**
Set the given options.
This function is in the "instantiation" LV2 threading class, so no other
instance functions may be called concurrently.
@return Bitwise OR of LV2_Options_Status values.
*/
uint32_t (*set)(LV2_Handle instance, const LV2_Options_Option* options);
} LV2_Options_Interface;
#ifdef __cplusplus
} /* extern "C" */
#endif
/**
@}
*/
#endif /* LV2_OPTIONS_H */

View File

@@ -0,0 +1,129 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/options>
a doap:Project ;
doap:name "LV2 Options" ;
doap:shortdesc "Runtime options for LV2 plugins and UIs." ;
doap:created "2012-08-20" ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "1.4" ;
doap:created "2019-02-03" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Relax range of opts:requiredOption and opts:supportedOption"
]
]
] , [
doap:revision "1.2" ;
doap:created "2013-01-10" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Set the range of opts:requiredOption and opts:supportedOption to opts:Option."
]
]
] , [
doap:revision "1.0" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This extension defines a facility for <q>options</q>, which are values the host
passes to a plugin or UI at run time.
There are two facilities for passing options to an instance: opts:options
allows passing options at instantiation time, and the opts:interface interface
allows options to be dynamically set and retrieved after instantiation.
Note that this extension is only for allowing hosts to configure plugins, and
is not a <q>live</q> control mechanism. For real-time control, use event-based
control via an atom:AtomPort with an atom:Sequence buffer.
Instances may indicate they require an option with the opts:requiredOption
property, or that they optionally support an option with the
opts:supportedOption property.
"""^^lv2:Markdown .
opts:Option
lv2:documentation """
It is not required for a property to explicitly be an Option in order to be
used as such. However, properties which are primarily intended for use as
options, or are at least particularly useful as options, should be explicitly
given this type for documentation purposes, and to assist hosts in discovering
option definitions.
"""^^lv2:Markdown .
opts:interface
lv2:documentation """
An interface (LV2_Options_Interface) for dynamically setting and getting
options. Note that this is intended for use by the host for configuring
plugins only, and is not a <q>live</q> plugin control mechanism.
The plugin data file should advertise this interface like so:
:::turtle
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
<plugin>
a lv2:Plugin ;
lv2:extensionData opts:interface .
"""^^lv2:Markdown .
opts:options
lv2:documentation """
To implement this feature, hosts MUST pass an LV2_Feature to the appropriate
instantiate method with this URI and data pointed to an array of
LV2_Options_Option terminated by an element with both key and value set to
zero. The instance should cast this data pointer to `const
LV2_Options_Option*` and scan the array for any options of interest. The
instance MUST NOT modify the options array in any way.
Note that requiring this feature may reduce the number of compatible hosts.
Unless some options are strictly required by the instance, this feature SHOULD
be listed as an lv2:optionalFeature.
"""^^lv2:Markdown .
opts:requiredOption
lv2:documentation """
The host MUST pass a value for the specified option via opts:options during
instantiation.
Note that use of this property may reduce the number of compatible hosts.
Wherever possible, it is better to list options with opts:supportedOption and
fall back to a reasonable default value if it is not provided.
"""^^lv2:Markdown .
opts:supportedOption
lv2:documentation """
The host SHOULD provide a value for the specified option if one is known, or
provide the user an opportunity to specify one if possible.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,44 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/options>
a owl:Ontology ;
rdfs:label "LV2 Options" ;
rdfs:comment "Runtime options for LV2 plugins and UIs." ;
rdfs:seeAlso <options.h> ,
<options.meta.ttl> .
opts:Option
a rdfs:Class ;
rdfs:label "Option" ;
rdfs:subClassOf rdf:Property ;
rdfs:comment "A value for a static option passed to an instance." .
opts:interface
a lv2:ExtensionData ;
rdfs:label "interface" ;
rdfs:comment "An interface for dynamically setting and getting options." .
opts:options
a lv2:Feature ;
rdfs:label "options" ;
rdfs:comment "The feature used to provide options to an instance." .
opts:requiredOption
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range rdf:Property ;
rdfs:label "required option" ;
rdfs:comment "An option required by the instance to function at all." .
opts:supportedOption
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range rdf:Property ;
rdfs:label "supported option" ;
rdfs:comment "An option supported or by the instance." .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/parameters>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 4 ;
rdfs:seeAlso <parameters.ttl> .

View File

@@ -0,0 +1,68 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_PARAMETERS_H
#define LV2_PARAMETERS_H
/**
@defgroup parameters Parameters
@ingroup lv2
Common parameters for audio processing.
See <http://lv2plug.in/ns/ext/parameters> for details.
@{
*/
// clang-format off
#define LV2_PARAMETERS_URI "http://lv2plug.in/ns/ext/parameters" ///< http://lv2plug.in/ns/ext/parameters
#define LV2_PARAMETERS_PREFIX LV2_PARAMETERS_URI "#" ///< http://lv2plug.in/ns/ext/parameters#
#define LV2_PARAMETERS__CompressorControls LV2_PARAMETERS_PREFIX "CompressorControls" ///< http://lv2plug.in/ns/ext/parameters#CompressorControls
#define LV2_PARAMETERS__ControlGroup LV2_PARAMETERS_PREFIX "ControlGroup" ///< http://lv2plug.in/ns/ext/parameters#ControlGroup
#define LV2_PARAMETERS__EnvelopeControls LV2_PARAMETERS_PREFIX "EnvelopeControls" ///< http://lv2plug.in/ns/ext/parameters#EnvelopeControls
#define LV2_PARAMETERS__FilterControls LV2_PARAMETERS_PREFIX "FilterControls" ///< http://lv2plug.in/ns/ext/parameters#FilterControls
#define LV2_PARAMETERS__OscillatorControls LV2_PARAMETERS_PREFIX "OscillatorControls" ///< http://lv2plug.in/ns/ext/parameters#OscillatorControls
#define LV2_PARAMETERS__amplitude LV2_PARAMETERS_PREFIX "amplitude" ///< http://lv2plug.in/ns/ext/parameters#amplitude
#define LV2_PARAMETERS__attack LV2_PARAMETERS_PREFIX "attack" ///< http://lv2plug.in/ns/ext/parameters#attack
#define LV2_PARAMETERS__bypass LV2_PARAMETERS_PREFIX "bypass" ///< http://lv2plug.in/ns/ext/parameters#bypass
#define LV2_PARAMETERS__cutoffFrequency LV2_PARAMETERS_PREFIX "cutoffFrequency" ///< http://lv2plug.in/ns/ext/parameters#cutoffFrequency
#define LV2_PARAMETERS__decay LV2_PARAMETERS_PREFIX "decay" ///< http://lv2plug.in/ns/ext/parameters#decay
#define LV2_PARAMETERS__delay LV2_PARAMETERS_PREFIX "delay" ///< http://lv2plug.in/ns/ext/parameters#delay
#define LV2_PARAMETERS__dryLevel LV2_PARAMETERS_PREFIX "dryLevel" ///< http://lv2plug.in/ns/ext/parameters#dryLevel
#define LV2_PARAMETERS__frequency LV2_PARAMETERS_PREFIX "frequency" ///< http://lv2plug.in/ns/ext/parameters#frequency
#define LV2_PARAMETERS__gain LV2_PARAMETERS_PREFIX "gain" ///< http://lv2plug.in/ns/ext/parameters#gain
#define LV2_PARAMETERS__hold LV2_PARAMETERS_PREFIX "hold" ///< http://lv2plug.in/ns/ext/parameters#hold
#define LV2_PARAMETERS__pulseWidth LV2_PARAMETERS_PREFIX "pulseWidth" ///< http://lv2plug.in/ns/ext/parameters#pulseWidth
#define LV2_PARAMETERS__ratio LV2_PARAMETERS_PREFIX "ratio" ///< http://lv2plug.in/ns/ext/parameters#ratio
#define LV2_PARAMETERS__release LV2_PARAMETERS_PREFIX "release" ///< http://lv2plug.in/ns/ext/parameters#release
#define LV2_PARAMETERS__resonance LV2_PARAMETERS_PREFIX "resonance" ///< http://lv2plug.in/ns/ext/parameters#resonance
#define LV2_PARAMETERS__sampleRate LV2_PARAMETERS_PREFIX "sampleRate" ///< http://lv2plug.in/ns/ext/parameters#sampleRate
#define LV2_PARAMETERS__sustain LV2_PARAMETERS_PREFIX "sustain" ///< http://lv2plug.in/ns/ext/parameters#sustain
#define LV2_PARAMETERS__threshold LV2_PARAMETERS_PREFIX "threshold" ///< http://lv2plug.in/ns/ext/parameters#threshold
#define LV2_PARAMETERS__waveform LV2_PARAMETERS_PREFIX "waveform" ///< http://lv2plug.in/ns/ext/parameters#waveform
#define LV2_PARAMETERS__wetDryRatio LV2_PARAMETERS_PREFIX "wetDryRatio" ///< http://lv2plug.in/ns/ext/parameters#wetDryRatio
#define LV2_PARAMETERS__wetLevel LV2_PARAMETERS_PREFIX "wetLevel" ///< http://lv2plug.in/ns/ext/parameters#wetLevel
// clang-format on
/**
@}
*/
#endif /* LV2_PARAMETERS_H */

View File

@@ -0,0 +1,75 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix param: <http://lv2plug.in/ns/ext/parameters#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/parameters>
a doap:Project ;
doap:name "LV2 Parameters" ;
doap:release [
doap:revision "1.4" ;
doap:created "2015-04-07" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.12.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add range to parameters so hosts know how to control them."
]
]
] , [
doap:revision "1.2" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Use consistent label style."
] , [
rdfs:label "Add param:sampleRate."
] , [
rdfs:label "Add parameters.h of URI defines for convenience."
]
]
] , [
doap:revision "1.0" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
doap:created "2009-00-00" ;
doap:shortdesc "Common parameters for audio processing." ;
doap:maintainer <http://drobilla.net/drobilla#me> ;
doap:developer <http://lv2plug.in/ns/meta#larsl> ;
lv2:documentation """
This is a vocabulary for parameters that are common in audio processing
software. A <q>parameter</q> is purely a metadata concept, unrelated to any
particular code mechanism. Parameters are used to assign meaning to controls
(for example, using lv2:designation for ports) so they can be used more
intelligently or presented to the user more efficiently.
"""^^lv2:Markdown .
param:wetDryRatio
a lv2:Parameter ;
rdfs:label "wet/dry ratio" ;
lv2:documentation """
The ratio between processed and bypass components in output signal. The dry
and wet percentages can be calculated from the following equations:
:::c
dry = (wetDryRatio.maximum - wetDryRatio.value) / wetDryRatio.maximum
wet = wetDryRatio.value / wetDryRatio.maximum
Typically, maximum value of 1 or 100 and minimum value of 0 should be used.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,202 @@
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix param: <http://lv2plug.in/ns/ext/parameters#> .
@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
<http://lv2plug.in/ns/ext/parameters>
a owl:Ontology ;
rdfs:label "LV2 Parameters" ;
rdfs:comment "Common parameters for audio processing." ;
rdfs:seeAlso <parameters.meta.ttl> .
param:ControlGroup
a rdfs:Class ;
rdfs:subClassOf pg:Group ;
rdfs:label "Control Group" ;
rdfs:comment "A group representing a set of associated controls." .
param:amplitude
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "amplitude" ;
rdfs:comment "An amplitude as a factor, where 0 is silent and 1 is unity." .
param:attack
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "attack" ;
rdfs:comment "The duration of an envelope attack stage." .
param:cutoffFrequency
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "cutoff frequency" ;
rdfs:comment "The cutoff frequency, typically in Hz, for a filter." .
param:decay
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "decay" ;
rdfs:comment "The duration of an envelope decay stage." .
param:delay
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "delay" ;
rdfs:comment "The duration of an envelope delay stage." .
param:frequency
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "frequency" ;
rdfs:comment "A frequency, typically in Hz." .
param:hold
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "hold" ;
rdfs:comment "The duration of an envelope hold stage." .
param:pulseWidth
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "pulse width" ;
rdfs:comment "The width of a pulse of a rectangular waveform." .
param:ratio
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "ratio" ;
rdfs:comment "Compression ratio." .
param:release
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "release" ;
rdfs:comment "The duration of an envelope release stage." .
param:resonance
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "resonance" ;
rdfs:comment "The resonance of a filter." .
param:sustain
a lv2:Parameter ;
rdfs:label "sustain" ;
rdfs:range atom:Float ;
rdfs:comment "The level of an envelope sustain stage as a factor." .
param:threshold
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "threshold" ;
rdfs:comment "Compression threshold." .
param:waveform
a lv2:Parameter ;
rdfs:range atom:Float ;
rdfs:label "waveform" ;
rdfs:comment """The waveform "fader" for oscillators or modulators that have several.""" .
param:gain
a lv2:Parameter ;
rdfs:range atom:Float ;
lv2:default 0.0 ;
lv2:minimum -20.0 ;
lv2:maximum 20.0 ;
units:unit units:db ;
rdfs:label "gain" ;
rdfs:comment "Gain in decibels." .
param:wetDryRatio
a lv2:Parameter ;
rdfs:label "wet/dry ratio" ;
rdfs:comment "The ratio between processed and bypassed levels in the output." .
param:wetLevel
a lv2:Parameter ;
rdfs:label "wet level" ;
rdfs:comment "The level of the processed component of a signal." .
param:dryLevel
a lv2:Parameter ;
rdfs:label "dry level" ;
rdfs:comment "The level of the unprocessed component of a signal." .
param:bypass
a lv2:Parameter ;
rdfs:label "bypass" ;
rdfs:comment "A boolean parameter that disables processing if true." .
param:sampleRate
a lv2:Parameter ;
rdfs:label "sample rate" ;
rdfs:comment "A sample rate in Hz." .
param:EnvelopeControls
a rdfs:Class ;
rdfs:subClassOf param:ControlGroup ;
rdfs:label "Envelope Controls" ;
rdfs:comment "Typical controls for a DAHDSR envelope." ;
pg:element [
lv2:index 0 ;
lv2:designation param:delay
] , [
lv2:index 1 ;
lv2:designation param:attack
] , [
lv2:index 2 ;
lv2:designation param:hold
] , [
lv2:index 3 ;
lv2:designation param:decay
] , [
lv2:index 4 ;
lv2:designation param:sustain
] , [
lv2:index 5 ;
lv2:designation param:release
] .
param:OscillatorControls
a rdfs:Class ;
rdfs:subClassOf param:ControlGroup ;
rdfs:label "Oscillator Controls" ;
rdfs:comment "Typical controls for an oscillator." ;
pg:element [
lv2:designation param:frequency
] , [
lv2:designation param:amplitude
] , [
lv2:designation param:waveform
] , [
lv2:designation param:pulseWidth
] .
param:FilterControls
a rdfs:Class ;
rdfs:subClassOf param:ControlGroup ;
rdfs:label "Filter Controls" ;
rdfs:comment "Typical controls for a filter." ;
pg:element [
lv2:designation param:cutoffFrequency
] , [
lv2:designation param:resonance
] .
param:CompressorControls
a rdfs:Class ;
rdfs:subClassOf param:ControlGroup ;
rdfs:label "Compressor Controls" ;
rdfs:comment "Typical controls for a compressor." ;
pg:element [
lv2:designation param:threshold
] , [
lv2:designation param:ratio
] .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/patch>
a lv2:Specification ;
lv2:minorVersion 2 ;
lv2:microVersion 8 ;
rdfs:seeAlso <patch.ttl> .

View File

@@ -0,0 +1,73 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_PATCH_H
#define LV2_PATCH_H
/**
@defgroup patch Patch
@ingroup lv2
Messages for accessing and manipulating properties.
Note the patch extension is purely data, this header merely defines URIs for
convenience.
See <http://lv2plug.in/ns/ext/patch> for details.
@{
*/
// clang-format off
#define LV2_PATCH_URI "http://lv2plug.in/ns/ext/patch" ///< http://lv2plug.in/ns/ext/patch
#define LV2_PATCH_PREFIX LV2_PATCH_URI "#" ///< http://lv2plug.in/ns/ext/patch#
#define LV2_PATCH__Ack LV2_PATCH_PREFIX "Ack" ///< http://lv2plug.in/ns/ext/patch#Ack
#define LV2_PATCH__Delete LV2_PATCH_PREFIX "Delete" ///< http://lv2plug.in/ns/ext/patch#Delete
#define LV2_PATCH__Copy LV2_PATCH_PREFIX "Copy" ///< http://lv2plug.in/ns/ext/patch#Copy
#define LV2_PATCH__Error LV2_PATCH_PREFIX "Error" ///< http://lv2plug.in/ns/ext/patch#Error
#define LV2_PATCH__Get LV2_PATCH_PREFIX "Get" ///< http://lv2plug.in/ns/ext/patch#Get
#define LV2_PATCH__Message LV2_PATCH_PREFIX "Message" ///< http://lv2plug.in/ns/ext/patch#Message
#define LV2_PATCH__Move LV2_PATCH_PREFIX "Move" ///< http://lv2plug.in/ns/ext/patch#Move
#define LV2_PATCH__Patch LV2_PATCH_PREFIX "Patch" ///< http://lv2plug.in/ns/ext/patch#Patch
#define LV2_PATCH__Post LV2_PATCH_PREFIX "Post" ///< http://lv2plug.in/ns/ext/patch#Post
#define LV2_PATCH__Put LV2_PATCH_PREFIX "Put" ///< http://lv2plug.in/ns/ext/patch#Put
#define LV2_PATCH__Request LV2_PATCH_PREFIX "Request" ///< http://lv2plug.in/ns/ext/patch#Request
#define LV2_PATCH__Response LV2_PATCH_PREFIX "Response" ///< http://lv2plug.in/ns/ext/patch#Response
#define LV2_PATCH__Set LV2_PATCH_PREFIX "Set" ///< http://lv2plug.in/ns/ext/patch#Set
#define LV2_PATCH__accept LV2_PATCH_PREFIX "accept" ///< http://lv2plug.in/ns/ext/patch#accept
#define LV2_PATCH__add LV2_PATCH_PREFIX "add" ///< http://lv2plug.in/ns/ext/patch#add
#define LV2_PATCH__body LV2_PATCH_PREFIX "body" ///< http://lv2plug.in/ns/ext/patch#body
#define LV2_PATCH__context LV2_PATCH_PREFIX "context" ///< http://lv2plug.in/ns/ext/patch#context
#define LV2_PATCH__destination LV2_PATCH_PREFIX "destination" ///< http://lv2plug.in/ns/ext/patch#destination
#define LV2_PATCH__property LV2_PATCH_PREFIX "property" ///< http://lv2plug.in/ns/ext/patch#property
#define LV2_PATCH__readable LV2_PATCH_PREFIX "readable" ///< http://lv2plug.in/ns/ext/patch#readable
#define LV2_PATCH__remove LV2_PATCH_PREFIX "remove" ///< http://lv2plug.in/ns/ext/patch#remove
#define LV2_PATCH__request LV2_PATCH_PREFIX "request" ///< http://lv2plug.in/ns/ext/patch#request
#define LV2_PATCH__subject LV2_PATCH_PREFIX "subject" ///< http://lv2plug.in/ns/ext/patch#subject
#define LV2_PATCH__sequenceNumber LV2_PATCH_PREFIX "sequenceNumber" ///< http://lv2plug.in/ns/ext/patch#sequenceNumber
#define LV2_PATCH__value LV2_PATCH_PREFIX "value" ///< http://lv2plug.in/ns/ext/patch#value
#define LV2_PATCH__wildcard LV2_PATCH_PREFIX "wildcard" ///< http://lv2plug.in/ns/ext/patch#wildcard
#define LV2_PATCH__writable LV2_PATCH_PREFIX "writable" ///< http://lv2plug.in/ns/ext/patch#writable
// clang-format on
/**
@}
*/
#endif /* LV2_PATCH_H */

View File

@@ -0,0 +1,374 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/patch>
a doap:Project ;
doap:created "2012-02-09" ;
doap:license <http://opensource.org/licenses/isc> ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:name "LV2 Patch" ;
doap:shortdesc "A protocol for accessing and manipulating properties." ;
doap:release [
doap:revision "2.8" ;
doap:created "2020-04-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.18.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Fix incorrect type of patch:sequenceNumber."
]
]
] , [
doap:revision "2.6" ;
doap:created "2019-02-03" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add patch:accept property."
] , [
rdfs:label "Add patch:context property."
]
]
] , [
doap:revision "2.4" ;
doap:created "2015-04-07" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.12.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Define patch:Get with no subject to implicitly apply to reciever. This can be used by UIs to get an initial description of a plugin."
] , [
rdfs:label "Add patch:Copy method."
]
]
] , [
doap:revision "2.2" ;
doap:created "2014-08-08" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add patch:sequenceNumber for associating replies with requests."
]
]
] , [
doap:revision "2.0" ;
doap:created "2013-01-10" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Make patch:Set a compact message for setting one property."
] , [
rdfs:label "Add patch:readable and patch:writable for describing available properties."
]
]
] , [
doap:revision "1.0" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This is a vocabulary for messages that access and manipulate properties.
It can be used as a dynamic control interface for plugins,
or anything else with a property-based model.
The key underlying concept here is to control things by manipulating arbitrary properties,
rather than by calling application-specific methods.
This allows implementations to understand what messages do
(at least in a mechanical sense),
which makes things like caching, proxying, or undo relatively straightforward to implement.
Note, however, that this is only conceptual:
there is no requirement to implement a general property store.
Typically, a plugin will understand a fixed set of properties that represent its parameters or other internal state, and ignore everything else.
This protocol is syntax-agnostic,
and [homoiconic](https://en.wikipedia.org/wiki/Homoiconicity)
in the sense that the messages use the same format as the data they manipulate.
In particular, messages can be serialised as a binary [Object](atom.html#Object) for realtime plugin control,
or as Turtle for saving to a file,
sending over a network,
printing for debugging purposes,
and so on.
This specification only defines a semantic protocol,
there is no corresponding API.
It can be used with the [Atom](atom.html) extension to control plugins which support message-based parameters as defined by the [Parameters](parameters.html) extension.
For example, if a plugin defines a `eg:volume` parameter, it can be controlled by the host by sending a patch:Set message to the plugin instance:
:::turtle
[
a patch:Set ;
patch:property eg:volume ;
patch:value 11.0 ;
]
Similarly, the host could get the current value for this parameter by sending a patch:Get message:
:::turtle
[
a patch:Get ;
patch:property eg:volume ;
]
The plugin would then respond with the same patch:Set message as above.
In this case, the plugin instance is implicitly the patch:subject,
but a specific subject can also be given for deeper control.
"""^^lv2:Markdown .
patch:Copy
lv2:documentation """
After this, the destination has the same description as the subject,
and the subject is unchanged.
It is an error if the subject does not exist,
or if the destination already exists.
Multiple subjects may be given if the destination is a container,
but the semantics of this case are application-defined.
"""^^lv2:Markdown .
patch:Get
lv2:documentation """
If a patch:property is given,
then the receiver should respond with a patch:Set message that gives only that property.
Otherwise, it should respond with a [concise bounded description](http://www.w3.org/Submission/CBD/) in a patch:Put message,
that is, a description that recursively includes any blank node values.
If a patch:subject is given, then the response should have the same subject.
If no subject is given, then the receiver is implicitly the subject.
If a patch:request node or a patch:sequenceNumber is given,
then the response should be a patch:Response and have the same property.
If neither is given, then the receiver can respond with a simple patch:Put message.
For example:
:::turtle
[]
a patch:Get ;
patch:subject eg:something .
Could result in:
:::turtle
[]
a patch:Put ;
patch:subject eg:something ;
patch:body [
eg:name "Something" ;
eg:ratio 1.6180339887 ;
] .
"""^^lv2:Markdown .
patch:Insert
lv2:documentation """
If the subject does not exist, it is created. If the subject does already
exist, it is added to.
This request only adds properties, it never removes them. The user must take
care that multiple values are not set for properties which should only have
one.
"""^^lv2:Markdown .
patch:Message
lv2:documentation """
This is an abstract base class for all patch messages. Concrete messages are
either a patch:Request or a patch:Response.
"""^^lv2:Markdown .
patch:Move
lv2:documentation """
After this, the destination has the description that the subject had, and the
subject no longer exists.
It is an error if the subject does not exist, or if the destination already
exists.
"""^^lv2:Markdown .
patch:Patch
lv2:documentation """
This method always has at least one subject, and exactly one patch:add and
patch:remove property. The value of patch:add and patch:remove are nodes which
have the properties to add or remove from the subject(s), respectively. The
special value patch:wildcard may be used as the value of a remove property to
remove all properties with the given predicate. For example:
:::turtle
[]
a patch:Patch ;
patch:subject <something> ;
patch:add [
eg:name "New name" ;
eg:age 42 ;
] ;
patch:remove [
eg:name "Old name" ;
eg:age patch:wildcard ; # Remove all old eg:age properties
] .
"""^^lv2:Markdown .
patch:Put
lv2:documentation """
If the subject does not already exist, it is created. If the subject does
already exist, the patch:body is considered an updated version of it, and the
previous version is replaced.
:::turtle
[]
a patch:Put ;
patch:subject <something> ;
patch:body [
eg:name "New name" ;
eg:age 42 ;
] .
"""^^lv2:Markdown .
patch:Request
a rdfs:Class ;
rdfs:label "Request" ;
rdfs:subClassOf patch:Message ;
lv2:documentation """
A request may have a patch:subject property, which specifies the resource that
the request applies to. The subject may be omitted in contexts where it is
implicit, for example if the recipient is the subject.
"""^^lv2:Markdown .
patch:Set
lv2:documentation """
This is equivalent to a patch:Patch which removes _all_ pre-existing values for
the property before setting the new value. For example:
:::turtle
[]
a patch:Set ;
patch:subject <something> ;
patch:property eg:name ;
patch:value "New name" .
Which is equivalent to:
:::turtle
[]
a patch:Patch ;
patch:subject <something> ;
patch:add [
eg:name "New name" ;
] ;
patch:remove [
eg:name patch:wildcard ;
] .
"""^^lv2:Markdown .
patch:body
lv2:documentation """
The details of this property's value depend on the type of message it is a part
of.
"""^^lv2:Markdown .
patch:context
lv2:documentation """
For example, a plugin may have a special context for ephemeral properties which
are only relevant during the lifetime of the instance and should not be saved
in state.
The specific uses for contexts are application specific. However, the context
MUST be a URI, and can be interpreted as the ID of a data model where
properties should be stored. Implementations MAY have special support for
contexts, for example by storing in a quad store or serializing to a format
that supports multiple RDF graphs such as TriG.
"""^^lv2:Markdown .
patch:readable
lv2:documentation """
See the similar patch:writable property for details.
"""^^lv2:Markdown .
patch:request
lv2:documentation """
This can be used if referring directly to the URI or blank node ID of the
request is possible. Otherwise, use patch:sequenceNumber.
"""^^lv2:Markdown .
patch:sequenceNumber
lv2:documentation """
This property is used to associate replies with requests when it is not
feasible to refer to request URIs with patch:request. A patch:Response with a
given sequence number is the reply to the previously send patch:Request with
the same sequence number.
The special sequence number 0 means that no reply is desired.
"""^^lv2:Markdown .
patch:wildcard
lv2:documentation """
This makes it possible to describe the removal of all values for a given
property.
"""^^lv2:Markdown .
patch:writable
lv2:documentation """
This is used to list properties that can be changed, for example to allow user
interfaces to present appropriate controls. For example:
:::turtle
@prefix eg: <http://example.org/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
eg:title
a rdf:Property ;
rdfs:label "title" ;
rdfs:range xsd:string .
eg:plugin
patch:writable eg:title .
"""^^lv2:Markdown .

View File

@@ -0,0 +1,251 @@
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/patch>
a owl:Ontology ;
rdfs:seeAlso <patch.h> ,
<patch.meta.ttl> ;
rdfs:label "LV2 Patch" ;
rdfs:comment "A protocol for accessing and manipulating properties." .
patch:Ack
a rdfs:Class ;
rdfs:subClassOf patch:Response ;
rdfs:label "Ack" ;
rdfs:comment "An acknowledgement that a request was successful." .
patch:Copy
a rdfs:Class ;
rdfs:subClassOf patch:Request ;
rdfs:label "Copy" ;
rdfs:subClassOf [
a owl:Restriction ;
owl:minCardinality 1 ;
owl:onProperty patch:subject
] , [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:destination
] ;
rdfs:comment "A request to copy the patch:subject to the patch:destination." .
patch:Delete
a rdfs:Class ;
rdfs:subClassOf patch:Request ;
rdfs:label "Delete" ;
rdfs:comment "Request that the patch:subject or subjects be deleted." .
patch:Error
a rdfs:Class ;
rdfs:subClassOf patch:Response ;
rdfs:label "Error" ;
rdfs:comment "A response indicating an error processing a request." .
patch:Get
a rdfs:Class ;
rdfs:subClassOf patch:Request ;
rdfs:label "Get" ;
rdfs:comment "A request for a description of the patch:subject." .
patch:Insert
a rdfs:Class ;
rdfs:subClassOf patch:Request ;
rdfs:label "Insert" ;
rdfs:subClassOf [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:subject
] ;
rdfs:comment "A request to insert a patch:body into the patch:subject." .
patch:Message
a rdfs:Class ;
rdfs:label "Patch Message" ;
rdfs:comment "A patch message." .
patch:Move
a rdfs:Class ;
rdfs:subClassOf patch:Request ;
rdfs:label "Move" ;
rdfs:subClassOf [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:subject
] , [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:destination
] ;
rdfs:comment "A request to move the patch:subject to the patch:destination." .
patch:Patch
a rdfs:Class ;
rdfs:subClassOf patch:Request ,
[
a owl:Restriction ;
owl:minCardinality 1 ;
owl:onProperty patch:subject
] , [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:add
] , [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:remove
] ;
rdfs:label "Patch" ;
rdfs:comment "A request to add and/or remove properties of the patch:subject." .
patch:Put
a rdfs:Class ;
rdfs:subClassOf patch:Request ;
rdfs:label "Put" ;
rdfs:subClassOf [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:subject
] ;
rdfs:comment "A request to put the patch:body as the patch:subject." .
patch:Request
a rdfs:Class ;
rdfs:label "Request" ;
rdfs:subClassOf patch:Message ;
rdfs:comment "A patch request message." .
patch:Response
a rdfs:Class ;
rdfs:subClassOf patch:Message ;
rdfs:label "Response" ;
rdfs:comment "A response to a patch:Request." .
patch:Set
a rdfs:Class ;
rdfs:label "Set" ;
rdfs:subClassOf patch:Request ,
[
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:property
] , [
a owl:Restriction ;
owl:cardinality 1 ;
owl:onProperty patch:value
] ;
rdfs:comment "A compact request to set a property to a value." .
patch:accept
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "accept" ;
rdfs:domain patch:Request ;
rdfs:range rdfs:Class ;
rdfs:comment "An accepted type for a response." .
patch:add
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain patch:Patch ;
rdfs:range rdfs:Resource ;
rdfs:label "add" ;
rdfs:comment "The properties to add to the subject." .
patch:body
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain patch:Message ;
rdfs:label "body" ;
rdfs:comment "The body of a message." .
patch:context
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain patch:Message ;
rdfs:label "context" ;
rdfs:comment "The context of properties in this message." .
patch:destination
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain patch:Message ;
rdfs:label "destination" ;
rdfs:comment "The destination to move the patch:subject to." .
patch:property
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "property" ;
rdfs:domain patch:Message ;
rdfs:range rdf:Property ;
rdfs:comment "The property for a patch:Set or patch:Get message." .
patch:readable
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "readable" ;
rdfs:range rdf:Property ;
rdfs:comment "A property that can be read with a patch:Get message." .
patch:remove
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:label "remove" ;
rdfs:domain patch:Patch ;
rdfs:range rdfs:Resource ;
rdfs:comment "The properties to remove from the subject." .
patch:request
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:label "request" ;
rdfs:domain patch:Response ;
rdfs:range patch:Request ;
rdfs:comment "The request this is a response to." .
patch:sequenceNumber
a rdf:Property ,
owl:DatatypeProperty ,
owl:FunctionalProperty ;
rdfs:label "sequence number" ;
rdfs:domain patch:Message ;
rdfs:range xsd:int ;
rdfs:comment "The sequence number of a request or response." .
patch:subject
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain patch:Message ;
rdfs:label "subject" ;
rdfs:comment "The subject this message applies to." .
patch:value
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:label "value" ;
rdfs:domain patch:Set ;
rdfs:range rdf:Property ;
rdfs:comment "The value of a property in a patch:Set message." .
patch:wildcard
a rdfs:Resource ;
rdfs:label "wildcard" ;
rdfs:comment "A wildcard that matches any resource." .
patch:writable
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "writable" ;
rdfs:range rdf:Property ;
rdfs:comment "A property that can be set with a patch:Set or patch:Patch message." .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/port-groups>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 4 ;
rdfs:seeAlso <port-groups.ttl> .

View File

@@ -0,0 +1,77 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_PORT_GROUPS_H
#define LV2_PORT_GROUPS_H
/**
@defgroup port-groups Port Groups
@ingroup lv2
Multi-channel groups of LV2 ports.
See <http://lv2plug.in/ns/ext/port-groups> for details.
@{
*/
// clang-format off
#define LV2_PORT_GROUPS_URI "http://lv2plug.in/ns/ext/port-groups" ///< http://lv2plug.in/ns/ext/port-groups
#define LV2_PORT_GROUPS_PREFIX LV2_PORT_GROUPS_URI "#" ///< http://lv2plug.in/ns/ext/port-groups#
#define LV2_PORT_GROUPS__DiscreteGroup LV2_PORT_GROUPS_PREFIX "DiscreteGroup" ///< http://lv2plug.in/ns/ext/port-groups#DiscreteGroup
#define LV2_PORT_GROUPS__Element LV2_PORT_GROUPS_PREFIX "Element" ///< http://lv2plug.in/ns/ext/port-groups#Element
#define LV2_PORT_GROUPS__FivePointOneGroup LV2_PORT_GROUPS_PREFIX "FivePointOneGroup" ///< http://lv2plug.in/ns/ext/port-groups#FivePointOneGroup
#define LV2_PORT_GROUPS__FivePointZeroGroup LV2_PORT_GROUPS_PREFIX "FivePointZeroGroup" ///< http://lv2plug.in/ns/ext/port-groups#FivePointZeroGroup
#define LV2_PORT_GROUPS__FourPointZeroGroup LV2_PORT_GROUPS_PREFIX "FourPointZeroGroup" ///< http://lv2plug.in/ns/ext/port-groups#FourPointZeroGroup
#define LV2_PORT_GROUPS__Group LV2_PORT_GROUPS_PREFIX "Group" ///< http://lv2plug.in/ns/ext/port-groups#Group
#define LV2_PORT_GROUPS__InputGroup LV2_PORT_GROUPS_PREFIX "InputGroup" ///< http://lv2plug.in/ns/ext/port-groups#InputGroup
#define LV2_PORT_GROUPS__MidSideGroup LV2_PORT_GROUPS_PREFIX "MidSideGroup" ///< http://lv2plug.in/ns/ext/port-groups#MidSideGroup
#define LV2_PORT_GROUPS__MonoGroup LV2_PORT_GROUPS_PREFIX "MonoGroup" ///< http://lv2plug.in/ns/ext/port-groups#MonoGroup
#define LV2_PORT_GROUPS__OutputGroup LV2_PORT_GROUPS_PREFIX "OutputGroup" ///< http://lv2plug.in/ns/ext/port-groups#OutputGroup
#define LV2_PORT_GROUPS__SevenPointOneGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneGroup" ///< http://lv2plug.in/ns/ext/port-groups#SevenPointOneGroup
#define LV2_PORT_GROUPS__SevenPointOneWideGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneWideGroup" ///< http://lv2plug.in/ns/ext/port-groups#SevenPointOneWideGroup
#define LV2_PORT_GROUPS__SixPointOneGroup LV2_PORT_GROUPS_PREFIX "SixPointOneGroup" ///< http://lv2plug.in/ns/ext/port-groups#SixPointOneGroup
#define LV2_PORT_GROUPS__StereoGroup LV2_PORT_GROUPS_PREFIX "StereoGroup" ///< http://lv2plug.in/ns/ext/port-groups#StereoGroup
#define LV2_PORT_GROUPS__ThreePointZeroGroup LV2_PORT_GROUPS_PREFIX "ThreePointZeroGroup" ///< http://lv2plug.in/ns/ext/port-groups#ThreePointZeroGroup
#define LV2_PORT_GROUPS__center LV2_PORT_GROUPS_PREFIX "center" ///< http://lv2plug.in/ns/ext/port-groups#center
#define LV2_PORT_GROUPS__centerLeft LV2_PORT_GROUPS_PREFIX "centerLeft" ///< http://lv2plug.in/ns/ext/port-groups#centerLeft
#define LV2_PORT_GROUPS__centerRight LV2_PORT_GROUPS_PREFIX "centerRight" ///< http://lv2plug.in/ns/ext/port-groups#centerRight
#define LV2_PORT_GROUPS__element LV2_PORT_GROUPS_PREFIX "element" ///< http://lv2plug.in/ns/ext/port-groups#element
#define LV2_PORT_GROUPS__group LV2_PORT_GROUPS_PREFIX "group" ///< http://lv2plug.in/ns/ext/port-groups#group
#define LV2_PORT_GROUPS__left LV2_PORT_GROUPS_PREFIX "left" ///< http://lv2plug.in/ns/ext/port-groups#left
#define LV2_PORT_GROUPS__lowFrequencyEffects LV2_PORT_GROUPS_PREFIX "lowFrequencyEffects" ///< http://lv2plug.in/ns/ext/port-groups#lowFrequencyEffects
#define LV2_PORT_GROUPS__mainInput LV2_PORT_GROUPS_PREFIX "mainInput" ///< http://lv2plug.in/ns/ext/port-groups#mainInput
#define LV2_PORT_GROUPS__mainOutput LV2_PORT_GROUPS_PREFIX "mainOutput" ///< http://lv2plug.in/ns/ext/port-groups#mainOutput
#define LV2_PORT_GROUPS__rearCenter LV2_PORT_GROUPS_PREFIX "rearCenter" ///< http://lv2plug.in/ns/ext/port-groups#rearCenter
#define LV2_PORT_GROUPS__rearLeft LV2_PORT_GROUPS_PREFIX "rearLeft" ///< http://lv2plug.in/ns/ext/port-groups#rearLeft
#define LV2_PORT_GROUPS__rearRight LV2_PORT_GROUPS_PREFIX "rearRight" ///< http://lv2plug.in/ns/ext/port-groups#rearRight
#define LV2_PORT_GROUPS__right LV2_PORT_GROUPS_PREFIX "right" ///< http://lv2plug.in/ns/ext/port-groups#right
#define LV2_PORT_GROUPS__side LV2_PORT_GROUPS_PREFIX "side" ///< http://lv2plug.in/ns/ext/port-groups#side
#define LV2_PORT_GROUPS__sideChainOf LV2_PORT_GROUPS_PREFIX "sideChainOf" ///< http://lv2plug.in/ns/ext/port-groups#sideChainOf
#define LV2_PORT_GROUPS__sideLeft LV2_PORT_GROUPS_PREFIX "sideLeft" ///< http://lv2plug.in/ns/ext/port-groups#sideLeft
#define LV2_PORT_GROUPS__sideRight LV2_PORT_GROUPS_PREFIX "sideRight" ///< http://lv2plug.in/ns/ext/port-groups#sideRight
#define LV2_PORT_GROUPS__source LV2_PORT_GROUPS_PREFIX "source" ///< http://lv2plug.in/ns/ext/port-groups#source
#define LV2_PORT_GROUPS__subGroupOf LV2_PORT_GROUPS_PREFIX "subGroupOf" ///< http://lv2plug.in/ns/ext/port-groups#subGroupOf
// clang-format on
/**
@}
*/
#endif /* LV2_PORT_GROUPS_H */

View File

@@ -0,0 +1,144 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/port-groups>
a doap:Project ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2 Port Groups" ;
doap:shortdesc "Multi-channel groups of LV2 ports." ;
doap:created "2008-00-00" ;
doap:developer <http://lv2plug.in/ns/meta#larsl> ,
<http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "1.4" ;
doap:created "2020-04-26" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.18.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Replace broken links with detailed Ambisonic channel descriptions."
] , [
rdfs:label "Remove incorrect type of pg:letterCode."
]
]
] , [
doap:revision "1.2" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Use consistent label style."
]
]
] , [
doap:revision "1.0" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] .
pg:Group
lv2:documentation """
A group logically combines ports which should be considered part of the same
stream. For example, two audio ports in a group may form a stereo stream.
Like ports, groups have a lv2:symbol that is unique within the context of the
plugin, where group symbols and port symbols reside in the same namespace. In
other words, a group on a plugin MUST NOT have the same symbol as any other
group or port on that plugin. This makes it possible to uniquely reference a
port or group on a plugin with a single identifier and no context.
Group definitions may be shared across plugins for brevity. For example, a
plugin collection may define a single URI for a pg:StereoGroup with the symbol
"input" and use it in many plugins.
"""^^lv2:Markdown .
pg:sideChainOf
lv2:documentation """
Indicates that this port or group should be considered a "side chain" of some
other port or group. The precise definition of "side chain" depends on the
plugin, but in general this group should be considered a modifier to some other
group, rather than an independent input itself.
"""^^lv2:Markdown .
pg:subGroupOf
lv2:documentation """
Indicates that this group is a child of another group. This property has no
meaning with respect to plugin execution, but the host may find this
information useful to provide a better user interface. Note that being a
sub-group does not relax the restriction that the group MUST have a unique
symbol with respect to the plugin.
"""^^lv2:Markdown .
pg:source
lv2:documentation """
Indicates that this port or group should be considered the "result" of some
other port or group. This property only makes sense on groups with outputs
when the source is a group with inputs. This can be used to convey a
relationship between corresponding input and output groups with different
types, for example in a mono to stereo plugin.
"""^^lv2:Markdown .
pg:mainInput
lv2:documentation """
Indicates that this group should be considered the "main" input, i.e. the
primary task is processing the signal in this group. A plugin MUST NOT have
more than one pg:mainInput property.
"""^^lv2:Markdown .
pg:mainOutput
lv2:documentation """
Indicates that this group should be considered the "main" output. The main
output group SHOULD have the main input group as a pg:source.
"""^^lv2:Markdown .
pg:group
lv2:documentation """
Indicates that this port is a part of a group of ports on the plugin. The port
should also have an lv2:designation property to define its designation within
that group.
"""^^lv2:Markdown .
pg:DiscreteGroup
lv2:documentation """
These groups are divided into channels where each represents a particular
speaker location. The position of sound in one of these groups depends on a
particular speaker configuration.
"""^^lv2:Markdown .
pg:AmbisonicGroup
lv2:documentation """
These groups are divided into channels which together represent a position in
an abstract n-dimensional space. The position of sound in one of these groups
does not depend on a particular speaker configuration; a decoder can be used to
convert an ambisonic stream for any speaker configuration.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,807 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/port-groups>
a owl:Ontology ;
rdfs:label "LV2 Port Groups" ;
rdfs:comment "Multi-channel groups of LV2 ports." ;
rdfs:seeAlso <port-groups.meta.ttl> .
pg:Group
a rdfs:Class ;
rdfs:label "Port Group" ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty lv2:symbol ;
owl:cardinality 1 ;
rdfs:comment "A Group MUST have exactly one string lv2:symbol."
] ;
rdfs:comment "A set of ports that are logicaly grouped together." .
pg:InputGroup
a rdfs:Class ;
rdfs:subClassOf pg:Group ;
rdfs:label "Input Group" ;
rdfs:comment "A group which contains exclusively inputs." .
pg:OutputGroup
a rdfs:Class ;
rdfs:subClassOf pg:Group ;
rdfs:label "Output Group" ;
rdfs:comment "A group which contains exclusively outputs." .
pg:Element
a rdfs:Class ;
rdfs:label "Element" ;
rdfs:comment "An ordered element of a group." ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty lv2:designation ;
owl:cardinality 1 ;
rdfs:comment "An element MUST have exactly one lv2:designation."
] ;
rdfs:comment "An element of a group, with a designation and optional index." .
pg:element
a rdf:Property ,
owl:ObjectProperty ;
rdfs:range pg:Element ;
rdfs:label "element" ;
rdfs:comment "An element within a port group." .
pg:sideChainOf
a rdf:Property ,
owl:ObjectProperty ;
rdfs:label "side-chain of" ;
rdfs:comment "Port or group is a side chain of another." .
pg:subGroupOf
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain pg:Group ;
rdfs:range pg:Group ;
rdfs:label "sub-group of" ;
rdfs:comment "Group is a child of another group." .
pg:source
a rdf:Property ,
owl:ObjectProperty ;
rdfs:domain pg:OutputGroup ;
rdfs:range pg:InputGroup ;
rdfs:label "source" ;
rdfs:comment "Port or group that this group is the output of." .
pg:mainInput
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain lv2:Plugin ;
rdfs:range pg:InputGroup ;
rdfs:label "main input" ;
rdfs:comment "Input group that is the primary input of the plugin." .
pg:mainOutput
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain lv2:Plugin ;
rdfs:range pg:OutputGroup ;
rdfs:label "main output" ;
rdfs:comment "Output group that is the primary output of the plugin." .
pg:group
a rdf:Property ,
owl:ObjectProperty ,
owl:FunctionalProperty ;
rdfs:domain lv2:Port ;
rdfs:range pg:Group ;
rdfs:label "group" ;
rdfs:comment "Group that this port is a part of." .
pg:DiscreteGroup
a rdfs:Class ;
rdfs:subClassOf pg:Group ;
rdfs:label "Discrete Group" ;
rdfs:comment "A group of discrete channels." .
pg:left
a lv2:Channel ;
rdfs:label "left" ;
rdfs:comment "The left channel of a stereo audio group." .
pg:right
a lv2:Channel ;
rdfs:label "right" ;
rdfs:comment "The right channel of a stereo audio group." .
pg:center
a lv2:Channel ;
rdfs:label "center" ;
rdfs:comment "The center channel of a discrete audio group." .
pg:side
a lv2:Channel ;
rdfs:label "side" ;
rdfs:comment "The side channel of a mid-side audio group." .
pg:centerLeft
a lv2:Channel ;
rdfs:label "center left" ;
rdfs:comment "The center-left channel of a 7.1 wide surround sound group." .
pg:centerRight
a lv2:Channel ;
rdfs:label "center right" ;
rdfs:comment "The center-right channel of a 7.1 wide surround sound group." .
pg:sideLeft
a lv2:Channel ;
rdfs:label "side left" ;
rdfs:comment "The side-left channel of a 6.1 or 7.1 surround sound group." .
pg:sideRight
a lv2:Channel ;
rdfs:label "side right" ;
rdfs:comment "The side-right channel of a 6.1 or 7.1 surround sound group." .
pg:rearLeft
a lv2:Channel ;
rdfs:label "rear left" ;
rdfs:comment "The rear-left channel of a surround sound group." .
pg:rearRight
a lv2:Channel ;
rdfs:label "rear right" ;
rdfs:comment "The rear-right channel of a surround sound group." .
pg:rearCenter
a lv2:Channel ;
rdfs:label "rear center" ;
rdfs:comment "The rear-center channel of a surround sound group." .
pg:lowFrequencyEffects
a lv2:Channel ;
rdfs:label "low-frequency effects" ;
rdfs:comment "The LFE channel of a *.1 surround sound group." .
pg:MonoGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "Mono" ;
rdfs:comment "A single channel audio group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:center
] .
pg:StereoGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "Stereo" ;
rdfs:comment "A 2-channel discrete stereo audio group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:right
] .
pg:MidSideGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "Mid-Side Stereo" ;
rdfs:comment "A 2-channel mid-side stereo audio group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:center
] , [
lv2:index 1 ;
lv2:designation pg:side
] .
pg:ThreePointZeroGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "3.0 Surround" ;
rdfs:comment "A 3.0 discrete surround sound group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:right
] , [
lv2:index 2 ;
lv2:designation pg:rearCenter
] .
pg:FourPointZeroGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "4.0 Surround" ;
rdfs:comment "A 4.0 (Quadraphonic) discrete surround sound group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:center
] , [
lv2:index 2 ;
lv2:designation pg:right
] , [
lv2:index 3 ;
lv2:designation pg:rearCenter
] .
pg:FivePointZeroGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "5.0 Surround" ;
rdfs:comment "A 5.0 (3-2 stereo) discrete surround sound group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:center
] , [
lv2:index 2 ;
lv2:designation pg:right
] , [
lv2:index 3 ;
lv2:designation pg:rearLeft
] , [
lv2:index 4 ;
lv2:designation pg:rearRight
] .
pg:FivePointOneGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "5.1 Surround" ;
rdfs:comment "A 5.1 (3-2 stereo with sub) discrete surround sound group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:center
] , [
lv2:index 2 ;
lv2:designation pg:right
] , [
lv2:index 3 ;
lv2:designation pg:rearLeft
] , [
lv2:index 4 ;
lv2:designation pg:rearRight
] , [
lv2:index 5 ;
lv2:designation pg:lowFrequencyEffects
] .
pg:SixPointOneGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "6.1 Surround" ;
rdfs:comment "A 6.1 discrete surround sound group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:center
] , [
lv2:index 2 ;
lv2:designation pg:right
] , [
lv2:index 3 ;
lv2:designation pg:sideLeft
] , [
lv2:index 4 ;
lv2:designation pg:sideRight
] , [
lv2:index 5 ;
lv2:designation pg:rearCenter
] , [
lv2:index 6 ;
lv2:designation pg:lowFrequencyEffects
] .
pg:SevenPointOneGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "7.1 Surround" ;
rdfs:comment "A 7.1 discrete surround sound group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:center
] , [
lv2:index 2 ;
lv2:designation pg:right
] , [
lv2:index 3 ;
lv2:designation pg:sideLeft
] , [
lv2:index 4 ;
lv2:designation pg:sideRight
] , [
lv2:index 5 ;
lv2:designation pg:rearLeft
] , [
lv2:index 6 ;
lv2:designation pg:rearRight
] , [
lv2:index 7 ;
lv2:designation pg:lowFrequencyEffects
] .
pg:SevenPointOneWideGroup
a rdfs:Class ;
rdfs:subClassOf pg:DiscreteGroup ;
rdfs:label "7.1 Surround (Wide)" ;
rdfs:comment "A 7.1 wide discrete surround sound group." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:left
] , [
lv2:index 1 ;
lv2:designation pg:centerLeft
] , [
lv2:index 2 ;
lv2:designation pg:center
] , [
lv2:index 3 ;
lv2:designation pg:centerRight
] , [
lv2:index 4 ;
lv2:designation pg:right
] , [
lv2:index 5 ;
lv2:designation pg:rearLeft
] , [
lv2:index 6 ;
lv2:designation pg:rearRight
] , [
lv2:index 7 ;
lv2:designation pg:lowFrequencyEffects
] .
pg:letterCode
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:domain lv2:Channel ;
rdfs:range rdf:PlainLiteral ;
rdfs:label "ambisonic letter code" ;
rdfs:comment "The YuMa letter code for an Ambisonic channel." .
pg:harmonicDegree
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:domain lv2:Channel ;
rdfs:range xsd:integer ;
rdfs:label "harmonic degree" ;
rdfs:comment "The degree coefficient (l) of the spherical harmonic for an Ambisonic channel." .
pg:harmonicIndex
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:domain lv2:Channel ;
rdfs:range xsd:integer ;
rdfs:label "harmonic index" ;
rdfs:comment "The index coefficient (m) of the spherical harmonic for an Ambisonic channel." .
pg:ACN0
a lv2:Channel ;
pg:letterCode "W" ;
pg:harmonicDegree 0 ;
pg:harmonicIndex 0 ;
rdfs:label "ACN0" ;
rdfs:comment "Ambisonic channel 0 (W): degree 0, index 0." .
pg:ACN1
a lv2:Channel ;
pg:letterCode "Y" ;
pg:harmonicDegree 1 ;
pg:harmonicIndex -1 ;
rdfs:label "ACN1" ;
rdfs:comment "Ambisonic channel 1 (Y): degree 1, index -1." .
pg:ACN2
a lv2:Channel ;
pg:letterCode "Z" ;
pg:harmonicDegree 1 ;
pg:harmonicIndex 0 ;
rdfs:label "ACN2" ;
rdfs:comment "Ambisonic channel 2 (Z): degree 1, index 0." .
pg:ACN3
a lv2:Channel ;
pg:letterCode "X" ;
pg:harmonicDegree 1 ;
pg:harmonicIndex 1 ;
rdfs:label "ACN3" ;
rdfs:comment "Ambisonic channel 3 (X): degree 1, index 1." .
pg:ACN4
a lv2:Channel ;
pg:letterCode "V" ;
pg:harmonicDegree 2 ;
pg:harmonicIndex -2 ;
rdfs:label "ACN4" ;
rdfs:comment "Ambisonic channel 4 (V): degree 2, index -2." .
pg:ACN5
a lv2:Channel ;
pg:letterCode "T" ;
pg:harmonicDegree 2 ;
pg:harmonicIndex -1 ;
rdfs:label "ACN5" ;
rdfs:comment "Ambisonic channel 5 (T): degree 2, index -1." .
pg:ACN6
a lv2:Channel ;
pg:letterCode "R" ;
pg:harmonicDegree 2 ;
pg:harmonicIndex 0 ;
rdfs:label "ACN6" ;
rdfs:comment "Ambisonic channel 6 (R): degree 2, index 0." .
pg:ACN7
a lv2:Channel ;
pg:letterCode "S" ;
pg:harmonicDegree 2 ;
pg:harmonicIndex 1 ;
rdfs:label "ACN7" ;
rdfs:comment "Ambisonic channel 7 (S): degree 2, index 1." .
pg:ACN8
a lv2:Channel ;
pg:letterCode "U" ;
pg:harmonicDegree 2 ;
pg:harmonicIndex 2 ;
rdfs:label "ACN8" ;
rdfs:comment "Ambisonic channel 8 (U): degree 2, index 2." .
pg:ACN9
a lv2:Channel ;
pg:letterCode "Q" ;
pg:harmonicDegree 3 ;
pg:harmonicIndex -3 ;
rdfs:label "ACN9" ;
rdfs:comment "Ambisonic channel 9 (Q): degree 3, index -3." .
pg:ACN10
a lv2:Channel ;
pg:letterCode "O" ;
pg:harmonicDegree 3 ;
pg:harmonicIndex -2 ;
rdfs:label "ACN10" ;
rdfs:comment "Ambisonic channel 10 (O): degree 3, index -2." .
pg:ACN11
a lv2:Channel ;
pg:letterCode "M" ;
pg:harmonicDegree 3 ;
pg:harmonicIndex -1 ;
rdfs:label "ACN11" ;
rdfs:comment "Ambisonic channel 11 (M): degree 3, index -1." .
pg:ACN12
a lv2:Channel ;
pg:letterCode "K" ;
pg:harmonicDegree 3 ;
pg:harmonicIndex 0 ;
rdfs:label "ACN12" ;
rdfs:comment "Ambisonic channel 12 (K): degree 3, index 0." .
pg:ACN13
a lv2:Channel ;
pg:letterCode "L" ;
pg:harmonicDegree 3 ;
pg:harmonicIndex 1 ;
rdfs:label "ACN13" ;
rdfs:comment "Ambisonic channel 13 (L): degree 3, index 1." .
pg:ACN14
a lv2:Channel ;
pg:letterCode "N" ;
pg:harmonicDegree 3 ;
pg:harmonicIndex 2 ;
rdfs:label "ACN14" ;
rdfs:comment "Ambisonic channel 14 (N): degree 3, index 2." .
pg:ACN15
a lv2:Channel ;
pg:letterCode "P" ;
pg:harmonicDegree 3 ;
pg:harmonicIndex 3 ;
rdfs:label "ACN15" ;
rdfs:comment "Ambisonic channel 15 (P): degree 3, index 3." .
pg:AmbisonicGroup
a rdfs:Class ;
rdfs:subClassOf pg:Group ;
rdfs:label "Ambisonic Group" ;
rdfs:comment "A group of Ambisonic channels." .
pg:AmbisonicBH1P0Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH1P0" ;
rdfs:comment "Ambisonic B stream of horizontal order 1 and peripheral order 0." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN3
] .
pg:AmbisonicBH1P1Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH1P1" ;
rdfs:comment "Ambisonic B stream of horizontal order 1 and peripheral order 1." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN2
] , [
lv2:index 3 ;
lv2:designation pg:ACN3
] .
pg:AmbisonicBH2P0Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH2P0" ;
rdfs:comment "Ambisonic B stream of horizontal order 2 and peripheral order 0." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN3
] , [
lv2:index 3 ;
lv2:designation pg:ACN4
] , [
lv2:index 4 ;
lv2:designation pg:ACN8
] .
pg:AmbisonicBH2P1Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH2P1" ;
rdfs:comment "Ambisonic B stream of horizontal order 2 and peripheral order 1." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN2
] , [
lv2:index 3 ;
lv2:designation pg:ACN3
] , [
lv2:index 4 ;
lv2:designation pg:ACN4
] , [
lv2:index 5 ;
lv2:designation pg:ACN8
] .
pg:AmbisonicBH2P2Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH2P2" ;
rdfs:comment "Ambisonic B stream of horizontal order 2 and peripheral order 2." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN2
] , [
lv2:index 3 ;
lv2:designation pg:ACN3
] , [
lv2:index 4 ;
lv2:designation pg:ACN4
] , [
lv2:index 5 ;
lv2:designation pg:ACN5
] , [
lv2:index 6 ;
lv2:designation pg:ACN6
] , [
lv2:index 7 ;
lv2:designation pg:ACN7
] , [
lv2:index 8 ;
lv2:designation pg:ACN8
] .
pg:AmbisonicBH3P0Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH3P0" ;
rdfs:comment "Ambisonic B stream of horizontal order 3 and peripheral order 0." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN3
] , [
lv2:index 3 ;
lv2:designation pg:ACN4
] , [
lv2:index 4 ;
lv2:designation pg:ACN8
] , [
lv2:index 5 ;
lv2:designation pg:ACN9
] , [
lv2:index 6 ;
lv2:designation pg:ACN15
] .
pg:AmbisonicBH3P1Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH3P1" ;
rdfs:comment "Ambisonic B stream of horizontal order 3 and peripheral order 1." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN2
] , [
lv2:index 3 ;
lv2:designation pg:ACN3
] , [
lv2:index 4 ;
lv2:designation pg:ACN4
] , [
lv2:index 5 ;
lv2:designation pg:ACN8
] , [
lv2:index 6 ;
lv2:designation pg:ACN9
] , [
lv2:index 7 ;
lv2:designation pg:ACN15
] .
pg:AmbisonicBH3P2Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH3P2" ;
rdfs:comment "Ambisonic B stream of horizontal order 3 and peripheral order 2." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN2
] , [
lv2:index 3 ;
lv2:designation pg:ACN3
] , [
lv2:index 4 ;
lv2:designation pg:ACN4
] , [
lv2:index 5 ;
lv2:designation pg:ACN5
] , [
lv2:index 6 ;
lv2:designation pg:ACN6
] , [
lv2:index 7 ;
lv2:designation pg:ACN7
] , [
lv2:index 8 ;
lv2:designation pg:ACN8
] , [
lv2:index 9 ;
lv2:designation pg:ACN9
] , [
lv2:index 10 ;
lv2:designation pg:ACN15
] .
pg:AmbisonicBH3P3Group
a rdfs:Class ;
rdfs:subClassOf pg:AmbisonicGroup ;
rdfs:label "Ambisonic BH3P3" ;
rdfs:comment "Ambisonic B stream of horizontal order 3 and peripheral order 3." ;
pg:element [
lv2:index 0 ;
lv2:designation pg:ACN0
] , [
lv2:index 1 ;
lv2:designation pg:ACN1
] , [
lv2:index 2 ;
lv2:designation pg:ACN2
] , [
lv2:index 3 ;
lv2:designation pg:ACN3
] , [
lv2:index 4 ;
lv2:designation pg:ACN4
] , [
lv2:index 5 ;
lv2:designation pg:ACN5
] , [
lv2:index 6 ;
lv2:designation pg:ACN6
] , [
lv2:index 7 ;
lv2:designation pg:ACN7
] , [
lv2:index 8 ;
lv2:designation pg:ACN8
] , [
lv2:index 9 ;
lv2:designation pg:ACN9
] , [
lv2:index 10 ;
lv2:designation pg:ACN10
] , [
lv2:index 11 ;
lv2:designation pg:ACN11
] , [
lv2:index 12 ;
lv2:designation pg:ACN12
] , [
lv2:index 13 ;
lv2:designation pg:ACN13
] , [
lv2:index 14 ;
lv2:designation pg:ACN14
] , [
lv2:index 15 ;
lv2:designation pg:ACN15
] .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/port-props>
a lv2:Specification ;
lv2:minorVersion 1 ;
lv2:microVersion 2 ;
rdfs:seeAlso <port-props.ttl> .

View File

@@ -0,0 +1,53 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_PORT_PROPS_H
#define LV2_PORT_PROPS_H
/**
@defgroup port-props Port Properties
@ingroup lv2
Various port properties.
@{
*/
// clang-format off
#define LV2_PORT_PROPS_URI "http://lv2plug.in/ns/ext/port-props" ///< http://lv2plug.in/ns/ext/port-props
#define LV2_PORT_PROPS_PREFIX LV2_PORT_PROPS_URI "#" ///< http://lv2plug.in/ns/ext/port-props#
#define LV2_PORT_PROPS__causesArtifacts LV2_PORT_PROPS_PREFIX "causesArtifacts" ///< http://lv2plug.in/ns/ext/port-props#causesArtifacts
#define LV2_PORT_PROPS__continuousCV LV2_PORT_PROPS_PREFIX "continuousCV" ///< http://lv2plug.in/ns/ext/port-props#continuousCV
#define LV2_PORT_PROPS__discreteCV LV2_PORT_PROPS_PREFIX "discreteCV" ///< http://lv2plug.in/ns/ext/port-props#discreteCV
#define LV2_PORT_PROPS__displayPriority LV2_PORT_PROPS_PREFIX "displayPriority" ///< http://lv2plug.in/ns/ext/port-props#displayPriority
#define LV2_PORT_PROPS__expensive LV2_PORT_PROPS_PREFIX "expensive" ///< http://lv2plug.in/ns/ext/port-props#expensive
#define LV2_PORT_PROPS__hasStrictBounds LV2_PORT_PROPS_PREFIX "hasStrictBounds" ///< http://lv2plug.in/ns/ext/port-props#hasStrictBounds
#define LV2_PORT_PROPS__logarithmic LV2_PORT_PROPS_PREFIX "logarithmic" ///< http://lv2plug.in/ns/ext/port-props#logarithmic
#define LV2_PORT_PROPS__notAutomatic LV2_PORT_PROPS_PREFIX "notAutomatic" ///< http://lv2plug.in/ns/ext/port-props#notAutomatic
#define LV2_PORT_PROPS__notOnGUI LV2_PORT_PROPS_PREFIX "notOnGUI" ///< http://lv2plug.in/ns/ext/port-props#notOnGUI
#define LV2_PORT_PROPS__rangeSteps LV2_PORT_PROPS_PREFIX "rangeSteps" ///< http://lv2plug.in/ns/ext/port-props#rangeSteps
#define LV2_PORT_PROPS__supportsStrictBounds LV2_PORT_PROPS_PREFIX "supportsStrictBounds" ///< http://lv2plug.in/ns/ext/port-props#supportsStrictBounds
#define LV2_PORT_PROPS__trigger LV2_PORT_PROPS_PREFIX "trigger" ///< http://lv2plug.in/ns/ext/port-props#trigger
// clang-format on
/**
@}
*/
#endif /* LV2_PORT_PROPS_H */

View File

@@ -0,0 +1,202 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix pprops: <http://lv2plug.in/ns/ext/port-props#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/port-props>
a doap:Project ;
doap:name "LV2 Port Properties" ;
doap:created "2009-01-01" ;
doap:shortdesc "Various properties for LV2 plugin ports." ;
doap:maintainer <http://drobilla.net/drobilla#me> ;
doap:developer <http://lv2plug.in/ns/meta#kfoltman> ;
doap:release [
doap:revision "1.2" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Use consistent label style."
]
]
] , [
doap:revision "1.0" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This vocabulary defines various properties for plugin ports, which can be used
to better describe how a plugin can be controlled. Using this metadata, hosts
can build better UIs for plugins, and provide more advanced automatic
functionality.
"""^^lv2:Markdown .
pprops:trigger
lv2:documentation """
Indicates that the data item corresponds to a momentary event that has been
detected (control output ports) or is to be triggered (control input ports).
For input ports, the port needs to be reset to lv2:default value after run()
function of the plugin has returned. If the control port is assigned a GUI
widget by the host, the widget should be of auto-off (momentary, one-shot) type
- for example, a push button if the port is also declared as lv2:toggled, or a
series of push button or auto-clear input box with a "Send" button if the port
is also lv2:integer.
"""^^lv2:Markdown .
pprops:supportsStrictBounds
lv2:documentation """
Indicates use of host support for pprops:hasStrictBounds port property. A
plugin that specifies it as optional feature can omit value clamping for
hasStrictBounds ports, if the feature is supported by the host. When specified
as required feature, it indicates that the plugin does not do any clamping for
input ports that have a pprops:hasStrictBounds property.
"""^^lv2:Markdown .
pprops:hasStrictBounds
lv2:documentation """
For hosts that support pprops:supportsStrictBounds, this indicates that the
value of the port should never exceed the port's minimum and maximum control
points. For input ports, it moves the responsibility for limiting the range of
values to host, if it supports pprops:supportsStrictBounds. For output ports,
it indicates that values within specified range are to be expected, and
breaking that should be considered by the host as error in plugin
implementation.
"""^^lv2:Markdown .
pprops:expensive
lv2:documentation """
Input ports only. Indicates that any changes to the port value may trigger
expensive background calculation (for example, regeneration of lookup tables in
a background thread). Any value changes may have not have immediate effect, or
may cause silence or diminished-quality version of the output until background
processing is finished. Ports having this property are typically not well
suited for connection to outputs of other plugins, and should not be offered as
connection targets or for automation by default.
"""^^lv2:Markdown .
pprops:causesArtifacts
lv2:documentation """
Input ports only. Indicates that any changes to the port value may produce
slight artifacts to produced audio signals (zipper noise and other results of
signal discontinuities). Connecting ports of this type to continuous signals
is not recommended, and when presenting a list of automation targets, those
ports may be marked as artifact-producing.
"""^^lv2:Markdown .
pprops:continuousCV
lv2:documentation """
Indicates that the port carries a "smooth" modulation signal. Control input
ports of this type are well-suited for being connected to sources of smooth
signals (knobs with smoothing, modulation rate oscillators, output ports with
continuousCV type, etc.). Typically, the plugin with ports which have this
property will implement appropriate smoothing to avoid audio artifacts. For
output ports, this property suggests the value of the port is likely to change
frequently, and describes a smooth signal (so successive values may be
considered points along a curve).
"""^^lv2:Markdown .
pprops:discreteCV
lv2:documentation """
Indicates that the port carries a "discrete" modulation signal. Input ports of
this type are well-suited for being connected to sources of discrete signals
(switches, buttons, classifiers, event detectors, etc.). May be combined with
pprops:trigger property. For output ports, this property suggests the value of
the port describe discrete values that should be interpreted as steps (and not
points along a curve).
"""^^lv2:Markdown .
pprops:logarithmic
lv2:documentation """
Indicates that port value behaviour within specified range (bounds) is a value
using logarithmic scale. The lower and upper bounds must be specified, and
must be of the same sign.
"""^^lv2:Markdown .
pprops:notAutomatic
lv2:documentation """
Indicates that the port is not primarily intended to be fed with modulation
signals from external sources (other plugins, etc.). It is merely a UI hint
and hosts may allow the user to override it.
"""^^lv2:Markdown .
pprops:notOnGUI
lv2:documentation """
Indicates that the port is not primarily intended to be represented by a
separate control in the user interface window (or any similar mechanism used
for direct, immediate control of control ports). It is merely a UI hint and
hosts may allow the user to override it.
"""^^lv2:Markdown .
pprops:displayPriority
lv2:documentation """
Indicates how important a port is to controlling the plugin. If a host can
only display some ports of a plugin, it should prefer ports with a higher
display priority. Priorities do not need to be unique, and are only meaningful
when compared to each other.
"""^^lv2:Markdown .
pprops:rangeSteps
lv2:documentation """
This value indicates into how many evenly-divided points the (control) port
range should be divided for step-wise control. This may be used for changing
the value with step-based controllers like arrow keys, mouse wheel, rotary
encoders, and so on.
Note that when used with a pprops:logarithmic port, the steps are logarithmic
too, and port value can be calculated as:
:::c
value = lower * pow(upper / lower, step / (steps - 1))
and the step from value is:
:::c
step = (steps - 1) * log(value / lower) / log(upper / lower)
where:
* `value` is the port value.
* `step` is the step number (0..steps).
* `steps` is the number of steps (= value of :rangeSteps property).
* `lower` and <code>upper</code> are the bounds.
"""^^lv2:Markdown .

View File

@@ -0,0 +1,79 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix pprops: <http://lv2plug.in/ns/ext/port-props#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://lv2plug.in/ns/ext/port-props>
a owl:Ontology ;
rdfs:label "LV2 Port Properties" ;
rdfs:comment "Various properties for LV2 plugin ports." ;
rdfs:seeAlso <port-props.meta.ttl> .
pprops:trigger
a lv2:PortProperty ;
rdfs:label "trigger" ;
rdfs:comment "Port is a momentary trigger." .
pprops:supportsStrictBounds
a lv2:Feature ;
rdfs:label "supports strict bounds" ;
rdfs:comment "A feature indicating plugin support for strict port bounds." .
pprops:hasStrictBounds
a lv2:PortProperty ;
rdfs:label "has strict bounds" ;
rdfs:comment "Port has strict bounds which are not internally clamped." .
pprops:expensive
a lv2:PortProperty ;
rdfs:label "changes are expensive" ;
rdfs:comment "Input port is expensive to change." .
pprops:causesArtifacts
a lv2:PortProperty ;
rdfs:label "changes cause artifacts" ;
rdfs:comment "Input port causes audible artifacts when changed." .
pprops:continuousCV
a lv2:PortProperty ;
rdfs:label "smooth modulation signal" ;
rdfs:comment "Port carries a smooth modulation signal." .
pprops:discreteCV
a lv2:PortProperty ;
rdfs:label "discrete modulation signal" ;
rdfs:comment "Port carries a discrete modulation signal." .
pprops:logarithmic
a lv2:PortProperty ;
rdfs:label "logarithmic" ;
rdfs:comment "Port value is logarithmic." .
pprops:notAutomatic
a lv2:PortProperty ;
rdfs:label "not automatic" ;
rdfs:comment "Port that is not intended to be fed with a modulation signal." .
pprops:notOnGUI
a lv2:PortProperty ;
rdfs:label "not on GUI" ;
rdfs:comment "Port that should not be displayed on a GUI." .
pprops:displayPriority
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:domain lv2:Port ;
rdfs:range xsd:nonNegativeInteger ;
rdfs:label "display priority" ;
rdfs:comment "A priority ranking this port in importance to its plugin." .
pprops:rangeSteps
a rdf:Property ,
owl:DatatypeProperty ;
rdfs:domain lv2:Port ;
rdfs:range xsd:nonNegativeInteger ;
rdfs:label "range steps" ;
rdfs:comment "The number of even steps the range should be divided into." .

View File

@@ -0,0 +1,9 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/presets>
a lv2:Specification ;
lv2:minorVersion 2 ;
lv2:microVersion 8 ;
rdfs:seeAlso <presets.ttl> .

View File

@@ -0,0 +1,48 @@
/*
Copyright 2012-2016 David Robillard <d@drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LV2_PRESETS_H
#define LV2_PRESETS_H
/**
@defgroup presets Presets
@ingroup lv2
Presets for plugins.
See <http://lv2plug.in/ns/ext/presets> for details.
@{
*/
// clang-format off
#define LV2_PRESETS_URI "http://lv2plug.in/ns/ext/presets" ///< http://lv2plug.in/ns/ext/presets
#define LV2_PRESETS_PREFIX LV2_PRESETS_URI "#" ///< http://lv2plug.in/ns/ext/presets#
#define LV2_PRESETS__Bank LV2_PRESETS_PREFIX "Bank" ///< http://lv2plug.in/ns/ext/presets#Bank
#define LV2_PRESETS__Preset LV2_PRESETS_PREFIX "Preset" ///< http://lv2plug.in/ns/ext/presets#Preset
#define LV2_PRESETS__bank LV2_PRESETS_PREFIX "bank" ///< http://lv2plug.in/ns/ext/presets#bank
#define LV2_PRESETS__preset LV2_PRESETS_PREFIX "preset" ///< http://lv2plug.in/ns/ext/presets#preset
#define LV2_PRESETS__value LV2_PRESETS_PREFIX "value" ///< http://lv2plug.in/ns/ext/presets#value
// clang-format on
/**
@}
*/
#endif /* LV2_PRESETS_H */

View File

@@ -0,0 +1,132 @@
@prefix dcs: <http://ontologi.es/doap-changeset#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://lv2plug.in/ns/ext/presets>
a doap:Project ;
doap:license <http://opensource.org/licenses/isc> ;
doap:name "LV2 Presets" ;
doap:shortdesc "Presets for LV2 plugins." ;
doap:created "2009-00-00" ;
doap:developer <http://drobilla.net/drobilla#me> ;
doap:release [
doap:revision "2.8" ;
doap:created "2012-10-14" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Use consistent label style."
] , [
rdfs:label "Add preset banks."
]
]
] , [
doap:revision "2.6" ;
doap:created "2012-04-17" ;
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Add pset:preset property for describing the preset currently applied to a plugin instance."
] , [
rdfs:label "Remove pset:appliesTo property, use lv2:appliesTo instead."
] , [
rdfs:label "Merge with unified LV2 package."
]
]
] , [
doap:revision "2.2" ;
doap:created "2011-11-21" ;
doap:file-release <http://lv2plug.in/spec/lv2-presets-2.2.tar.bz2> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Update packaging."
] , [
rdfs:label "Improve documentation."
]
]
] , [
doap:revision "2.0" ;
doap:created "2010-10-04" ;
doap:file-release <http://lv2plug.in/spec/lv2-presets-2.0.tar.gz> ;
dcs:blame <http://drobilla.net/drobilla#me> ;
dcs:changeset [
dcs:item [
rdfs:label "Initial release."
]
]
] ;
lv2:documentation """
This is a vocabulary for LV2 plugin presets, that is, named sets of control
values and possibly other state. The structure of a pset:Preset is
deliberately identical to that of an lv2:Plugin, and can be thought of as a
plugin template or overlay.
Presets may be defined in any bundle, including the plugin's bundle, separate
third party preset bundles, or user preset bundles saved by hosts. Since
preset data tends to be large, it is recommended that plugins describe presets
in a separate file(s) to avoid slowing down hosts. The `manifest.ttl` of a
bundle containing presets should list them like so:
:::turtle
eg:mypreset
a pset:Preset ;
lv2:appliesTo eg:myplugin ;
rdfs:seeAlso <mypreset.ttl> .
"""^^lv2:Markdown .
pset:Preset
lv2:documentation """
The structure of a Preset deliberately mirrors that of a plugin, so existing
predicates can be used to describe any data associated with the preset. For
example:
:::turtle
@prefix eg: <http://example.org/> .
eg:mypreset
a pset:Preset ;
rdfs:label "One louder" ;
lv2:appliesTo eg:myplugin ;
lv2:port [
lv2:symbol "volume1" ;
pset:value 11.0
] , [
lv2:symbol "volume2" ;
pset:value 11.0
] .
A Preset SHOULD have at least one lv2:appliesTo property. Each Port on a
Preset MUST have at least a lv2:symbol property and a pset:value property.
Hosts SHOULD save user presets to a bundle in the user-local LV2 directory (for
example `~/.lv2`) with a name like `<Plugin_Name>_<Preset_Name>.preset.lv2`
(for example `LV2_Amp_At_Eleven.preset.lv2`), where names are transformed to be
valid LV2 symbols for maximum compatibility.
"""^^lv2:Markdown .
pset:value
lv2:documentation """
This property is used in a similar way to lv2:default.
"""^^lv2:Markdown .
pset:preset
lv2:documentation """
Specifies the preset currently applied to a plugin instance. This property may
be useful for saving state, or notifying a plugin instance at run-time about a
preset change.
"""^^lv2:Markdown .

Some files were not shown because too many files have changed in this diff Show More