From 84c2c81cb59773e1dab21039fd5e9bb1bbf470a0 Mon Sep 17 00:00:00 2001 From: falkTX Date: Wed, 17 Jun 2015 11:35:17 +0200 Subject: [PATCH] Update: Fix LV2 time position, set plugin categories --- dpf/dgl/NanoVG.hpp | 5 +- dpf/dgl/src/pugl/pugl_win.cpp | 5 +- dpf/distrho/DistrhoUI.hpp | 6 +- dpf/distrho/src/DistrhoPluginLV2.cpp | 260 +++++++++++++-------- dpf/distrho/src/DistrhoPluginLV2export.cpp | 208 +++++++++++++++-- plugins/3BandEQ/DistrhoPluginInfo.h | 2 + plugins/3BandSplitter/DistrhoPluginInfo.h | 2 + plugins/MVerb/DistrhoPluginInfo.h | 2 + plugins/Makefile.MVerb.mk | 4 + plugins/Makefile.Mini-Series.mk | 4 + plugins/Makefile.Nekobi.mk | 4 + plugins/Nekobi/DistrhoPluginInfo.h | 11 +- plugins/PingPongPan/DistrhoPluginInfo.h | 2 + plugins/ProM/DistrhoPluginInfo.h | 2 + 14 files changed, 380 insertions(+), 137 deletions(-) diff --git a/dpf/dgl/NanoVG.hpp b/dpf/dgl/NanoVG.hpp index 18ec1de..0d50133 100644 --- a/dpf/dgl/NanoVG.hpp +++ b/dpf/dgl/NanoVG.hpp @@ -801,11 +801,12 @@ public: float text(float x, float y, const char* string, const char* end); /** - Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn. + Draws multi-line text string at specified location wrapped at the specified width. + If end is specified only the sub-string up to the end is drawn. White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. Words longer than the max width are slit at nearest character (i.e. no hyphenation). */ - void textBox(float x, float y, float breakRowWidth, const char* string, const char* end); + void textBox(float x, float y, float breakRowWidth, const char* string, const char* end = nullptr); /** Measures the specified text string. The bounds value are [xmin,ymin, xmax,ymax]. diff --git a/dpf/dgl/src/pugl/pugl_win.cpp b/dpf/dgl/src/pugl/pugl_win.cpp index 1ac7c9e..acf7d9f 100644 --- a/dpf/dgl/src/pugl/pugl_win.cpp +++ b/dpf/dgl/src/pugl/pugl_win.cpp @@ -18,13 +18,14 @@ @file pugl_win.cpp Windows/WGL Pugl Implementation. */ +#include #include #include #include #include -#include -#include +#include +#include #include "pugl/pugl_internal.h" diff --git a/dpf/distrho/DistrhoUI.hpp b/dpf/distrho/DistrhoUI.hpp index 18d0789..00540e8 100644 --- a/dpf/distrho/DistrhoUI.hpp +++ b/dpf/distrho/DistrhoUI.hpp @@ -107,14 +107,14 @@ protected: * DSP/Plugin Callbacks */ /** - A parameter has changed on the plugin side. + A parameter has changed on the plugin side.@n This is called by the host to inform the UI about parameter changes. */ virtual void parameterChanged(uint32_t index, float value) = 0; #if DISTRHO_PLUGIN_WANT_PROGRAMS /** - A program has been loaded on the plugin side. + A program has been loaded on the plugin side.@n This is called by the host to inform the UI about program changes. */ virtual void programLoaded(uint32_t index) = 0; @@ -122,7 +122,7 @@ protected: #if DISTRHO_PLUGIN_WANT_STATE /** - A state has changed on the plugin side. + A state has changed on the plugin side.@n This is called by the host to inform the UI about state changes. */ virtual void stateChanged(const char* key, const char* value) = 0; diff --git a/dpf/distrho/src/DistrhoPluginLV2.cpp b/dpf/distrho/src/DistrhoPluginLV2.cpp index bd2a522..d52012f 100644 --- a/dpf/distrho/src/DistrhoPluginLV2.cpp +++ b/dpf/distrho/src/DistrhoPluginLV2.cpp @@ -40,10 +40,6 @@ # error DISTRHO_PLUGIN_URI undefined! #endif -#if DISTRHO_PLUGIN_WANT_TIMEPOS -# warning LV2 TimePos still TODO -#endif - #define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) #define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) @@ -61,9 +57,6 @@ public: fLastControlValues(nullptr), fSampleRate(sampleRate), #if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT -# if DISTRHO_PLUGIN_WANT_TIMEPOS - fLastTimeSpeed(0.0), -# endif fURIDs(uridMap), #endif fUridMap(uridMap), @@ -133,8 +126,7 @@ public: #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS - // hosts may not send all values, resulting on some invalid ones - fTimePosition.bbt.valid = false; + // hosts may not send all values, resulting on some invalid data fTimePosition.bbt.bar = 1; fTimePosition.bbt.beat = 1; fTimePosition.bbt.tick = 0; @@ -311,142 +303,178 @@ public: LV2_Atom* bar = nullptr; LV2_Atom* barBeat = nullptr; - LV2_Atom* beat = nullptr; LV2_Atom* beatUnit = nullptr; LV2_Atom* beatsPerBar = nullptr; LV2_Atom* beatsPerMinute = nullptr; - LV2_Atom* ticksPerBeat = nullptr; LV2_Atom* frame = nullptr; LV2_Atom* speed = nullptr; + LV2_Atom* ticksPerBeat = nullptr; lv2_atom_object_get(obj, fURIDs.timeBar, &bar, fURIDs.timeBarBeat, &barBeat, - fURIDs.timeBeat, &beat, fURIDs.timeBeatUnit, &beatUnit, fURIDs.timeBeatsPerBar, &beatsPerBar, fURIDs.timeBeatsPerMinute, &beatsPerMinute, - fURIDs.timeTicksPerBeat, &ticksPerBeat, fURIDs.timeFrame, &frame, fURIDs.timeSpeed, &speed, + fURIDs.timeTicksPerBeat, &ticksPerBeat, nullptr); + // need to handle this first as other values depend on it + if (ticksPerBeat != nullptr) + { + /**/ if (ticksPerBeat->type == fURIDs.atomDouble) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; + else if (ticksPerBeat->type == fURIDs.atomFloat) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; + else if (ticksPerBeat->type == fURIDs.atomInt) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; + else if (ticksPerBeat->type == fURIDs.atomLong) + fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; + else + d_stderr("Unknown lv2 ticksPerBeat value type"); + + if (fLastPositionData.ticksPerBeat > 0) + fTimePosition.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat; + } + + // same + if (speed != nullptr) + { + /**/ if (speed->type == fURIDs.atomDouble) + fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body; + else if (speed->type == fURIDs.atomFloat) + fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body; + else if (speed->type == fURIDs.atomInt) + fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body; + else if (speed->type == fURIDs.atomLong) + fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body; + else + d_stderr("Unknown lv2 speed value type"); + + fTimePosition.playing = d_isNotZero(fLastPositionData.speed); + } + if (bar != nullptr) { /**/ if (bar->type == fURIDs.atomDouble) - fTimePosition.bbt.bar = ((LV2_Atom_Double*)bar)->body + 1.0; + fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body; else if (bar->type == fURIDs.atomFloat) - fTimePosition.bbt.bar = ((LV2_Atom_Float*)bar)->body + 1.0f; + fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body; else if (bar->type == fURIDs.atomInt) - fTimePosition.bbt.bar = ((LV2_Atom_Int*)bar)->body + 1; + fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body; else if (bar->type == fURIDs.atomLong) - fTimePosition.bbt.bar = ((LV2_Atom_Long*)bar)->body + 1; + fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body; else d_stderr("Unknown lv2 bar value type"); - } - if (ticksPerBeat != nullptr) - { - /**/ if (ticksPerBeat->type == fURIDs.atomDouble) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; - else if (ticksPerBeat->type == fURIDs.atomFloat) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; - else if (ticksPerBeat->type == fURIDs.atomInt) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; - else if (ticksPerBeat->type == fURIDs.atomLong) - fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; - else - d_stderr("Unknown lv2 ticksPerBeat value type"); + if (fLastPositionData.bar >= 0) + fTimePosition.bbt.bar = fLastPositionData.bar + 1; } if (barBeat != nullptr) { - double barBeatValue = 0.0; - /**/ if (barBeat->type == fURIDs.atomDouble) - barBeatValue = ((LV2_Atom_Double*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body; else if (barBeat->type == fURIDs.atomFloat) - barBeatValue = ((LV2_Atom_Float*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body; else if (barBeat->type == fURIDs.atomInt) - barBeatValue = ((LV2_Atom_Int*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body; else if (barBeat->type == fURIDs.atomLong) - barBeatValue = ((LV2_Atom_Long*)barBeat)->body; + fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body; else d_stderr("Unknown lv2 barBeat value type"); - const double rest = std::fmod(barBeatValue, 1.0); - fTimePosition.bbt.beat = barBeatValue-rest+1.0; - fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; - } - // barBeat includes beat - else if (beat != nullptr) - { - /**/ if (beat->type == fURIDs.atomDouble) - fTimePosition.bbt.beat = ((LV2_Atom_Double*)beat)->body + 1.0; - else if (beat->type == fURIDs.atomFloat) - fTimePosition.bbt.beat = ((LV2_Atom_Float*)beat)->body + 1.0f; - else if (beat->type == fURIDs.atomInt) - fTimePosition.bbt.beat = ((LV2_Atom_Int*)beat)->body + 1; - else if (beat->type == fURIDs.atomLong) - fTimePosition.bbt.beat = ((LV2_Atom_Long*)beat)->body + 1; - else - d_stderr("Unknown lv2 beat value type"); + if (fLastPositionData.barBeat >= 0.0f) + { + const double rest = std::fmod(fLastPositionData.barBeat, 1.0); + fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; + fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; + } } if (beatUnit != nullptr) { /**/ if (beatUnit->type == fURIDs.atomDouble) - fTimePosition.bbt.beatType = ((LV2_Atom_Double*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomFloat) - fTimePosition.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomInt) - fTimePosition.bbt.beatType = ((LV2_Atom_Int*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomLong) - fTimePosition.bbt.beatType = ((LV2_Atom_Long*)beatUnit)->body; + fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body; else d_stderr("Unknown lv2 beatUnit value type"); + + if (fLastPositionData.beatUnit > 0) + fTimePosition.bbt.beatType = fLastPositionData.beatUnit; } if (beatsPerBar != nullptr) { /**/ if (beatsPerBar->type == fURIDs.atomDouble) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomFloat) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomInt) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomLong) - fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; + fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; else d_stderr("Unknown lv2 beatsPerBar value type"); + + if (fLastPositionData.beatsPerBar > 0.0f) + fTimePosition.bbt.beatsPerBar = fLastPositionData.beatsPerBar; } if (beatsPerMinute != nullptr) { /**/ if (beatsPerMinute->type == fURIDs.atomDouble) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomFloat) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomInt) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomLong) - fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; + fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; else d_stderr("Unknown lv2 beatsPerMinute value type"); - } - fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); + if (fLastPositionData.beatsPerMinute > 0.0f) + { + fTimePosition.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute; - if (frame != nullptr && frame->type == fURIDs.atomLong) - fTimePosition.frame = ((LV2_Atom_Long*)frame)->body; + if (d_isNotZero(fLastPositionData.speed)) + fTimePosition.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed); + } + } - if (speed != nullptr && speed->type == fURIDs.atomFloat) + if (frame != nullptr) { - fLastTimeSpeed = ((LV2_Atom_Float*)speed)->body; - fTimePosition.playing = (fLastTimeSpeed == 1.0); + /**/ if (frame->type == fURIDs.atomDouble) + fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body; + else if (frame->type == fURIDs.atomFloat) + fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body; + else if (frame->type == fURIDs.atomInt) + fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body; + else if (frame->type == fURIDs.atomLong) + fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body; + else + d_stderr("Unknown lv2 frame value type"); + + if (fLastPositionData.frame >= 0) + fTimePosition.frame = fLastPositionData.frame; } - fTimePosition.bbt.valid = (beatsPerMinute != nullptr && beatsPerBar != nullptr && beatUnit != nullptr); + fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* + fTimePosition.bbt.beatsPerBar* + (fTimePosition.bbt.bar-1); + + fTimePosition.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 && + fLastPositionData.beatUnit > 0 && + fLastPositionData.beatsPerBar > 0.0f); + continue; } # endif @@ -485,37 +513,56 @@ public: # if DISTRHO_PLUGIN_WANT_TIMEPOS // update timePos for next callback - if (fLastTimeSpeed != 0.0) + if (d_isNotZero(fLastPositionData.speed)) { - const double newFrames = fLastTimeSpeed*sampleCount; + if (fLastPositionData.speed > 0.0) + { + // playing forwards + fLastPositionData.frame += sampleCount; + } + else + { + // playing backwards + fLastPositionData.frame -= sampleCount; - fTimePosition.frame += newFrames; + if (fLastPositionData.frame < 0) + fLastPositionData.frame = 0; + } + + fTimePosition.frame = fLastPositionData.frame; if (fTimePosition.bbt.valid) { - const double samplesPerBeat = 60.0 / fTimePosition.bbt.beatsPerMinute * fSampleRate; - const double ticksPerSample = fTimePosition.bbt.ticksPerBeat / samplesPerBeat; + const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; + const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; + const double addedBarBeats = double(sampleCount) / framesPerBeat; - double newTickPos = double(fTimePosition.bbt.tick) + ticksPerSample*newFrames; - double newBeatPos = double(fTimePosition.bbt.beat)-1.0; - double newBarPos = double(fTimePosition.bbt.bar)-1.0; - - for (; newTickPos >= fTimePosition.bbt.ticksPerBeat;) + if (fLastPositionData.barBeat >= 0.0f) { - ++newBeatPos; - newTickPos -= fTimePosition.bbt.ticksPerBeat; - } + fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats, + fLastPositionData.beatsPerBar); - for (; newBeatPos >= fTimePosition.bbt.beatsPerBar;) - { - ++newBarPos; - newBeatPos -= fTimePosition.bbt.beatsPerBar; + const double rest = std::fmod(fLastPositionData.barBeat, 1.0); + fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; + fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; + + if (fLastPositionData.bar >= 0) + { + fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/ + fLastPositionData.beatsPerBar); + + if (fLastPositionData.bar < 0) + fLastPositionData.bar = 0; + + fTimePosition.bbt.bar = fLastPositionData.bar + 1; + + fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* + fTimePosition.bbt.beatsPerBar* + (fTimePosition.bbt.bar-1); + } } - fTimePosition.bbt.bar = newBarPos+1.0; - fTimePosition.bbt.beat = newBeatPos+1.0; - fTimePosition.bbt.tick = newTickPos; - fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); + fTimePosition.bbt.beatsPerMinute = std::abs(beatsPerMinute); } } # endif @@ -788,7 +835,28 @@ private: #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS TimePosition fTimePosition; - double fLastTimeSpeed; + + struct Lv2PositionData { + int64_t bar; + float barBeat; + uint32_t beatUnit; + float beatsPerBar; + float beatsPerMinute; + int64_t frame; + double speed; + int64_t ticksPerBeat; + + Lv2PositionData() + : bar(-1), + barBeat(-1.0f), + beatUnit(0), + beatsPerBar(0.0f), + beatsPerMinute(0.0f), + frame(-1), + speed(0.0), + ticksPerBeat(-1) {} + + } fLastPositionData; #endif // LV2 URIDs @@ -807,7 +875,6 @@ private: LV2_URID timePosition; LV2_URID timeBar; LV2_URID timeBarBeat; - LV2_URID timeBeat; LV2_URID timeBeatUnit; LV2_URID timeBeatsPerBar; LV2_URID timeBeatsPerMinute; @@ -829,7 +896,6 @@ private: timePosition(uridMap->map(uridMap->handle, LV2_TIME__Position)), timeBar(uridMap->map(uridMap->handle, LV2_TIME__bar)), timeBarBeat(uridMap->map(uridMap->handle, LV2_TIME__barBeat)), - timeBeat(uridMap->map(uridMap->handle, LV2_TIME__beat)), timeBeatUnit(uridMap->map(uridMap->handle, LV2_TIME__beatUnit)), timeBeatsPerBar(uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar)), timeBeatsPerMinute(uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute)), diff --git a/dpf/distrho/src/DistrhoPluginLV2export.cpp b/dpf/distrho/src/DistrhoPluginLV2export.cpp index 9508b43..beb7742 100644 --- a/dpf/distrho/src/DistrhoPluginLV2export.cpp +++ b/dpf/distrho/src/DistrhoPluginLV2export.cpp @@ -23,6 +23,7 @@ #include "lv2/midi.h" #include "lv2/options.h" #include "lv2/port-props.h" +#include "lv2/presets.h" #include "lv2/resize-port.h" #include "lv2/state.h" #include "lv2/time.h" @@ -49,6 +50,18 @@ # define DISTRHO_PLUGIN_HAS_UI 0 #endif +#if DISTRHO_PLUGIN_HAS_UI +# if DISTRHO_OS_HAIKU +# define DISTRHO_LV2_UI_TYPE "BeUI" +# elif DISTRHO_OS_MAC +# define DISTRHO_LV2_UI_TYPE "CocoaUI" +# elif DISTRHO_OS_WINDOWS +# define DISTRHO_LV2_UI_TYPE "WindowsUI" +# else +# define DISTRHO_LV2_UI_TYPE "X11UI" +# endif +#endif + #define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) #define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) @@ -69,6 +82,15 @@ void lv2_generate_ttl(const char* const basename) String pluginDLL(basename); String pluginTTL(pluginDLL + ".ttl"); +#if DISTRHO_PLUGIN_HAS_UI + String pluginUI(pluginDLL); +# if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + pluginUI.truncate(pluginDLL.rfind("_dsp")); + pluginUI += "_ui"; + const String uiTTL(pluginUI + ".ttl"); +# endif +#endif + // --------------------------------------------- { @@ -78,6 +100,9 @@ void lv2_generate_ttl(const char* const basename) String manifestString; manifestString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; manifestString += "@prefix rdfs: .\n"; +#if DISTRHO_PLUGIN_WANT_PROGRAMS + manifestString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n"; +#endif #if DISTRHO_PLUGIN_HAS_UI manifestString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; #endif @@ -91,45 +116,49 @@ void lv2_generate_ttl(const char* const basename) #if DISTRHO_PLUGIN_HAS_UI manifestString += "<" DISTRHO_UI_URI ">\n"; -# if DISTRHO_OS_HAIKU - manifestString += " a ui:BeUI ;\n"; -# elif DISTRHO_OS_MAC - manifestString += " a ui:CocoaUI ;\n"; -# elif DISTRHO_OS_WINDOWS - manifestString += " a ui:WindowsUI ;\n"; -# else - manifestString += " a ui:X11UI ;\n"; -# endif -# if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS - String pluginUI(pluginDLL); - pluginUI.truncate(pluginDLL.rfind("_dsp")); - pluginUI += "_ui"; - + manifestString += " a ui:" DISTRHO_LV2_UI_TYPE " ;\n"; manifestString += " ui:binary <" + pluginUI + "." DISTRHO_DLL_EXTENSION "> ;\n"; -# else - manifestString += " ui:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n"; -#endif +# if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS manifestString += "\n"; manifestString += " lv2:extensionData ui:idleInterface ,\n"; -# if DISTRHO_PLUGIN_WANT_PROGRAMS +# if DISTRHO_PLUGIN_WANT_PROGRAMS manifestString += " ui:showInterface ,\n"; manifestString += " <" LV2_PROGRAMS__Interface "> ;\n"; -# else +# else manifestString += " ui:showInterface ;\n"; -# endif +# endif manifestString += "\n"; manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; manifestString += " ui:resize ,\n"; manifestString += " ui:touch ;\n"; manifestString += "\n"; -# if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n"; manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n"; manifestString += " <" LV2_OPTIONS__options "> ,\n"; + manifestString += " <" LV2_URID__map "> .\n"; # else - manifestString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ,\n"; + manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n"; # endif - manifestString += " <" LV2_URID__map "> .\n"; + manifestString += "\n"; +#endif + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#"); + + char strBuf[0xff+1]; + strBuf[0xff] = '\0'; + + // Presets + for (uint32_t i = 0; i < plugin.getProgramCount(); ++i) + { + std::snprintf(strBuf, 0xff, "%03i", i+1); + + manifestString += "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; + manifestString += " a pset:Preset ;\n"; + manifestString += " lv2:appliesTo <" DISTRHO_PLUGIN_URI "> ;\n"; + manifestString += " rdfs:seeAlso .\n"; + manifestString += "\n"; + } #endif manifestFile << manifestString << std::endl; @@ -161,7 +190,9 @@ void lv2_generate_ttl(const char* const basename) // plugin pluginString += "<" DISTRHO_PLUGIN_URI ">\n"; -#if DISTRHO_PLUGIN_IS_SYNTH +#ifdef DISTRHO_PLUGIN_LV2_CATEGORY + pluginString += " a " DISTRHO_PLUGIN_LV2_CATEGORY ", lv2:Plugin ;\n"; +#elif DISTRHO_PLUGIN_IS_SYNTH pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n"; #else pluginString += " a lv2:Plugin ;\n"; @@ -428,4 +459,133 @@ void lv2_generate_ttl(const char* const basename) pluginFile.close(); std::cout << " done!" << std::endl; } + + // --------------------------------------------- + +#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS + { + std::cout << "Writing " << uiTTL << "..."; std::cout.flush(); + std::fstream uiFile(uiTTL, std::ios::out); + + String uiString; + uiString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; + uiString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; + uiString += "\n"; + + uiString += "<" DISTRHO_UI_URI ">\n"; + uiString += " lv2:extensionData ui:idleInterface ,\n"; +# if DISTRHO_PLUGIN_WANT_PROGRAMS + uiString += " ui:showInterface ,\n"; + uiString += " <" LV2_PROGRAMS__Interface "> ;\n"; +# else + uiString += " ui:showInterface ;\n"; +# endif + uiString += "\n"; + uiString += " lv2:optionalFeature ui:noUserResize ,\n"; + uiString += " ui:resize ,\n"; + uiString += " ui:touch ;\n"; + uiString += "\n"; + uiString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ,\n"; + uiString += " <" LV2_URID__map "> .\n"; + + uiFile << uiString << std::endl; + uiFile.close(); + std::cout << " done!" << std::endl; + } +#endif + + // --------------------------------------------- + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + { + std::cout << "Writing presets.ttl..."; std::cout.flush(); + std::fstream presetsFile("presets.ttl", std::ios::out); + + String presetsString; + presetsString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; + presetsString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n"; + presetsString += "@prefix rdfs: .\n"; +# if DISTRHO_PLUGIN_WANT_STATE + presetsString += "@prefix state: <" LV2_STATE_PREFIX "> .\n"; +# endif + presetsString += "\n"; + + const uint32_t numParameters = plugin.getParameterCount(); + const uint32_t numPrograms = plugin.getProgramCount(); +# if DISTRHO_PLUGIN_WANT_STATE + const uint32_t numStates = plugin.getStateCount(); +# endif + + const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#"); + + char strBuf[0xff+1]; + strBuf[0xff] = '\0'; + + String presetString; + + for (uint32_t i=0; i\n"; + presetString += " rdfs:label \"" + plugin.getProgramName(i) + "\" ;\n\n"; + + // TODO +# if 0 // DISTRHO_PLUGIN_WANT_STATE + for (uint32_t j=0; j\n"; + presetString += "\"\"\"\n"; + presetString += plugin.getState(j); + presetString += "\"\"\"\n"; + + if (j+1 == numStates) + { + if (numParameters > 0) + presetString += " ] ;\n\n"; + else + presetString += " ] .\n\n"; + } + else + { + presetString += " ] ,\n"; + } + } +# endif + + for (uint32_t j=0; j