diff --git a/README.build b/README.md similarity index 61% rename from README.build rename to README.md index 89682ae..24445ec 100644 --- a/README.build +++ b/README.md @@ -1,51 +1,61 @@ -# -*- mode: org -*- +# NON -* Non-things build instructions +## Non-things build instructions This repository contains all of the non-* software. -** Getting NTK +### Getting NTK If you just cloned the non repository or just executed git pull, then you should also run - git submodule update --init +``` +git submodule update --init +``` to pull down the latest NTK code required by Non. Git does *not* do this automatically. -** Building NTK +### Building NTK If you don't have NTK installed system-wide (which isn't very likely yet) you *MUST* begin the build process by typing: - cd lib/ntk - ./waf configure - ./waf +``` +cd lib/ntk +./waf configure +./waf +``` Once NTK has been built you must install it system-wide before attempting to build the non-* programs. To install NTK type: - su -c './waf install' +``` +su -c './waf install' +``` -** Build all projects +### Build all projects Typing: - ./waf configure - ./waf - su -c './waf install' +``` +./waf configure +./waf + su -c './waf install' +``` from the base of the checkout of the Non git repository will build and install all of the non-* programs together. -** Build a single project +### Build a single project Typing: - ./waf configure --project=[timline|sequencer|mixer|session-manager] - ./waf - su -c './waf install' +``` +./waf configure --project=[timline|sequencer|mixer|session-manager] +./waf +su -c './waf install' +``` diff --git a/mixer/src/Chain.C b/mixer/src/Chain.C index 015c925..5985fce 100644 --- a/mixer/src/Chain.C +++ b/mixer/src/Chain.C @@ -927,6 +927,7 @@ Chain::buffer_size ( nframes_t nframes ) configure_ports(); + Module::set_buffer_size ( nframes ); for ( int i = 0; i < modules(); ++i ) { Module *m = module(i); diff --git a/mixer/src/LV2_RDF.hpp b/mixer/src/LV2_RDF.hpp new file mode 100644 index 0000000..2fdbc30 --- /dev/null +++ b/mixer/src/LV2_RDF.hpp @@ -0,0 +1,642 @@ +/* + * Custom types to store LV2 information + * Copyright (C) 2011-2014 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the doc/GPL.txt file. + */ + +#ifndef LV2_RDF_HPP_INCLUDED +#define LV2_RDF_HPP_INCLUDED + +#include +#include + +// Base Types +typedef const char* LV2_URI; +typedef uint32_t LV2_Property; + +// Port Midi Map Types +#define LV2_PORT_MIDI_MAP_CC 1 +#define LV2_PORT_MIDI_MAP_NRPN 2 + +#define LV2_IS_PORT_MIDI_MAP_CC(x) ((x) == LV2_PORT_MIDI_MAP_CC) +#define LV2_IS_PORT_MIDI_MAP_NRPN(x) ((x) == LV2_PORT_MIDI_MAP_NRPN) + +// Port Point Hints +#define LV2_PORT_POINT_DEFAULT 0x1 +#define LV2_PORT_POINT_MINIMUM 0x2 +#define LV2_PORT_POINT_MAXIMUM 0x4 + +#define LV2_HAVE_DEFAULT_PORT_POINT(x) ((x) & LV2_PORT_POINT_DEFAULT) +#define LV2_HAVE_MINIMUM_PORT_POINT(x) ((x) & LV2_PORT_POINT_MINIMUM) +#define LV2_HAVE_MAXIMUM_PORT_POINT(x) ((x) & LV2_PORT_POINT_MAXIMUM) + +// Port Unit Hints +#define LV2_PORT_UNIT_NAME 0x1 +#define LV2_PORT_UNIT_RENDER 0x2 +#define LV2_PORT_UNIT_SYMBOL 0x4 +#define LV2_PORT_UNIT_UNIT 0x8 + +#define LV2_HAVE_PORT_UNIT_NAME(x) ((x) & LV2_PORT_UNIT_NAME) +#define LV2_HAVE_PORT_UNIT_RENDER(x) ((x) & LV2_PORT_UNIT_RENDER) +#define LV2_HAVE_PORT_UNIT_SYMBOL(x) ((x) & LV2_PORT_UNIT_SYMBOL) +#define LV2_HAVE_PORT_UNIT_UNIT(x) ((x) & LV2_PORT_UNIT_UNIT) + +// Port Unit Unit +#define LV2_PORT_UNIT_BAR 1 +#define LV2_PORT_UNIT_BEAT 2 +#define LV2_PORT_UNIT_BPM 3 +#define LV2_PORT_UNIT_CENT 4 +#define LV2_PORT_UNIT_CM 5 +#define LV2_PORT_UNIT_COEF 6 +#define LV2_PORT_UNIT_DB 7 +#define LV2_PORT_UNIT_DEGREE 8 +#define LV2_PORT_UNIT_FRAME 9 +#define LV2_PORT_UNIT_HZ 10 +#define LV2_PORT_UNIT_INCH 11 +#define LV2_PORT_UNIT_KHZ 12 +#define LV2_PORT_UNIT_KM 13 +#define LV2_PORT_UNIT_M 14 +#define LV2_PORT_UNIT_MHZ 15 +#define LV2_PORT_UNIT_MIDINOTE 16 +#define LV2_PORT_UNIT_MILE 17 +#define LV2_PORT_UNIT_MIN 18 +#define LV2_PORT_UNIT_MM 19 +#define LV2_PORT_UNIT_MS 20 +#define LV2_PORT_UNIT_OCT 21 +#define LV2_PORT_UNIT_PC 22 +#define LV2_PORT_UNIT_S 23 +#define LV2_PORT_UNIT_SEMITONE 24 + +#define LV2_IS_PORT_UNIT_BAR(x) ((x) == LV2_PORT_UNIT_BAR) +#define LV2_IS_PORT_UNIT_BEAT(x) ((x) == LV2_PORT_UNIT_BEAT) +#define LV2_IS_PORT_UNIT_BPM(x) ((x) == LV2_PORT_UNIT_BPM) +#define LV2_IS_PORT_UNIT_CENT(x) ((x) == LV2_PORT_UNIT_CENT) +#define LV2_IS_PORT_UNIT_CM(x) ((x) == LV2_PORT_UNIT_CM) +#define LV2_IS_PORT_UNIT_COEF(x) ((x) == LV2_PORT_UNIT_COEF) +#define LV2_IS_PORT_UNIT_DB(x) ((x) == LV2_PORT_UNIT_DB) +#define LV2_IS_PORT_UNIT_DEGREE(x) ((x) == LV2_PORT_UNIT_DEGREE) +#define LV2_IS_PORT_UNIT_FRAME(x) ((x) == LV2_PORT_UNIT_FRAME) +#define LV2_IS_PORT_UNIT_HZ(x) ((x) == LV2_PORT_UNIT_HZ) +#define LV2_IS_PORT_UNIT_INCH(x) ((x) == LV2_PORT_UNIT_INCH) +#define LV2_IS_PORT_UNIT_KHZ(x) ((x) == LV2_PORT_UNIT_KHZ) +#define LV2_IS_PORT_UNIT_KM(x) ((x) == LV2_PORT_UNIT_KM) +#define LV2_IS_PORT_UNIT_M(x) ((x) == LV2_PORT_UNIT_M) +#define LV2_IS_PORT_UNIT_MHZ(x) ((x) == LV2_PORT_UNIT_MHZ) +#define LV2_IS_PORT_UNIT_MIDINOTE(x) ((x) == LV2_PORT_UNIT_MIDINOTE) +#define LV2_IS_PORT_UNIT_MILE(x) ((x) == LV2_PORT_UNIT_MILE) +#define LV2_IS_PORT_UNIT_MIN(x) ((x) == LV2_PORT_UNIT_MIN) +#define LV2_IS_PORT_UNIT_MM(x) ((x) == LV2_PORT_UNIT_MM) +#define LV2_IS_PORT_UNIT_MS(x) ((x) == LV2_PORT_UNIT_MS) +#define LV2_IS_PORT_UNIT_OCT(x) ((x) == LV2_PORT_UNIT_OCT) +#define LV2_IS_PORT_UNIT_PC(x) ((x) == LV2_PORT_UNIT_PC) +#define LV2_IS_PORT_UNIT_S(x) ((x) == LV2_PORT_UNIT_S) +#define LV2_IS_PORT_UNIT_SEMITONE(x) ((x) == LV2_PORT_UNIT_SEMITONE) + +// Port Types +#define LV2_PORT_INPUT 0x001 +#define LV2_PORT_OUTPUT 0x002 +#define LV2_PORT_CONTROL 0x004 +#define LV2_PORT_AUDIO 0x008 +#define LV2_PORT_CV 0x010 +#define LV2_PORT_ATOM 0x020 +#define LV2_PORT_ATOM_SEQUENCE (0x040 | LV2_PORT_ATOM) +#define LV2_PORT_EVENT 0x080 +#define LV2_PORT_MIDI_LL 0x100 + +// Port Data Types +#define LV2_PORT_DATA_MIDI_EVENT 0x1000 +#define LV2_PORT_DATA_OSC_EVENT 0x2000 +#define LV2_PORT_DATA_PATCH_MESSAGE 0x4000 +#define LV2_PORT_DATA_TIME_POSITION 0x8000 + +#define LV2_IS_PORT_INPUT(x) ((x) & LV2_PORT_INPUT) +#define LV2_IS_PORT_OUTPUT(x) ((x) & LV2_PORT_OUTPUT) +#define LV2_IS_PORT_CONTROL(x) ((x) & LV2_PORT_CONTROL) +#define LV2_IS_PORT_AUDIO(x) ((x) & LV2_PORT_AUDIO) +#define LV2_IS_PORT_CV(x) ((x) & LV2_PORT_CV) +#define LV2_IS_PORT_ATOM_SEQUENCE(x) ((x) & LV2_PORT_ATOM_SEQUENCE) +#define LV2_IS_PORT_EVENT(x) ((x) & LV2_PORT_EVENT) +#define LV2_IS_PORT_MIDI_LL(x) ((x) & LV2_PORT_MIDI_LL) + +#define LV2_PORT_SUPPORTS_MIDI_EVENT(x) ((x) & LV2_PORT_DATA_MIDI_EVENT) +#define LV2_PORT_SUPPORTS_OSC_EVENT(x) ((x) & LV2_PORT_DATA_OSC_EVENT) +#define LV2_PORT_SUPPORTS_PATCH_MESSAGE(x) ((x) & LV2_PORT_DATA_PATCH_MESSAGE) +#define LV2_PORT_SUPPORTS_TIME_POSITION(x) ((x) & LV2_PORT_DATA_TIME_POSITION) + +// Port Properties +#define LV2_PORT_OPTIONAL 0x0001 +#define LV2_PORT_ENUMERATION 0x0002 +#define LV2_PORT_INTEGER 0x0004 +#define LV2_PORT_SAMPLE_RATE 0x0008 +#define LV2_PORT_TOGGLED 0x0010 +#define LV2_PORT_CAUSES_ARTIFACTS 0x0020 +#define LV2_PORT_CONTINUOUS_CV 0x0040 +#define LV2_PORT_DISCRETE_CV 0x0080 +#define LV2_PORT_EXPENSIVE 0x0100 +#define LV2_PORT_STRICT_BOUNDS 0x0200 +#define LV2_PORT_LOGARITHMIC 0x0400 +#define LV2_PORT_NOT_AUTOMATIC 0x0800 +#define LV2_PORT_NOT_ON_GUI 0x1000 +#define LV2_PORT_TRIGGER 0x2000 +#define LV2_PORT_NON_AUTOMABLE 0x4000 + +#define LV2_IS_PORT_OPTIONAL(x) ((x) & LV2_PORT_OPTIONAL) +#define LV2_IS_PORT_ENUMERATION(x) ((x) & LV2_PORT_ENUMERATION) +#define LV2_IS_PORT_INTEGER(x) ((x) & LV2_PORT_INTEGER) +#define LV2_IS_PORT_SAMPLE_RATE(x) ((x) & LV2_PORT_SAMPLE_RATE) +#define LV2_IS_PORT_TOGGLED(x) ((x) & LV2_PORT_TOGGLED) +#define LV2_IS_PORT_CAUSES_ARTIFACTS(x) ((x) & LV2_PORT_CAUSES_ARTIFACTS) +#define LV2_IS_PORT_CONTINUOUS_CV(x) ((x) & LV2_PORT_CONTINUOUS_CV) +#define LV2_IS_PORT_DISCRETE_CV(x) ((x) & LV2_PORT_DISCRETE_CV) +#define LV2_IS_PORT_EXPENSIVE(x) ((x) & LV2_PORT_EXPENSIVE) +#define LV2_IS_PORT_STRICT_BOUNDS(x) ((x) & LV2_PORT_STRICT_BOUNDS) +#define LV2_IS_PORT_LOGARITHMIC(x) ((x) & LV2_PORT_LOGARITHMIC) +#define LV2_IS_PORT_NOT_AUTOMATIC(x) ((x) & LV2_PORT_NOT_AUTOMATIC) +#define LV2_IS_PORT_NOT_ON_GUI(x) ((x) & LV2_PORT_NOT_ON_GUI) +#define LV2_IS_PORT_TRIGGER(x) ((x) & LV2_PORT_TRIGGER) +#define LV2_IS_PORT_NON_AUTOMABLE(x) ((x) & LV2_PORT_NON_AUTOMABLE) + +// Port Designation +#define LV2_PORT_DESIGNATION_CONTROL 1 +#define LV2_PORT_DESIGNATION_FREEWHEELING 2 +#define LV2_PORT_DESIGNATION_LATENCY 3 +#define LV2_PORT_DESIGNATION_SAMPLE_RATE 4 +#define LV2_PORT_DESIGNATION_TIME_BAR 5 +#define LV2_PORT_DESIGNATION_TIME_BAR_BEAT 6 +#define LV2_PORT_DESIGNATION_TIME_BEAT 7 +#define LV2_PORT_DESIGNATION_TIME_BEAT_UNIT 8 +#define LV2_PORT_DESIGNATION_TIME_BEATS_PER_BAR 9 +#define LV2_PORT_DESIGNATION_TIME_BEATS_PER_MINUTE 10 +#define LV2_PORT_DESIGNATION_TIME_FRAME 11 +#define LV2_PORT_DESIGNATION_TIME_FRAMES_PER_SECOND 12 +#define LV2_PORT_DESIGNATION_TIME_SPEED 13 +#define LV2_PORT_DESIGNATION_TIME_TICKS_PER_BEAT 14 + +#define LV2_IS_PORT_DESIGNATION_CONTROL(x) ((x) == LV2_PORT_DESIGNATION_CONTROL) +#define LV2_IS_PORT_DESIGNATION_FREEWHEELING(x) ((x) == LV2_PORT_DESIGNATION_FREEWHEELING) +#define LV2_IS_PORT_DESIGNATION_LATENCY(x) ((x) == LV2_PORT_DESIGNATION_LATENCY) +#define LV2_IS_PORT_DESIGNATION_SAMPLE_RATE(x) ((x) == LV2_PORT_DESIGNATION_SAMPLE_RATE) +#define LV2_IS_PORT_DESIGNATION_TIME_BAR(x) ((x) == LV2_PORT_DESIGNATION_TIME_BAR) +#define LV2_IS_PORT_DESIGNATION_TIME_BAR_BEAT(x) ((x) == LV2_PORT_DESIGNATION_TIME_BAR_BEAT) +#define LV2_IS_PORT_DESIGNATION_TIME_BEAT(x) ((x) == LV2_PORT_DESIGNATION_TIME_BEAT) +#define LV2_IS_PORT_DESIGNATION_TIME_BEAT_UNIT(x) ((x) == LV2_PORT_DESIGNATION_TIME_BEAT_UNIT) +#define LV2_IS_PORT_DESIGNATION_TIME_BEATS_PER_BAR(x) ((x) == LV2_PORT_DESIGNATION_TIME_BEATS_PER_BAR) +#define LV2_IS_PORT_DESIGNATION_TIME_BEATS_PER_MINUTE(x) ((x) == LV2_PORT_DESIGNATION_TIME_BEATS_PER_MINUTE) +#define LV2_IS_PORT_DESIGNATION_TIME_FRAME(x) ((x) == LV2_PORT_DESIGNATION_TIME_FRAME) +#define LV2_IS_PORT_DESIGNATION_TIME_FRAMES_PER_SECOND(x) ((x) == LV2_PORT_DESIGNATION_TIME_FRAMES_PER_SECOND) +#define LV2_IS_PORT_DESIGNATION_TIME_SPEED(x) ((x) == LV2_PORT_DESIGNATION_TIME_SPEED) +#define LV2_IS_PORT_DESIGNATION_TIME_TICKS_PER_BEAT(x) ((x) == LV2_PORT_DESIGNATION_TIME_TICKS_PER_BEAT) +#define LV2_IS_PORT_DESIGNATION_TIME(x) ((x) >= LV2_PORT_DESIGNATION_TIME_BAR && (x) <= LV2_PORT_DESIGNATION_TIME_TICKS_PER_BEAT) + +// Feature Types +#define LV2_FEATURE_OPTIONAL 1 +#define LV2_FEATURE_REQUIRED 2 + +#define LV2_IS_FEATURE_OPTIONAL(x) ((x) == LV2_FEATURE_OPTIONAL) +#define LV2_IS_FEATURE_REQUIRED(x) ((x) == LV2_FEATURE_REQUIRED) + +// UI Types +#define LV2_UI_GTK2 1 +#define LV2_UI_GTK3 2 +#define LV2_UI_QT4 3 +#define LV2_UI_QT5 4 +#define LV2_UI_COCOA 5 +#define LV2_UI_WINDOWS 6 +#define LV2_UI_X11 7 +#define LV2_UI_EXTERNAL 8 +#define LV2_UI_OLD_EXTERNAL 9 + +#define LV2_IS_UI_GTK2(x) ((x) == LV2_UI_GTK2) +#define LV2_IS_UI_GTK3(x) ((x) == LV2_UI_GTK3) +#define LV2_IS_UI_QT4(x) ((x) == LV2_UI_QT4) +#define LV2_IS_UI_QT5(x) ((x) == LV2_UI_QT5) +#define LV2_IS_UI_COCOA(x) ((x) == LV2_UI_COCOA) +#define LV2_IS_UI_WINDOWS(x) ((x) == LV2_UI_WINDOWS) +#define LV2_IS_UI_X11(x) ((x) == LV2_UI_X11) +#define LV2_IS_UI_EXTERNAL(x) ((x) == LV2_UI_EXTERNAL) +#define LV2_IS_UI_OLD_EXTERNAL(x) ((x) == LV2_UI_OLD_EXTERNAL) + +// Plugin Types +#define LV2_PLUGIN_DELAY 0x000001 +#define LV2_PLUGIN_REVERB 0x000002 +#define LV2_PLUGIN_SIMULATOR 0x000004 +#define LV2_PLUGIN_DISTORTION 0x000008 +#define LV2_PLUGIN_WAVESHAPER 0x000010 +#define LV2_PLUGIN_DYNAMICS 0x000020 +#define LV2_PLUGIN_AMPLIFIER 0x000040 +#define LV2_PLUGIN_COMPRESSOR 0x000080 +#define LV2_PLUGIN_ENVELOPE 0x000100 +#define LV2_PLUGIN_EXPANDER 0x000200 +#define LV2_PLUGIN_GATE 0x000400 +#define LV2_PLUGIN_LIMITER 0x000800 +#define LV2_PLUGIN_EQ 0x001000 +#define LV2_PLUGIN_MULTI_EQ 0x002000 +#define LV2_PLUGIN_PARA_EQ 0x004000 +#define LV2_PLUGIN_FILTER 0x008000 +#define LV2_PLUGIN_ALLPASS 0x010000 +#define LV2_PLUGIN_BANDPASS 0x020000 +#define LV2_PLUGIN_COMB 0x040000 +#define LV2_PLUGIN_HIGHPASS 0x080000 +#define LV2_PLUGIN_LOWPASS 0x100000 + +#define LV2_PLUGIN_GENERATOR 0x000001 +#define LV2_PLUGIN_CONSTANT 0x000002 +#define LV2_PLUGIN_INSTRUMENT 0x000004 +#define LV2_PLUGIN_OSCILLATOR 0x000008 +#define LV2_PLUGIN_MODULATOR 0x000010 +#define LV2_PLUGIN_CHORUS 0x000020 +#define LV2_PLUGIN_FLANGER 0x000040 +#define LV2_PLUGIN_PHASER 0x000080 +#define LV2_PLUGIN_SPATIAL 0x000100 +#define LV2_PLUGIN_SPECTRAL 0x000200 +#define LV2_PLUGIN_PITCH 0x000400 +#define LV2_PLUGIN_UTILITY 0x000800 +#define LV2_PLUGIN_ANALYSER 0x001000 +#define LV2_PLUGIN_CONVERTER 0x002000 +#define LV2_PLUGIN_FUNCTION 0x008000 +#define LV2_PLUGIN_MIXER 0x010000 + +#define LV2_GROUP_DELAY (LV2_PLUGIN_DELAY|LV2_PLUGIN_REVERB) +#define LV2_GROUP_DISTORTION (LV2_PLUGIN_DISTORTION|LV2_PLUGIN_WAVESHAPER) +#define LV2_GROUP_DYNAMICS (LV2_PLUGIN_DYNAMICS|LV2_PLUGIN_AMPLIFIER|LV2_PLUGIN_COMPRESSOR|LV2_PLUGIN_ENVELOPE|LV2_PLUGIN_EXPANDER|LV2_PLUGIN_GATE|LV2_PLUGIN_LIMITER) +#define LV2_GROUP_EQ (LV2_PLUGIN_EQ|LV2_PLUGIN_MULTI_EQ|LV2_PLUGIN_PARA_EQ) +#define LV2_GROUP_FILTER (LV2_PLUGIN_FILTER|LV2_PLUGIN_ALLPASS|LV2_PLUGIN_BANDPASS|LV2_PLUGIN_COMB|LV2_GROUP_EQ|LV2_PLUGIN_HIGHPASS|LV2_PLUGIN_LOWPASS) +#define LV2_GROUP_GENERATOR (LV2_PLUGIN_GENERATOR|LV2_PLUGIN_CONSTANT|LV2_PLUGIN_INSTRUMENT|LV2_PLUGIN_OSCILLATOR) +#define LV2_GROUP_MODULATOR (LV2_PLUGIN_MODULATOR|LV2_PLUGIN_CHORUS|LV2_PLUGIN_FLANGER|LV2_PLUGIN_PHASER) +#define LV2_GROUP_REVERB (LV2_PLUGIN_REVERB) +#define LV2_GROUP_SIMULATOR (LV2_PLUGIN_SIMULATOR|LV2_PLUGIN_REVERB) +#define LV2_GROUP_SPATIAL (LV2_PLUGIN_SPATIAL) +#define LV2_GROUP_SPECTRAL (LV2_PLUGIN_SPECTRAL|LV2_PLUGIN_PITCH) +#define LV2_GROUP_UTILITY (LV2_PLUGIN_UTILITY|LV2_PLUGIN_ANALYSER|LV2_PLUGIN_CONVERTER|LV2_PLUGIN_FUNCTION|LV2_PLUGIN_MIXER) + +#define LV2_IS_DELAY(x, y) ((x) & LV2_GROUP_DELAY) +#define LV2_IS_DISTORTION(x, y) ((x) & LV2_GROUP_DISTORTION) +#define LV2_IS_DYNAMICS(x, y) ((x) & LV2_GROUP_DYNAMICS) +#define LV2_IS_EQ(x, y) ((x) & LV2_GROUP_EQ) +#define LV2_IS_FILTER(x, y) ((x) & LV2_GROUP_FILTER) +#define LV2_IS_GENERATOR(x, y) ((y) & LV2_GROUP_GENERATOR) +#define LV2_IS_INSTRUMENT(x, y) ((y) & LV2_PLUGIN_INSTRUMENT) +#define LV2_IS_MODULATOR(x, y) ((y) & LV2_GROUP_MODULATOR) +#define LV2_IS_REVERB(x, y) ((x) & LV2_GROUP_REVERB) +#define LV2_IS_SIMULATOR(x, y) ((x) & LV2_GROUP_SIMULATOR) +#define LV2_IS_SPATIAL(x, y) ((y) & LV2_GROUP_SPATIAL) +#define LV2_IS_SPECTRAL(x, y) ((y) & LV2_GROUP_SPECTRAL) +#define LV2_IS_UTILITY(x, y) ((y) & LV2_GROUP_UTILITY) + +// Port Midi Map +struct LV2_RDF_PortMidiMap { + LV2_Property Type; + uint32_t Number; + + LV2_RDF_PortMidiMap() + : Type(0), + Number(0) {} +}; + +// Port Points +struct LV2_RDF_PortPoints { + LV2_Property Hints; + float Default; + float Minimum; + float Maximum; + + LV2_RDF_PortPoints() + : Hints(0x0), + Default(0.0f), + Minimum(0.0f), + Maximum(1.0f) {} +}; + +// Port Unit +struct LV2_RDF_PortUnit { + LV2_Property Hints; + const char* Name; + const char* Render; + const char* Symbol; + LV2_Property Unit; + + LV2_RDF_PortUnit() + : Hints(0x0), + Name(NULL), + Render(NULL), + Symbol(NULL), + Unit(0) {} + + ~LV2_RDF_PortUnit() + { + if (Name != NULL) + { + ::free((void*)Name); + Name = NULL; + } + if (Render != NULL) + { + ::free((void*)Render); + Render = NULL; + } + if (Symbol != NULL) + { + ::free((void*)Symbol); + Symbol = NULL; + } + } +}; + +// Port Scale Point +struct LV2_RDF_PortScalePoint { + const char* Label; + float Value; + + LV2_RDF_PortScalePoint() + : Label(NULL), + Value(0.0f) {} + + ~LV2_RDF_PortScalePoint() + { + if (Label != NULL) + { + ::free((void*)Label); + Label = NULL; + } + } +}; + +// Port +struct LV2_RDF_Port { + LV2_Property Types; + LV2_Property Properties; + LV2_Property Designation; + const char* Name; + const char* Symbol; + + LV2_RDF_PortMidiMap MidiMap; + LV2_RDF_PortPoints Points; + LV2_RDF_PortUnit Unit; + + uint32_t MinimumSize; + + uint32_t ScalePointCount; + LV2_RDF_PortScalePoint* ScalePoints; + + LV2_RDF_Port() + : Types(0x0), + Properties(0x0), + Designation(0), + Name(NULL), + Symbol(NULL), + MinimumSize(0), + ScalePointCount(0), + ScalePoints(NULL) {} + + ~LV2_RDF_Port() + { + if (Name != NULL) + { + ::free((void*)Name); + Name = NULL; + } + if (Symbol != NULL) + { + ::free((void*)Symbol); + Symbol = NULL; + } + if (ScalePoints != NULL) + { + delete[] ScalePoints; + ScalePoints = NULL; + } + } +}; + +// Preset +struct LV2_RDF_Preset { + LV2_URI URI; + const char* Label; + + LV2_RDF_Preset() + : URI(NULL), + Label(NULL) {} + + ~LV2_RDF_Preset() + { + if (URI != NULL) + { + ::free((void*)URI); + URI = NULL; + } + if (Label != NULL) + { + ::free((void*)Label); + Label = NULL; + } + } +}; + +// Feature +struct LV2_RDF_Feature { + LV2_Property Type; + LV2_URI URI; + + LV2_RDF_Feature() + : Type(0), + URI(NULL) {} + + ~LV2_RDF_Feature() + { + if (URI != NULL) + { + ::free((void*)URI); + URI = NULL; + } + } +}; + +// UI +struct LV2_RDF_UI { + LV2_Property Type; + LV2_URI URI; + const char* Binary; + const char* Bundle; + + uint32_t FeatureCount; + LV2_RDF_Feature* Features; + + uint32_t ExtensionCount; + LV2_URI* Extensions; + + LV2_RDF_UI() + : Type(0), + URI(NULL), + Binary(NULL), + Bundle(NULL), + FeatureCount(0), + Features(NULL), + ExtensionCount(0), + Extensions(NULL) {} + + ~LV2_RDF_UI() + { + if (URI != NULL) + { + ::free((void*)URI); + URI = NULL; + } + if (Binary != NULL) + { + ::free((void*)Binary); + Binary = NULL; + } + if (Bundle != NULL) + { + ::free((void*)Bundle); + Bundle = NULL; + } + if (Features != NULL) + { + delete[] Features; + Features = NULL; + } + if (Extensions != NULL) + { + for (uint32_t i=0; i + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the doc/GPL.txt file. + */ + +#ifndef LV2_RDF_UTILS_HPP_INCLUDED +#define LV2_RDF_UTILS_HPP_INCLUDED + +// disable -Wdocumentation for LV2 headers +#if defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) > 300 +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdocumentation" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lv2/lv2_external_ui.h" +#include "lv2/lv2_kxstudio_properties.h" + +#include "lilv/lilvmm.hpp" + +// enable -Wdocumentation again +#if defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) > 300 +# pragma clang diagnostic pop +#endif + +#include "LV2_RDF.hpp" + +#if 0 +#ifdef USE_QT +# include +#else +# include "juce_core.h" +#endif +#endif + +// ----------------------------------------------------------------------- +// Define namespaces and missing prefixes + +#define NS_dct "http://purl.org/dc/terms/" +#define NS_doap "http://usefulinc.com/ns/doap#" +#define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" +#define NS_rdfs "http://www.w3.org/2000/01/rdf-schema#" +#define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#" + +#define LV2_MIDI_Map__CC "http://ll-plugins.nongnu.org/lv2/namespace#CC" +#define LV2_MIDI_Map__NRPN "http://ll-plugins.nongnu.org/lv2/namespace#NRPN" + +#define LV2_MIDI_LL__MidiPort "http://ll-plugins.nongnu.org/lv2/ext/MidiPort" + +#define LV2_UI__Qt5UI LV2_UI_PREFIX "Qt5UI" +#define LV2_UI__makeResident LV2_UI_PREFIX "makeResident" + +// ----------------------------------------------------------------------- +// Custom Atom types + +struct LV2_Atom_MidiEvent { + LV2_Atom atom; /**< Atom header. */ + uint8_t data[4]; /**< MIDI data (body). */ +}; + +static inline +uint32_t lv2_atom_total_size(const LV2_Atom_MidiEvent& midiEv) +{ + return static_cast(sizeof(LV2_Atom)) + midiEv.atom.size; +} + +// ----------------------------------------------------------------------- +// Our LV2 World class + +class Lv2WorldClass : public Lilv::World +{ +public: + // Base Types + Lilv::Node port; + Lilv::Node symbol; + Lilv::Node designation; + Lilv::Node freeWheeling; + Lilv::Node reportsLatency; + + // Plugin Types + Lilv::Node class_allpass; + Lilv::Node class_amplifier; + Lilv::Node class_analyzer; + Lilv::Node class_bandpass; + Lilv::Node class_chorus; + Lilv::Node class_comb; + Lilv::Node class_compressor; + Lilv::Node class_constant; + Lilv::Node class_converter; + Lilv::Node class_delay; + Lilv::Node class_distortion; + Lilv::Node class_dynamics; + Lilv::Node class_eq; + Lilv::Node class_envelope; + Lilv::Node class_expander; + Lilv::Node class_filter; + Lilv::Node class_flanger; + Lilv::Node class_function; + Lilv::Node class_gate; + Lilv::Node class_generator; + Lilv::Node class_highpass; + Lilv::Node class_instrument; + Lilv::Node class_limiter; + Lilv::Node class_lowpass; + Lilv::Node class_mixer; + Lilv::Node class_modulator; + Lilv::Node class_multiEQ; + Lilv::Node class_oscillator; + Lilv::Node class_paraEQ; + Lilv::Node class_phaser; + Lilv::Node class_pitch; + Lilv::Node class_reverb; + Lilv::Node class_simulator; + Lilv::Node class_spatial; + Lilv::Node class_spectral; + Lilv::Node class_utility; + Lilv::Node class_waveshaper; + + // Port Types + Lilv::Node port_input; + Lilv::Node port_output; + Lilv::Node port_control; + Lilv::Node port_audio; + Lilv::Node port_cv; + Lilv::Node port_atom; + Lilv::Node port_event; + Lilv::Node port_midi; + + // Port Properties + Lilv::Node pprop_optional; + Lilv::Node pprop_enumeration; + Lilv::Node pprop_integer; + Lilv::Node pprop_sampleRate; + Lilv::Node pprop_toggled; + Lilv::Node pprop_artifacts; + Lilv::Node pprop_continuousCV; + Lilv::Node pprop_discreteCV; + Lilv::Node pprop_expensive; + Lilv::Node pprop_strictBounds; + Lilv::Node pprop_logarithmic; + Lilv::Node pprop_notAutomatic; + Lilv::Node pprop_notOnGUI; + Lilv::Node pprop_trigger; + Lilv::Node pprop_nonAutomable; + + // Unit Hints + Lilv::Node unit_name; + Lilv::Node unit_render; + Lilv::Node unit_symbol; + Lilv::Node unit_unit; + + // UI Types + Lilv::Node ui_gtk2; + Lilv::Node ui_gtk3; + Lilv::Node ui_qt4; + Lilv::Node ui_qt5; + Lilv::Node ui_cocoa; + Lilv::Node ui_windows; + Lilv::Node ui_x11; + Lilv::Node ui_external; + Lilv::Node ui_externalOld; + Lilv::Node ui_externalOld2; + + // Misc + Lilv::Node atom_bufferType; + Lilv::Node atom_sequence; + Lilv::Node atom_supports; + + Lilv::Node preset_preset; + + Lilv::Node state_state; + + Lilv::Node value_default; + Lilv::Node value_minimum; + Lilv::Node value_maximum; + + Lilv::Node rz_asLargeAs; + Lilv::Node rz_minSize; + + // Port Data Types + Lilv::Node midi_event; + Lilv::Node patch_message; + Lilv::Node time_position; + + // MIDI CC + Lilv::Node mm_defaultControl; + Lilv::Node mm_controlType; + Lilv::Node mm_controlNumber; + + // Other + Lilv::Node dct_replaces; + Lilv::Node doap_license; + Lilv::Node rdf_type; + Lilv::Node rdfs_label; + + bool needsInit; + + // ------------------------------------------------------------------- + + Lv2WorldClass() + : Lilv::World(), + port (new_uri(LV2_CORE__port)), + symbol (new_uri(LV2_CORE__symbol)), + designation (new_uri(LV2_CORE__designation)), + freeWheeling (new_uri(LV2_CORE__freeWheeling)), + reportsLatency (new_uri(LV2_CORE__reportsLatency)), + + class_allpass (new_uri(LV2_CORE__AllpassPlugin)), + class_amplifier (new_uri(LV2_CORE__AmplifierPlugin)), + class_analyzer (new_uri(LV2_CORE__AnalyserPlugin)), + class_bandpass (new_uri(LV2_CORE__BandpassPlugin)), + class_chorus (new_uri(LV2_CORE__ChorusPlugin)), + class_comb (new_uri(LV2_CORE__CombPlugin)), + class_compressor (new_uri(LV2_CORE__CompressorPlugin)), + class_constant (new_uri(LV2_CORE__ConstantPlugin)), + class_converter (new_uri(LV2_CORE__ConverterPlugin)), + class_delay (new_uri(LV2_CORE__DelayPlugin)), + class_distortion (new_uri(LV2_CORE__DistortionPlugin)), + class_dynamics (new_uri(LV2_CORE__DynamicsPlugin)), + class_eq (new_uri(LV2_CORE__EQPlugin)), + class_envelope (new_uri(LV2_CORE__EnvelopePlugin)), + class_expander (new_uri(LV2_CORE__ExpanderPlugin)), + class_filter (new_uri(LV2_CORE__FilterPlugin)), + class_flanger (new_uri(LV2_CORE__FlangerPlugin)), + class_function (new_uri(LV2_CORE__FunctionPlugin)), + class_gate (new_uri(LV2_CORE__GatePlugin)), + class_generator (new_uri(LV2_CORE__GeneratorPlugin)), + class_highpass (new_uri(LV2_CORE__HighpassPlugin)), + class_instrument (new_uri(LV2_CORE__InstrumentPlugin)), + class_limiter (new_uri(LV2_CORE__LimiterPlugin)), + class_lowpass (new_uri(LV2_CORE__LowpassPlugin)), + class_mixer (new_uri(LV2_CORE__MixerPlugin)), + class_modulator (new_uri(LV2_CORE__ModulatorPlugin)), + class_multiEQ (new_uri(LV2_CORE__MultiEQPlugin)), + class_oscillator (new_uri(LV2_CORE__OscillatorPlugin)), + class_paraEQ (new_uri(LV2_CORE__ParaEQPlugin)), + class_phaser (new_uri(LV2_CORE__PhaserPlugin)), + class_pitch (new_uri(LV2_CORE__PitchPlugin)), + class_reverb (new_uri(LV2_CORE__ReverbPlugin)), + class_simulator (new_uri(LV2_CORE__SimulatorPlugin)), + class_spatial (new_uri(LV2_CORE__SpatialPlugin)), + class_spectral (new_uri(LV2_CORE__SpectralPlugin)), + class_utility (new_uri(LV2_CORE__UtilityPlugin)), + class_waveshaper (new_uri(LV2_CORE__WaveshaperPlugin)), + + port_input (new_uri(LV2_CORE__InputPort)), + port_output (new_uri(LV2_CORE__OutputPort)), + port_control (new_uri(LV2_CORE__ControlPort)), + port_audio (new_uri(LV2_CORE__AudioPort)), + port_cv (new_uri(LV2_CORE__CVPort)), + port_atom (new_uri(LV2_ATOM__AtomPort)), + port_event (new_uri(LV2_EVENT__EventPort)), + port_midi (new_uri(LV2_MIDI_LL__MidiPort)), + + pprop_optional (new_uri(LV2_CORE__connectionOptional)), + pprop_enumeration (new_uri(LV2_CORE__enumeration)), + pprop_integer (new_uri(LV2_CORE__integer)), + pprop_sampleRate (new_uri(LV2_CORE__sampleRate)), + pprop_toggled (new_uri(LV2_CORE__toggled)), + pprop_artifacts (new_uri(LV2_PORT_PROPS__causesArtifacts)), + pprop_continuousCV (new_uri(LV2_PORT_PROPS__continuousCV)), + pprop_discreteCV (new_uri(LV2_PORT_PROPS__discreteCV)), + pprop_expensive (new_uri(LV2_PORT_PROPS__expensive)), + pprop_strictBounds (new_uri(LV2_PORT_PROPS__hasStrictBounds)), + pprop_logarithmic (new_uri(LV2_PORT_PROPS__logarithmic)), + pprop_notAutomatic (new_uri(LV2_PORT_PROPS__notAutomatic)), + pprop_notOnGUI (new_uri(LV2_PORT_PROPS__notOnGUI)), + pprop_trigger (new_uri(LV2_PORT_PROPS__trigger)), + pprop_nonAutomable (new_uri(LV2_KXSTUDIO_PROPERTIES__NonAutomable)), + + unit_name (new_uri(LV2_UNITS__name)), + unit_render (new_uri(LV2_UNITS__render)), + unit_symbol (new_uri(LV2_UNITS__symbol)), + unit_unit (new_uri(LV2_UNITS__unit)), + + ui_gtk2 (new_uri(LV2_UI__GtkUI)), + ui_gtk3 (new_uri(LV2_UI__Gtk3UI)), + ui_qt4 (new_uri(LV2_UI__Qt4UI)), + ui_qt5 (new_uri(LV2_UI__Qt5UI)), + ui_cocoa (new_uri(LV2_UI__CocoaUI)), + ui_windows (new_uri(LV2_UI__WindowsUI)), + ui_x11 (new_uri(LV2_UI__X11UI)), + ui_external (new_uri(LV2_EXTERNAL_UI__Widget)), + ui_externalOld (new_uri(LV2_EXTERNAL_UI_DEPRECATED_URI)), + ui_externalOld2 (new_uri("http://nedko.arnaudov.name/lv2/external_ui/")), + + atom_bufferType (new_uri(LV2_ATOM__bufferType)), + atom_sequence (new_uri(LV2_ATOM__Sequence)), + atom_supports (new_uri(LV2_ATOM__supports)), + + preset_preset (new_uri(LV2_PRESETS__Preset)), + + state_state (new_uri(LV2_STATE__state)), + + value_default (new_uri(LV2_CORE__default)), + value_minimum (new_uri(LV2_CORE__minimum)), + value_maximum (new_uri(LV2_CORE__maximum)), + + rz_asLargeAs (new_uri(LV2_RESIZE_PORT__asLargeAs)), + rz_minSize (new_uri(LV2_RESIZE_PORT__minimumSize)), + + midi_event (new_uri(LV2_MIDI__MidiEvent)), + patch_message (new_uri(LV2_PATCH__Message)), + time_position (new_uri(LV2_TIME__Position)), + + mm_defaultControl (new_uri(NS_llmm "defaultMidiController")), + mm_controlType (new_uri(NS_llmm "controllerType")), + mm_controlNumber (new_uri(NS_llmm "controllerNumber")), + + dct_replaces (new_uri(NS_dct "replaces")), + doap_license (new_uri(NS_doap "license")), + rdf_type (new_uri(NS_rdf "type")), + rdfs_label (new_uri(NS_rdfs "label")), + + needsInit(true) {} + + static Lv2WorldClass& getInstance() + { + static Lv2WorldClass lv2World; + return lv2World; + } + + void initIfNeeded(/*const char* const LV2_PATH*/) + { + if (/*LV2_PATH == NULL || LV2_PATH[0] == '\0' ||*/ ! needsInit) + return; + + needsInit = false; + Lilv::World::load_all(/*LV2_PATH*/); + } + + void load_bundle(const char* const bundle) + { + if (bundle == NULL || bundle[0] == '\0') + return; + + needsInit = false; + Lilv::World::load_bundle(Lilv::Node(new_uri(bundle))); + } + + uint getPluginCount() const + { + if (needsInit) + return 0; + + if (const LilvPlugins* const cPlugins = lilv_world_get_all_plugins(this->me)) + return lilv_plugins_size(cPlugins); + + return 0; + } + + const LilvPlugin* getPluginFromIndex(const uint index) const + { + if (needsInit) + return NULL; + + if (const LilvPlugins* const cPlugins = lilv_world_get_all_plugins(this->me)) + { + uint32_t i=0; + for (LilvIter *it = lilv_plugins_begin(cPlugins); ! lilv_plugins_is_end(cPlugins, it); it = lilv_plugins_next(cPlugins, it), ++i) + { + if (index != i) + continue; + + return lilv_plugins_get(cPlugins, it); + } + } + + return NULL; + } + + const LilvPlugin* getPluginFromURI(const LV2_URI uri) const + { + if (uri == NULL || uri[0] == '\0' || needsInit) + return NULL; + + if (const LilvPlugins* const cPlugins = lilv_world_get_all_plugins(this->me)) + { + if (LilvNode* const uriNode = lilv_new_uri(this->me, uri)) + { + const LilvPlugin* const cPlugin(lilv_plugins_get_by_uri(cPlugins, uriNode)); + lilv_node_free(uriNode); + return cPlugin; + } + } + + return NULL; + } + +#if 0 /* requires custom lilv */ + LilvState* getStateFromURI(const LV2_URI uri, const LV2_URID_Map* const uridMap) const + { + if (uri == NULL || uri[0] == '\0' || uridMap == NULL || needsInit) + return NULL; + + if (LilvNode* const uriNode = lilv_new_uri(this->me, uri)) + { + LilvState* const cState(lilv_state_new_from_world(this->me, uridMap, uriNode)); + lilv_node_free(uriNode); + return cState; + } + + return NULL; + } +#endif +}; + +// ----------------------------------------------------------------------- +// Create new RDF object (using lilv) + +static inline +const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets) +{ + if (uri == NULL || uri[0] == '\0') + return NULL; + + Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); + + const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(uri)); + if (cPlugin == NULL) return NULL; + + Lilv::Plugin lilvPlugin(cPlugin); + LV2_RDF_Descriptor* const rdfDescriptor(new LV2_RDF_Descriptor()); + + // ------------------------------------------------------------------- + // Set Plugin Type + { + Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type)); + + if (typeNodes.size() > 0) + { + if (typeNodes.contains(lv2World.class_allpass)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_ALLPASS; + if (typeNodes.contains(lv2World.class_amplifier)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_AMPLIFIER; + if (typeNodes.contains(lv2World.class_analyzer)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_ANALYSER; + if (typeNodes.contains(lv2World.class_bandpass)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_BANDPASS; + if (typeNodes.contains(lv2World.class_chorus)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_CHORUS; + if (typeNodes.contains(lv2World.class_comb)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_COMB; + if (typeNodes.contains(lv2World.class_compressor)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_COMPRESSOR; + if (typeNodes.contains(lv2World.class_constant)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_CONSTANT; + if (typeNodes.contains(lv2World.class_converter)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_CONVERTER; + if (typeNodes.contains(lv2World.class_delay)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_DELAY; + if (typeNodes.contains(lv2World.class_distortion)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_DISTORTION; + if (typeNodes.contains(lv2World.class_dynamics)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_DYNAMICS; + if (typeNodes.contains(lv2World.class_eq)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_EQ; + if (typeNodes.contains(lv2World.class_envelope)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_ENVELOPE; + if (typeNodes.contains(lv2World.class_expander)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_EXPANDER; + if (typeNodes.contains(lv2World.class_filter)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_FILTER; + if (typeNodes.contains(lv2World.class_flanger)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_FLANGER; + if (typeNodes.contains(lv2World.class_function)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_FUNCTION; + if (typeNodes.contains(lv2World.class_gate)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_GATE; + if (typeNodes.contains(lv2World.class_generator)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_GENERATOR; + if (typeNodes.contains(lv2World.class_highpass)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_HIGHPASS; + if (typeNodes.contains(lv2World.class_instrument)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_INSTRUMENT; + if (typeNodes.contains(lv2World.class_limiter)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_LIMITER; + if (typeNodes.contains(lv2World.class_lowpass)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_LOWPASS; + if (typeNodes.contains(lv2World.class_mixer)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_MIXER; + if (typeNodes.contains(lv2World.class_modulator)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_MODULATOR; + if (typeNodes.contains(lv2World.class_multiEQ)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_MULTI_EQ; + if (typeNodes.contains(lv2World.class_oscillator)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_OSCILLATOR; + if (typeNodes.contains(lv2World.class_paraEQ)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_PARA_EQ; + if (typeNodes.contains(lv2World.class_phaser)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_PHASER; + if (typeNodes.contains(lv2World.class_pitch)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_PITCH; + if (typeNodes.contains(lv2World.class_reverb)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_REVERB; + if (typeNodes.contains(lv2World.class_simulator)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_SIMULATOR; + if (typeNodes.contains(lv2World.class_spatial)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_SPATIAL; + if (typeNodes.contains(lv2World.class_spectral)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_SPECTRAL; + if (typeNodes.contains(lv2World.class_utility)) + rdfDescriptor->Type[1] |= LV2_PLUGIN_UTILITY; + if (typeNodes.contains(lv2World.class_waveshaper)) + rdfDescriptor->Type[0] |= LV2_PLUGIN_WAVESHAPER; + } + + lilv_nodes_free(const_cast(typeNodes.me)); + } + + // ------------------------------------------------------------------- + // Set Plugin Information + { + rdfDescriptor->URI = strdup(uri); + + if (const char* const name = lilvPlugin.get_name().as_string()) + rdfDescriptor->Name = strdup(name); + + if (const char* const author = lilvPlugin.get_author_name().as_string()) + rdfDescriptor->Author = strdup(author); + + if (const char* const binary = lilvPlugin.get_library_uri().as_string()) + rdfDescriptor->Binary = strdup(lilv_uri_to_path(binary)); + + if (const char* const bundle = lilvPlugin.get_bundle_uri().as_string()) + rdfDescriptor->Bundle = strdup(lilv_uri_to_path(bundle)); + + Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license)); + + if (licenseNodes.size() > 0) + { + if (const char* const license = licenseNodes.get_first().as_string()) + rdfDescriptor->License = strdup(license); + } + + lilv_nodes_free(const_cast(licenseNodes.me)); + } + +#if 0 + // ------------------------------------------------------------------- + // Set Plugin UniqueID + { + Lilv::Nodes replaceNodes(lilvPlugin.get_value(lv2World.dct_replaces)); + + if (replaceNodes.size() > 0) + { + Lilv::Node replaceNode(replaceNodes.get_first()); + + if (replaceNode.is_uri()) + { +#ifdef USE_QT + const QString replaceURI(replaceNode.as_uri()); + + if (replaceURI.startsWith("urn:")) + { + const QString replaceId(replaceURI.split(":").last()); + + bool ok; + const ulong uniqueId(replaceId.toULong(&ok)); + + if (ok && uniqueId != 0) + rdfDescriptor->UniqueID = uniqueId; + } +#else + const juce::String replaceURI(replaceNode.as_uri()); + + if (replaceURI.startsWith("urn:")) + { + const int uniqueId(replaceURI.getTrailingIntValue()); + + if (uniqueId > 0) + rdfDescriptor->UniqueID = static_cast(uniqueId); + } +#endif + } + } + + lilv_nodes_free(const_cast(replaceNodes.me)); + } +#endif + + // ------------------------------------------------------------------- + // Set Plugin Ports + + if (lilvPlugin.get_num_ports() > 0) + { + rdfDescriptor->PortCount = lilvPlugin.get_num_ports(); + rdfDescriptor->Ports = new LV2_RDF_Port[rdfDescriptor->PortCount]; + + for (uint32_t i = 0; i < rdfDescriptor->PortCount; ++i) + { + Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i)); + LV2_RDF_Port* const rdfPort(&rdfDescriptor->Ports[i]); + + // ----------------------------------------------------------- + // Set Port Information + { + if (const char* const name = Lilv::Node(lilvPort.get_name()).as_string()) + rdfPort->Name = strdup(name); + + if (const char* const symbol = Lilv::Node(lilvPort.get_symbol()).as_string()) + rdfPort->Symbol = strdup(symbol); + } + + // ----------------------------------------------------------- + // Set Port Mode and Type + { + // Input or Output + /**/ if (lilvPort.is_a(lv2World.port_input)) + rdfPort->Types |= LV2_PORT_INPUT; + else if (lilvPort.is_a(lv2World.port_output)) + rdfPort->Types |= LV2_PORT_OUTPUT; + else + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' is not input or output", uri, rdfPort->Name); + + // Data Type + /**/ if (lilvPort.is_a(lv2World.port_control)) + { + rdfPort->Types |= LV2_PORT_CONTROL; + } + else if (lilvPort.is_a(lv2World.port_audio)) + { + rdfPort->Types |= LV2_PORT_AUDIO; + } + else if (lilvPort.is_a(lv2World.port_cv)) + { + rdfPort->Types |= LV2_PORT_CV; + } + else if (lilvPort.is_a(lv2World.port_atom)) + { + rdfPort->Types |= LV2_PORT_ATOM; + + Lilv::Nodes bufferTypeNodes(lilvPort.get_value(lv2World.atom_bufferType)); + + for (LilvIter* it = lilv_nodes_begin(bufferTypeNodes.me); ! lilv_nodes_is_end(bufferTypeNodes.me, it); it = lilv_nodes_next(bufferTypeNodes.me, it)) + { + const Lilv::Node node(lilv_nodes_get(bufferTypeNodes.me, it)); + if (! node.is_uri()) continue; + + if (node.equals(lv2World.atom_sequence)) + rdfPort->Types |= LV2_PORT_ATOM_SEQUENCE; + else + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses an unknown atom buffer type '%s'", uri, rdfPort->Name, node.as_uri()); + } + + Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports)); + + for (LilvIter* it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it)) + { + const Lilv::Node node(lilv_nodes_get(supportNodes.me, it)); + if (! node.is_uri()) continue; + + /**/ if (node.equals(lv2World.midi_event)) + rdfPort->Types |= LV2_PORT_DATA_MIDI_EVENT; + + else if (node.equals(lv2World.patch_message)) + rdfPort->Types |= LV2_PORT_DATA_PATCH_MESSAGE; + + else if (node.equals(lv2World.time_position)) + rdfPort->Types |= LV2_PORT_DATA_TIME_POSITION; + } + + lilv_nodes_free(const_cast(bufferTypeNodes.me)); + lilv_nodes_free(const_cast(supportNodes.me)); + } + else if (lilvPort.is_a(lv2World.port_event)) + { + rdfPort->Types |= LV2_PORT_EVENT; + bool supported = false; + + if (lilvPort.supports_event(lv2World.midi_event)) + { + rdfPort->Types |= LV2_PORT_DATA_MIDI_EVENT; + supported = true; + } + if (lilvPort.supports_event(lv2World.patch_message)) + { + rdfPort->Types |= LV2_PORT_DATA_PATCH_MESSAGE; + supported = true; + } + if (lilvPort.supports_event(lv2World.time_position)) + { + rdfPort->Types |= LV2_PORT_DATA_TIME_POSITION; + supported = true; + } + + if (! supported) + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' is of event type but has unsupported data", uri, rdfPort->Name); + } + else if (lilvPort.is_a(lv2World.port_midi)) + { + rdfPort->Types |= LV2_PORT_MIDI_LL; + rdfPort->Types |= LV2_PORT_DATA_MIDI_EVENT; + } + else + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' is of unkown data type", uri, rdfPort->Name); + } + + // ----------------------------------------------------------- + // Set Port Properties + { + if (lilvPort.has_property(lv2World.pprop_optional)) + rdfPort->Properties |= LV2_PORT_OPTIONAL; + if (lilvPort.has_property(lv2World.pprop_enumeration)) + rdfPort->Properties |= LV2_PORT_ENUMERATION; + if (lilvPort.has_property(lv2World.pprop_integer)) + rdfPort->Properties |= LV2_PORT_INTEGER; + if (lilvPort.has_property(lv2World.pprop_sampleRate)) + rdfPort->Properties |= LV2_PORT_SAMPLE_RATE; + if (lilvPort.has_property(lv2World.pprop_toggled)) + rdfPort->Properties |= LV2_PORT_TOGGLED; + + if (lilvPort.has_property(lv2World.pprop_artifacts)) + rdfPort->Properties |= LV2_PORT_CAUSES_ARTIFACTS; + if (lilvPort.has_property(lv2World.pprop_continuousCV)) + rdfPort->Properties |= LV2_PORT_CONTINUOUS_CV; + if (lilvPort.has_property(lv2World.pprop_discreteCV)) + rdfPort->Properties |= LV2_PORT_DISCRETE_CV; + if (lilvPort.has_property(lv2World.pprop_expensive)) + rdfPort->Properties |= LV2_PORT_EXPENSIVE; + if (lilvPort.has_property(lv2World.pprop_strictBounds)) + rdfPort->Properties |= LV2_PORT_STRICT_BOUNDS; + if (lilvPort.has_property(lv2World.pprop_logarithmic)) + rdfPort->Properties |= LV2_PORT_LOGARITHMIC; + if (lilvPort.has_property(lv2World.pprop_notAutomatic)) + rdfPort->Properties |= LV2_PORT_NOT_AUTOMATIC; + if (lilvPort.has_property(lv2World.pprop_notOnGUI)) + rdfPort->Properties |= LV2_PORT_NOT_ON_GUI; + if (lilvPort.has_property(lv2World.pprop_trigger)) + rdfPort->Properties |= LV2_PORT_TRIGGER; + if (lilvPort.has_property(lv2World.pprop_nonAutomable)) + rdfPort->Properties |= LV2_PORT_NON_AUTOMABLE; + + if (lilvPort.has_property(lv2World.reportsLatency)) + rdfPort->Designation = LV2_PORT_DESIGNATION_LATENCY; + + // no port properties set, check if using old/invalid ones + if (rdfPort->Properties == 0x0) + { + static const Lilv::Node oldPropArtifacts(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#causesArtifacts")); + static const Lilv::Node oldPropContinuousCV(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#continuousCV")); + static const Lilv::Node oldPropDiscreteCV(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#discreteCV")); + static const Lilv::Node oldPropExpensive(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#expensive")); + static const Lilv::Node oldPropStrictBounds(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#hasStrictBounds")); + static const Lilv::Node oldPropLogarithmic(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#logarithmic")); + static const Lilv::Node oldPropNotAutomatic(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#notAutomatic")); + static const Lilv::Node oldPropNotOnGUI(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#notOnGUI")); + static const Lilv::Node oldPropTrigger(lv2World.new_uri("http://lv2plug.in/ns/dev/extportinfo#trigger")); + + if (lilvPort.has_property(oldPropArtifacts)) + { + rdfPort->Properties |= LV2_PORT_CAUSES_ARTIFACTS; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'causesArtifacts'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropContinuousCV)) + { + rdfPort->Properties |= LV2_PORT_CONTINUOUS_CV; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'continuousCV'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropDiscreteCV)) + { + rdfPort->Properties |= LV2_PORT_DISCRETE_CV; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'discreteCV'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropExpensive)) + { + rdfPort->Properties |= LV2_PORT_EXPENSIVE; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'expensive'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropStrictBounds)) + { + rdfPort->Properties |= LV2_PORT_STRICT_BOUNDS; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'hasStrictBounds'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropLogarithmic)) + { + rdfPort->Properties |= LV2_PORT_LOGARITHMIC; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'logarithmic'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropNotAutomatic)) + { + rdfPort->Properties |= LV2_PORT_NOT_AUTOMATIC; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'notAutomatic'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropNotOnGUI)) + { + rdfPort->Properties |= LV2_PORT_NOT_ON_GUI; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'notOnGUI'", uri, rdfPort->Name); + } + if (lilvPort.has_property(oldPropTrigger)) + { + rdfPort->Properties |= LV2_PORT_TRIGGER; + fprintf(stderr, "lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'trigger'", uri, rdfPort->Name); + } + } + } + + // ----------------------------------------------------------- + // Set Port Designation + { + if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me)) + { + if (const char* const designation = lilv_node_as_string(designationNode)) + { + /**/ if (::strcmp(designation, LV2_CORE__control) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_CONTROL; + else if (::strcmp(designation, LV2_CORE__freeWheeling) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_FREEWHEELING; + else if (::strcmp(designation, LV2_CORE__latency) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_LATENCY; + else if (::strcmp(designation, LV2_PARAMETERS__sampleRate) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_SAMPLE_RATE; + else if (::strcmp(designation, LV2_TIME__bar) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BAR; + else if (::strcmp(designation, LV2_TIME__barBeat) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BAR_BEAT; + else if (::strcmp(designation, LV2_TIME__beat) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEAT; + else if (::strcmp(designation, LV2_TIME__beatUnit) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEAT_UNIT; + else if (::strcmp(designation, LV2_TIME__beatsPerBar) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEATS_PER_BAR; + else if (::strcmp(designation, LV2_TIME__beatsPerMinute) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEATS_PER_MINUTE; + else if (::strcmp(designation, LV2_TIME__frame) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_FRAME; + else if (::strcmp(designation, LV2_TIME__framesPerSecond) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_FRAMES_PER_SECOND; + else if (::strcmp(designation, LV2_TIME__speed) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_SPEED; + else if (::strcmp(designation, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0) + rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_TICKS_PER_BEAT; + else if (::strncmp(designation, LV2_PARAMETERS_PREFIX, ::strlen(LV2_PARAMETERS_PREFIX)) == 0) + (void)0; // nothing + else if (::strncmp(designation, LV2_PORT_GROUPS_PREFIX, ::strlen(LV2_PORT_GROUPS_PREFIX)) == 0) + (void)0; // nothing + else + fprintf(stderr, "lv2_rdf_new(\"%s\") - got unknown port designation '%s'", uri, designation); + } + lilv_node_free(designationNode); + } + } + + // ----------------------------------------------------------- + // Set Port MIDI Map + { + if (LilvNode* const midiMapNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.mm_defaultControl.me)) + { + if (lilv_node_is_blank(midiMapNode)) + { + Lilv::Nodes midiMapTypeNodes(lv2World.find_nodes(midiMapNode, lv2World.mm_controlType, NULL)); + Lilv::Nodes midiMapNumberNodes(lv2World.find_nodes(midiMapNode, lv2World.mm_controlNumber, NULL)); + + if (midiMapTypeNodes.size() == 1 && midiMapNumberNodes.size() == 1) + { + if (const char* const midiMapType = midiMapTypeNodes.get_first().as_string()) + { + /**/ if (::strcmp(midiMapType, LV2_MIDI_Map__CC) == 0) + rdfPort->MidiMap.Type = LV2_PORT_MIDI_MAP_CC; + else if (::strcmp(midiMapType, LV2_MIDI_Map__NRPN) == 0) + rdfPort->MidiMap.Type = LV2_PORT_MIDI_MAP_NRPN; + else + fprintf(stderr, "lv2_rdf_new(\"%s\") - got unknown port Midi-Map type '%s'", uri, midiMapType); + + rdfPort->MidiMap.Number = static_cast(midiMapNumberNodes.get_first().as_int()); + } + } + + lilv_nodes_free(const_cast(midiMapTypeNodes.me)); + lilv_nodes_free(const_cast(midiMapNumberNodes.me)); + } + + lilv_node_free(midiMapNode); + } + + // TODO - also check using new official MIDI API too + } + + // ----------------------------------------------------------- + // Set Port Points + { + if (LilvNode* const defNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.value_default.me)) + { + rdfPort->Points.Hints |= LV2_PORT_POINT_DEFAULT; + rdfPort->Points.Default = lilv_node_as_float(defNode); + lilv_node_free(defNode); + } + + if (LilvNode* const minNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.value_minimum.me)) + { + rdfPort->Points.Hints |= LV2_PORT_POINT_MINIMUM; + rdfPort->Points.Minimum = lilv_node_as_float(minNode); + lilv_node_free(minNode); + } + + if (LilvNode* const maxNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.value_maximum.me)) + { + rdfPort->Points.Hints |= LV2_PORT_POINT_MAXIMUM; + rdfPort->Points.Maximum = lilv_node_as_float(maxNode); + lilv_node_free(maxNode); + } + } + + // ----------------------------------------------------------- + // Set Port Unit + { + if (LilvNode* const unitUnitNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.unit_unit.me)) + { + if (lilv_node_is_uri(unitUnitNode)) + { + if (const char* const unitUnit = lilv_node_as_uri(unitUnitNode)) + { + rdfPort->Unit.Hints |= LV2_PORT_UNIT_UNIT; + + /**/ if (::strcmp(unitUnit, LV2_UNITS__bar) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_BAR; + else if (::strcmp(unitUnit, LV2_UNITS__beat) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_BEAT; + else if (::strcmp(unitUnit, LV2_UNITS__bpm) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_BPM; + else if (::strcmp(unitUnit, LV2_UNITS__cent) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_CENT; + else if (::strcmp(unitUnit, LV2_UNITS__cm) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_CM; + else if (::strcmp(unitUnit, LV2_UNITS__coef) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_COEF; + else if (::strcmp(unitUnit, LV2_UNITS__db) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_DB; + else if (::strcmp(unitUnit, LV2_UNITS__degree) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_DEGREE; + else if (::strcmp(unitUnit, LV2_UNITS__frame) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_FRAME; + else if (::strcmp(unitUnit, LV2_UNITS__hz) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_HZ; + else if (::strcmp(unitUnit, LV2_UNITS__inch) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_INCH; + else if (::strcmp(unitUnit, LV2_UNITS__khz) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_KHZ; + else if (::strcmp(unitUnit, LV2_UNITS__km) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_KM; + else if (::strcmp(unitUnit, LV2_UNITS__m) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_M; + else if (::strcmp(unitUnit, LV2_UNITS__mhz) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_MHZ; + else if (::strcmp(unitUnit, LV2_UNITS__midiNote) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_MIDINOTE; + else if (::strcmp(unitUnit, LV2_UNITS__mile) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_MILE; + else if (::strcmp(unitUnit, LV2_UNITS__min) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_MIN; + else if (::strcmp(unitUnit, LV2_UNITS__mm) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_MM; + else if (::strcmp(unitUnit, LV2_UNITS__ms) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_MS; + else if (::strcmp(unitUnit, LV2_UNITS__oct) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_OCT; + else if (::strcmp(unitUnit, LV2_UNITS__pc) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_PC; + else if (::strcmp(unitUnit, LV2_UNITS__s) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_S; + else if (::strcmp(unitUnit, LV2_UNITS__semitone12TET) == 0) + rdfPort->Unit.Unit = LV2_PORT_UNIT_SEMITONE; + else + fprintf(stderr, "lv2_rdf_new(\"%s\") - got unknown unit unit '%s'", uri, unitUnit); + } + } + lilv_node_free(unitUnitNode); + } + + // FIXME + + if (LilvNode* const unitNameNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.unit_name.me)) + { + if (const char* const unitName = lilv_node_as_string(unitNameNode)) + { + rdfPort->Unit.Hints |= LV2_PORT_UNIT_NAME; + rdfPort->Unit.Name = strdup(unitName); + } + lilv_node_free(unitNameNode); + } + + if (LilvNode* const unitRenderNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.unit_render.me)) + { + if (const char* const unitRender = lilv_node_as_string(unitRenderNode)) + { + rdfPort->Unit.Hints |= LV2_PORT_UNIT_RENDER; + rdfPort->Unit.Render = strdup(unitRender); + } + lilv_node_free(unitRenderNode); + } + + if (LilvNode* const unitSymbolNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.unit_symbol.me)) + { + if (const char* const unitSymbol = lilv_node_as_string(unitSymbolNode)) + { + rdfPort->Unit.Hints |= LV2_PORT_UNIT_SYMBOL; + rdfPort->Unit.Symbol = strdup(unitSymbol); + } + lilv_node_free(unitSymbolNode); + } + } + + // ----------------------------------------------------------- + // Set Port Minimum Size + { + if (LilvNode* const minimumSizeNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.rz_minSize.me)) + { + const int minimumSize(lilv_node_as_int(minimumSizeNode)); + + if (minimumSize > 0) + rdfPort->MinimumSize = static_cast(minimumSize); + + lilv_node_free(minimumSizeNode); + } + } + + // ----------------------------------------------------------- + // Set Port Scale Points + + { + Lilv::ScalePoints lilvScalePoints(lilvPort.get_scale_points()); + + if (lilvScalePoints.size() > 0) + { + rdfPort->ScalePointCount = lilvScalePoints.size(); + rdfPort->ScalePoints = new LV2_RDF_PortScalePoint[rdfPort->ScalePointCount]; + + uint32_t h = 0; + LILV_FOREACH(scale_points, it, lilvScalePoints) + { + if (h >= rdfPort->ScalePointCount) break; + + Lilv::ScalePoint lilvScalePoint(lilvScalePoints.get(it)); + LV2_RDF_PortScalePoint* const rdfScalePoint(&rdfPort->ScalePoints[h++]); + + if (const char* const label = Lilv::Node(lilvScalePoint.get_label()).as_string()) + rdfScalePoint->Label = strdup(label); + + rdfScalePoint->Value = Lilv::Node(lilvScalePoint.get_value()).as_float(); + } + } + + lilv_nodes_free(const_cast(lilvScalePoints.me)); + } + } + } + +#if 0 + // ------------------------------------------------------------------- + // Set Plugin Presets + + if (loadPresets) + { + Lilv::Nodes presetNodes(lilvPlugin.get_related(lv2World.preset_preset)); + + if (presetNodes.size() > 0) + { + // create a list of preset URIs (for checking appliesTo, sorting and unique-ness) + // FIXME - check appliesTo? + +#ifdef USE_QT + QStringList presetListURIs; + + LILV_FOREACH(nodes, it, presetNodes) + { + Lilv::Node presetNode(presetNodes.get(it)); + + QString presetURI(presetNode.as_uri()); + + if (! (presetURI.trimmed().isEmpty() || presetListURIs.contains(presetURI))) + presetListURIs.append(presetURI); + } + + presetListURIs.sort(); + + rdfDescriptor->PresetCount = static_cast(presetListURIs.count()); +#else + juce::StringArray presetListURIs; + + LILV_FOREACH(nodes, it, presetNodes) + { + Lilv::Node presetNode(presetNodes.get(it)); + + juce::String presetURI(presetNode.as_uri()); + + if (presetURI.trim().isNotEmpty()) + presetListURIs.addIfNotAlreadyThere(presetURI); + } + + presetListURIs.sortNatural(); + + rdfDescriptor->PresetCount = static_cast(presetListURIs.size()); +#endif + + // create presets with unique URIs + rdfDescriptor->Presets = new LV2_RDF_Preset[rdfDescriptor->PresetCount]; + + // set preset data + LILV_FOREACH(nodes, it, presetNodes) + { + Lilv::Node presetNode(presetNodes.get(it)); + + if (lv2World.load_resource(presetNode) == -1) + continue; + + if (const char* const presetURI = presetNode.as_uri()) + { +#ifdef USE_QT + const int index(presetListURIs.indexOf(QString(presetURI))); +#else + const int index(presetListURIs.indexOf(juce::String(presetURI))); +#endif + if (index < 0) continue; + + LV2_RDF_Preset* const rdfPreset(&rdfDescriptor->Presets[index]); + + // --------------------------------------------------- + // Set Preset Information + { + rdfPreset->URI = strdup(presetURI); + + Lilv::Nodes presetLabelNodes(lv2World.find_nodes(presetNode, lv2World.rdfs_label, NULL)); + + if (presetLabelNodes.size() > 0) + { + if (const char* const label = presetLabelNodes.get_first().as_string()) + rdfPreset->Label = strdup(label); + } + + lilv_nodes_free(const_cast(presetLabelNodes.me)); + } + } + } + } + + lilv_nodes_free(const_cast(presetNodes.me)); + } +#endif + + // ------------------------------------------------------------------- + // Set Plugin Features + { + Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features()); + + if (lilvFeatureNodes.size() > 0) + { + Lilv::Nodes lilvFeatureNodesR(lilvPlugin.get_required_features()); + + rdfDescriptor->FeatureCount = lilvFeatureNodes.size(); + rdfDescriptor->Features = new LV2_RDF_Feature[rdfDescriptor->FeatureCount]; + + uint32_t h = 0; + LILV_FOREACH(nodes, it, lilvFeatureNodes) + { + if (h >= rdfDescriptor->FeatureCount) break; + + Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it)); + LV2_RDF_Feature* const rdfFeature(&rdfDescriptor->Features[h++]); + + rdfFeature->Type = lilvFeatureNodesR.contains(lilvFeatureNode) ? LV2_FEATURE_REQUIRED : LV2_FEATURE_OPTIONAL; + + if (const char* const featureURI = lilvFeatureNode.as_uri()) + rdfFeature->URI = strdup(featureURI); + else + rdfFeature->URI = NULL; + } + + lilv_nodes_free(const_cast(lilvFeatureNodesR.me)); + } + + lilv_nodes_free(const_cast(lilvFeatureNodes.me)); + } + + // ------------------------------------------------------------------- + // Set Plugin Extensions + { + Lilv::Nodes lilvExtensionDataNodes(lilvPlugin.get_extension_data()); + + if (lilvExtensionDataNodes.size() > 0) + { + rdfDescriptor->ExtensionCount = lilvExtensionDataNodes.size(); + rdfDescriptor->Extensions = new LV2_URI[rdfDescriptor->ExtensionCount]; + + uint32_t h = 0; + LILV_FOREACH(nodes, it, lilvExtensionDataNodes) + { + if (h >= rdfDescriptor->ExtensionCount) break; + + Lilv::Node lilvExtensionDataNode(lilvExtensionDataNodes.get(it)); + LV2_URI* const rdfExtension(&rdfDescriptor->Extensions[h++]); + + if (lilvExtensionDataNode.is_uri()) + { + if (const char* const extURI = lilvExtensionDataNode.as_uri()) + { + *rdfExtension = strdup(extURI); + continue; + } + } + *rdfExtension = NULL; + } + + for (uint32_t x=h; x < rdfDescriptor->ExtensionCount; ++x) + rdfDescriptor->Extensions[x] = NULL; + } + + lilv_nodes_free(const_cast(lilvExtensionDataNodes.me)); + } + + // ------------------------------------------------------------------- + // Set Plugin UIs + { + Lilv::UIs lilvUIs(lilvPlugin.get_uis()); + + if (lilvUIs.size() > 0) + { + rdfDescriptor->UICount = lilvUIs.size(); + rdfDescriptor->UIs = new LV2_RDF_UI[rdfDescriptor->UICount]; + + uint32_t h = 0; + LILV_FOREACH(uis, it, lilvUIs) + { + if (h >= rdfDescriptor->UICount) break; + + Lilv::UI lilvUI(lilvUIs.get(it)); + LV2_RDF_UI* const rdfUI(&rdfDescriptor->UIs[h++]); + + // ------------------------------------------------------- + // Set UI Type + + /**/ if (lilvUI.is_a(lv2World.ui_gtk2)) + rdfUI->Type = LV2_UI_GTK2; + else if (lilvUI.is_a(lv2World.ui_gtk3)) + rdfUI->Type = LV2_UI_GTK3; + else if (lilvUI.is_a(lv2World.ui_qt4)) + rdfUI->Type = LV2_UI_QT4; + else if (lilvUI.is_a(lv2World.ui_qt5)) + rdfUI->Type = LV2_UI_QT5; + else if (lilvUI.is_a(lv2World.ui_cocoa)) + rdfUI->Type = LV2_UI_COCOA; + else if (lilvUI.is_a(lv2World.ui_windows)) + rdfUI->Type = LV2_UI_WINDOWS; + else if (lilvUI.is_a(lv2World.ui_x11)) + rdfUI->Type = LV2_UI_X11; + else if (lilvUI.is_a(lv2World.ui_external)) + rdfUI->Type = LV2_UI_EXTERNAL; + else if (lilvUI.is_a(lv2World.ui_externalOld)) + rdfUI->Type = LV2_UI_OLD_EXTERNAL; + else if (lilvUI.is_a(lv2World.ui_externalOld2)) + (void)0; // nothing + else + fprintf(stderr, "lv2_rdf_new(\"%s\") - UI '%s' is of unknown type", uri, lilvUI.get_uri().as_uri()); + + // ------------------------------------------------------- + // Set UI Information + { + if (const char* const uiURI = lilvUI.get_uri().as_uri()) + rdfUI->URI = strdup(uiURI); + + if (const char* const uiBinary = lilvUI.get_binary_uri().as_string()) + rdfUI->Binary = strdup(lilv_uri_to_path(uiBinary)); + + if (const char* const uiBundle = lilvUI.get_bundle_uri().as_string()) + rdfUI->Bundle = strdup(lilv_uri_to_path(uiBundle)); + } + +#if 0 /* needs custom lilv */ + // ------------------------------------------------------- + // Set UI Features + { + Lilv::Nodes lilvFeatureNodes(lilvUI.get_supported_features()); + + if (lilvFeatureNodes.size() > 0) + { + Lilv::Nodes lilvFeatureNodesR(lilvUI.get_required_features()); + + rdfUI->FeatureCount = lilvFeatureNodes.size(); + rdfUI->Features = new LV2_RDF_Feature[rdfUI->FeatureCount]; + + uint32_t h2 = 0; + LILV_FOREACH(nodes, it2, lilvFeatureNodes) + { + if (h2 >= rdfUI->FeatureCount) break; + + Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it2)); + LV2_RDF_Feature* const rdfFeature(&rdfUI->Features[h2++]); + + rdfFeature->Type = lilvFeatureNodesR.contains(lilvFeatureNode) ? LV2_FEATURE_REQUIRED : LV2_FEATURE_OPTIONAL; + + if (const char* const featureURI = lilvFeatureNode.as_uri()) + rdfFeature->URI = strdup(featureURI); + else + rdfFeature->URI = NULL; + } + + lilv_nodes_free(const_cast(lilvFeatureNodesR.me)); + } + + lilv_nodes_free(const_cast(lilvFeatureNodes.me)); + } + + // ------------------------------------------------------- + // Set UI Extensions + { + Lilv::Nodes lilvExtensionDataNodes(lilvUI.get_extension_data()); + + if (lilvExtensionDataNodes.size() > 0) + { + rdfUI->ExtensionCount = lilvExtensionDataNodes.size(); + rdfUI->Extensions = new LV2_URI[rdfUI->ExtensionCount]; + + uint32_t h2 = 0; + LILV_FOREACH(nodes, it2, lilvExtensionDataNodes) + { + if (h2 >= rdfUI->ExtensionCount) break; + + Lilv::Node lilvExtensionDataNode(lilvExtensionDataNodes.get(it2)); + LV2_URI* const rdfExtension(&rdfUI->Extensions[h2++]); + + if (lilvExtensionDataNode.is_uri()) + { + if (const char* const extURI = lilvExtensionDataNode.as_uri()) + { + *rdfExtension = strdup(extURI); + continue; + } + } + *rdfExtension = NULL; + } + + for (uint32_t x2=h2; x2 < rdfUI->ExtensionCount; ++x2) + rdfUI->Extensions[x2] = NULL; + } + + lilv_nodes_free(const_cast(lilvExtensionDataNodes.me)); + } +#endif + } + } + + lilv_nodes_free(const_cast(lilvUIs.me)); + } + + return rdfDescriptor; +} + +// ----------------------------------------------------------------------- + +#endif // LV2_RDF_UTILS_HPP_INCLUDED diff --git a/mixer/src/Module.C b/mixer/src/Module.C index f41a92a..aa74c42 100644 --- a/mixer/src/Module.C +++ b/mixer/src/Module.C @@ -49,6 +49,7 @@ +nframes_t Module::_buffer_size = 0; nframes_t Module::_sample_rate = 0; Module *Module::_copied_module_empty = 0; char *Module::_copied_module_settings = 0; @@ -903,14 +904,14 @@ Module::insert_menu_cb ( const Fl_Menu_ *m ) mod = new Mono_Pan_Module(); else if ( !strcmp(picked, "Plugin" )) { - unsigned long id = Plugin_Chooser::plugin_chooser( this->ninputs() ); + Picked picked = Plugin_Chooser::plugin_chooser( this->ninputs() ); - if ( id == 0 ) + if ( picked.unique_id == 0 ) return; Plugin_Module *m = new Plugin_Module(); - m->load( id ); + m->load( picked ); mod = m; } diff --git a/mixer/src/Module.H b/mixer/src/Module.H index 7258244..033c1f9 100644 --- a/mixer/src/Module.H +++ b/mixer/src/Module.H @@ -50,6 +50,7 @@ class Module : public Fl_Group, public Loggable { Chain *_chain; bool _is_default; + static nframes_t _buffer_size; static nframes_t _sample_rate; static Module *_copied_module_empty; static char *_copied_module_settings; @@ -87,6 +88,14 @@ public: virtual void update_tooltip ( void ); + struct Picked { + bool is_lv2; + union { + const char* uri; + unsigned long unique_id; + }; + }; + class Port { @@ -548,6 +557,7 @@ protected: bool add_aux_port ( bool input, const char *prefix, int n , JACK::Port::type_e type ); public: + nframes_t buffer_size ( void ) const { return Module::_buffer_size; } nframes_t sample_rate ( void ) const { return Module::_sample_rate; } @@ -561,6 +571,7 @@ public: bool add_aux_audio_input ( const char *prefix, int n ); bool add_aux_cv_input ( const char *prefix, int n ); + static void set_buffer_size ( nframes_t bsize ) { _buffer_size = bsize; } static void set_sample_rate ( nframes_t srate ) { _sample_rate = srate; } void command_open_parameter_editor(); diff --git a/mixer/src/Plugin_Chooser.C b/mixer/src/Plugin_Chooser.C index ea50226..25a40a8 100644 --- a/mixer/src/Plugin_Chooser.C +++ b/mixer/src/Plugin_Chooser.C @@ -32,9 +32,11 @@ static std::vector _plugin_rows; -unsigned long +Module::Picked Plugin_Chooser::plugin_chooser ( int ninputs ) { + Module::Picked picked = { false, 0 }; + Plugin_Chooser *o = new Plugin_Chooser( 0,0,735,500,"Plugin Chooser"); o->ui->inputs_input->value( ninputs ); @@ -46,7 +48,16 @@ Plugin_Chooser::plugin_chooser ( int ninputs ) while ( o->shown() ) Fl::wait(); - unsigned long picked = o->value(); + if (const char* const uri = o->uri()) + { + picked.is_lv2 = true; + picked.uri = uri; + } + else + { + picked.is_lv2 = false; + picked.unique_id = o->value(); + } delete o; @@ -250,7 +261,10 @@ Plugin_Chooser::cb_table ( Fl_Widget *w ) } else { - _value = _plugin_rows[R]->id; + if (::strcmp(_plugin_rows[R]->type, "LV2") == 0) + _uri = _plugin_rows[R]->path; + else + _value = _plugin_rows[R]->id; hide(); } } @@ -363,6 +377,7 @@ Plugin_Chooser::Plugin_Chooser ( int X,int Y,int W,int H, const char *L ) : Fl_Double_Window ( X,Y,W,H,L ) { set_modal(); + _uri = NULL; _value = 0; _plugins = Plugin_Module::get_all_plugins(); diff --git a/mixer/src/Plugin_Chooser.H b/mixer/src/Plugin_Chooser.H index ce67564..9e3eefc 100644 --- a/mixer/src/Plugin_Chooser.H +++ b/mixer/src/Plugin_Chooser.H @@ -37,6 +37,7 @@ class Plugin_Chooser : public Fl_Double_Window void search ( const char *name, const char *author, const char *category, int ninputs, int noutputs, bool favorites ); + const char* _uri; unsigned long _value; int load_favorites ( void ); @@ -46,13 +47,14 @@ class Plugin_Chooser : public Fl_Double_Window void load_categories ( void ); public: + const char* uri ( void ) const { return _uri; } unsigned long value ( void ) const { return _value; } Plugin_Chooser ( int X,int Y,int W,int H, const char *L=0 ); virtual ~Plugin_Chooser( ); - static unsigned long plugin_chooser ( int ninputs ); + static Module::Picked plugin_chooser ( int ninputs ); }; diff --git a/mixer/src/Plugin_Module.C b/mixer/src/Plugin_Module.C index f281c39..f8ffdd6 100644 --- a/mixer/src/Plugin_Module.C +++ b/mixer/src/Plugin_Module.C @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ #define HAVE_LIBLRDF 1 #include "LADSPAInfo.h" +#include "LV2_RDF_Utils.hpp" + #include "Chain.H" //#include "Client/Client.H" @@ -49,15 +52,275 @@ +/* supported lv2 features */ +enum Plugin_Module_Supported_Features { + Plugin_Feature_BufSize_Bounded = 0, + Plugin_Feature_BufSize_Fixed, + Plugin_Feature_Options, + Plugin_Feature_URI_Map, + Plugin_Feature_URID_Map, + Plugin_Feature_URID_Unmap, + Plugin_Features_Count +}; + +/* pre-mapped lv2 uris */ +enum Plugin_Module_URIs { + Plugin_Module_URI_Null = 0, + Plugin_Module_URI_Atom_Double, + Plugin_Module_URI_Atom_Int, + Plugin_Module_URI_BufSize_MaxLength, + Plugin_Module_URI_BufSize_MinLength, + Plugin_Module_URI_Parameter_SampleRate, + Plugin_Module_URI_Count +}; + +/* lv2 plugin options */ +/* mostly empty for now, plugins usually require it because of buf-size extension */ +struct Plugin_Module_Options { + enum OptIndex { + MaxBlockLenth = 0, + MinBlockLenth, + SampleRate, + Null, + Count + }; + + int maxBufferSize; + int minBufferSize; + double sampleRate; + LV2_Options_Option opts[Count]; + + Plugin_Module_Options() + { + maxBufferSize = 0; + minBufferSize = 0; + sampleRate = 0.0; + + LV2_Options_Option& optMaxBlockLenth(opts[MaxBlockLenth]); + optMaxBlockLenth.context = LV2_OPTIONS_INSTANCE; + optMaxBlockLenth.subject = 0; + optMaxBlockLenth.key = Plugin_Module_URI_BufSize_MaxLength; + optMaxBlockLenth.size = sizeof(int); + optMaxBlockLenth.type = Plugin_Module_URI_Atom_Int; + optMaxBlockLenth.value = &maxBufferSize; + + LV2_Options_Option& optMinBlockLenth(opts[MinBlockLenth]); + optMinBlockLenth.context = LV2_OPTIONS_INSTANCE; + optMinBlockLenth.subject = 0; + optMinBlockLenth.key = Plugin_Module_URI_BufSize_MinLength; + optMinBlockLenth.size = sizeof(int); + optMinBlockLenth.type = Plugin_Module_URI_Atom_Int; + optMinBlockLenth.value = &minBufferSize; + + LV2_Options_Option& optSampleRate(opts[SampleRate]); + optSampleRate.context = LV2_OPTIONS_INSTANCE; + optSampleRate.subject = 0; + optSampleRate.key = Plugin_Module_URI_Parameter_SampleRate; + optSampleRate.size = sizeof(double); + optSampleRate.type = Plugin_Module_URI_Atom_Double; + optSampleRate.value = &sampleRate; + + LV2_Options_Option& optNull(opts[Null]); + optNull.context = LV2_OPTIONS_INSTANCE; + optNull.subject = 0; + optNull.key = Plugin_Module_URI_Null; + optNull.size = 0; + optNull.type = Plugin_Module_URI_Null; + optNull.value = NULL; + } +}; + +/* handy class to handle lv2 open/close */ +class LV2_Lib_Manager +{ +public: + LV2_Lib_Manager() {} + + ~LV2_Lib_Manager() + { + for (std::vector::iterator it=libraries.begin(), end=libraries.end(); it != end; ++it) + { + LibraryInfo& libinfo (*it); + + if ( libinfo.handle ) + dlclose( libinfo.handle ); + } + + libraries.clear(); + } + + const LV2_Descriptor* get_descriptor_for_uri(const std::string& binary, const char* uri) + { + for (std::vector::iterator it=libraries.begin(), end=libraries.end(); it != end; ++it) + { + const LibraryInfo& libinfo(*it); + + if (libinfo.binary == binary) + return libinfo.desc; + } + + if (void* const handle = dlopen(binary.c_str(), RTLD_LAZY)) + { + if (LV2_Descriptor_Function descfn = (LV2_Descriptor_Function)dlsym(handle, "lv2_descriptor")) + { + uint32_t i=0; + const LV2_Descriptor* desc; + while ((desc = descfn(i++)) != NULL) + { + if ( ::strcmp(desc->URI, uri) == 0) + break; + } + if ( ! desc ) return NULL; + + LibraryInfo info; + info.binary = binary; + info.handle = handle; + info.desc = desc; + libraries.push_back( info ); + + return desc; + } + } + + return NULL; + } + +private: + struct LibraryInfo { + std::string binary; + void* handle; + const LV2_Descriptor* desc; + }; + std::vector libraries; +}; + +static LV2_Lib_Manager lv2_lib_manager; + static LADSPAInfo *ladspainfo; Thread* Plugin_Module::plugin_discover_thread; /* keep this out of the header to avoid spreading ladspa.h dependency */ struct Plugin_Module::ImplementationData { - const LADSPA_Descriptor *descriptor; -// std::vector m_LADSPABufVec; - std::vector handle; + const LADSPA_Descriptor *descriptor; + struct { + const LV2_Descriptor *descriptor; + const LV2_RDF_Descriptor *rdf_data; + LV2_Feature* features[Plugin_Features_Count+1]; + // extension data + Plugin_Module_Options options; + std::vector mappedURIs; + // extensions + struct { + const LV2_Options_Interface* options; + const LV2_State_Interface* state; + const LV2_Worker_Interface* worker; + } ext; + } lv2; + std::vector handle; + + ImplementationData() + { + descriptor = NULL; + lv2.descriptor = NULL; + lv2.rdf_data = NULL; + + for (int i=0; iURI = NULL; + lv2.features[i]->data = NULL; + } + lv2.features[Plugin_Features_Count] = NULL; + + lv2.mappedURIs.push_back(""); // Plugin_Module_URI_Null + lv2.mappedURIs.push_back(LV2_ATOM__Double); // Plugin_Module_URI_Atom_Double + lv2.mappedURIs.push_back(LV2_ATOM__Int); // Plugin_Module_URI_Atom_Int + lv2.mappedURIs.push_back(LV2_BUF_SIZE__maxBlockLength); // Plugin_Module_URI_BufSize_MaxLength + lv2.mappedURIs.push_back(LV2_BUF_SIZE__minBlockLength); // Plugin_Module_URI_BufSize_MinLength + lv2.mappedURIs.push_back(LV2_PARAMETERS__sampleRate); // Plugin_Module_URI_Parameter_SampleRate + + lv2.ext.options = NULL; + lv2.ext.state = NULL; + lv2.ext.worker = NULL; + } + + ~ImplementationData() + { + if ( lv2.rdf_data ) + { + delete lv2.rdf_data; + lv2.rdf_data = NULL; + } + + if ( lv2.features[Plugin_Feature_URI_Map] && lv2.features[Plugin_Feature_URI_Map]->data ) + delete (LV2_URI_Map_Feature*)lv2.features[Plugin_Feature_URI_Map]->data; + + if ( lv2.features[Plugin_Feature_URID_Map] && lv2.features[Plugin_Feature_URID_Map]->data ) + delete (LV2_URID_Map*)lv2.features[Plugin_Feature_URID_Map]->data; + + if ( lv2.features[Plugin_Feature_URID_Unmap] && lv2.features[Plugin_Feature_URID_Unmap]->data ) + delete (LV2_URID_Unmap*)lv2.features[Plugin_Feature_URID_Unmap]->data; + } + + // ------------------------------------------------------------------- + // LV2 Features + + static uint32_t _lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char*, const char* uri) + { + return _lv2_urid_map(data, uri); + } + + static LV2_URID _lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri) + { + if ( handle == NULL || ! uri ) + return Plugin_Module_URI_Null; + if ( ::strcmp(uri, LV2_ATOM__Double) == 0 ) + return Plugin_Module_URI_Atom_Double; + if ( ::strcmp(uri, LV2_ATOM__Int) == 0 ) + return Plugin_Module_URI_Atom_Int; + if ( ::strcmp(uri, LV2_BUF_SIZE__maxBlockLength) == 0 ) + return Plugin_Module_URI_BufSize_MaxLength; + if ( ::strcmp(uri, LV2_BUF_SIZE__minBlockLength) == 0 ) + return Plugin_Module_URI_BufSize_MinLength; + if ( ::strcmp(uri, LV2_PARAMETERS__sampleRate) == 0 ) + return Plugin_Module_URI_Parameter_SampleRate; + + ImplementationData* self = (ImplementationData*)handle; + + uint32_t ret = 0; + for (std::vector::iterator it = self->lv2.mappedURIs.begin(), end = self->lv2.mappedURIs.end(); it != end; ++it) + { + if (ret == 0) + { + ret = 1; + continue; + } + + const std::string& thisURI(*it); + + if ( thisURI == uri ) + return ret; + + ++ret; + } + + self->lv2.mappedURIs.push_back(uri); + return ret; + } + + static const char* _lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) + { + if ( handle == NULL || urid == 0 ) + return NULL; + + ImplementationData* self = (ImplementationData*)handle; + + if ( urid <= self->lv2.mappedURIs.size() ) + return self->lv2.mappedURIs[urid].c_str(); + + return NULL; + } }; @@ -84,7 +347,10 @@ Plugin_Module::get ( Log_Entry &e ) const { // char s[512]; // snprintf( s, sizeof( s ), "ladspa:%lu", _idata->descriptor->UniqueID ); - e.add( ":plugin_id", _idata->descriptor->UniqueID ); + if (_is_lv2) + e.add( ":lv2_plugin_uri", _idata->lv2.descriptor->URI ); + else + e.add( ":plugin_id", _idata->descriptor->UniqueID ); /* these help us display the module on systems which are missing this plugin */ e.add( ":plugin_ins", _plugin_ins ); @@ -104,7 +370,11 @@ Plugin_Module::set ( Log_Entry &e ) if ( ! strcmp( s, ":plugin_id" ) ) { - load( (unsigned long) atoll ( v ) ); + load_ladspa( (unsigned long) atoll ( v ) ); + } + else if ( ! strcmp( s, ":lv2_plugin_uri" ) ) + { + load_lv2( v ); } else if ( ! strcmp( s, ":plugin_ins" ) ) { @@ -127,10 +397,10 @@ Plugin_Module::init ( void ) _latency = 0; _last_latency = 0; _idata = new Plugin_Module::ImplementationData(); - _idata->handle.clear(); /* module will be bypassed until plugin is loaded */ _bypass = true; _crosswire = false; + _is_lv2 = false; align( (Fl_Align)FL_ALIGN_CENTER | FL_ALIGN_INSIDE ); // color( (Fl_Color)fl_color_average( FL_MAGENTA, FL_WHITE, 0.5f ) ); @@ -138,6 +408,41 @@ Plugin_Module::init ( void ) int tw, th, tx, ty; bbox( tx, ty, tw, th ); + + // init lv2 stuff + _idata->lv2.options.maxBufferSize = buffer_size(); + _idata->lv2.options.minBufferSize = buffer_size(); + _idata->lv2.options.sampleRate = sample_rate(); + + LV2_URI_Map_Feature* const uriMapFt = new LV2_URI_Map_Feature; + uriMapFt->callback_data = _idata; + uriMapFt->uri_to_id = ImplementationData::_lv2_uri_to_id; + + LV2_URID_Map* const uridMapFt = new LV2_URID_Map; + uridMapFt->handle = _idata; + uridMapFt->map = ImplementationData::_lv2_urid_map; + + LV2_URID_Unmap* const uridUnmapFt = new LV2_URID_Unmap; + uridUnmapFt->handle = _idata; + uridUnmapFt->unmap = ImplementationData::_lv2_urid_unmap; + + _idata->lv2.features[Plugin_Feature_BufSize_Bounded]->URI = LV2_BUF_SIZE__boundedBlockLength; + _idata->lv2.features[Plugin_Feature_BufSize_Bounded]->data = NULL; + + _idata->lv2.features[Plugin_Feature_BufSize_Fixed]->URI = LV2_BUF_SIZE__fixedBlockLength; + _idata->lv2.features[Plugin_Feature_BufSize_Fixed]->data = NULL; + + _idata->lv2.features[Plugin_Feature_Options]->URI = LV2_OPTIONS__options; + _idata->lv2.features[Plugin_Feature_Options]->data = _idata->lv2.options.opts; + + _idata->lv2.features[Plugin_Feature_URI_Map]->URI = LV2_URI_MAP_URI; + _idata->lv2.features[Plugin_Feature_URI_Map]->data = uriMapFt; + + _idata->lv2.features[Plugin_Feature_URID_Map]->URI = LV2_URID__map; + _idata->lv2.features[Plugin_Feature_URID_Map]->data = uridMapFt; + + _idata->lv2.features[Plugin_Feature_URID_Unmap]->URI = LV2_URID__unmap; + _idata->lv2.features[Plugin_Feature_URID_Unmap]->data = uridUnmapFt; } void @@ -258,6 +563,8 @@ Plugin_Module::discover_thread ( void * ) ladspainfo = new LADSPAInfo(); + Lv2WorldClass::getInstance().initIfNeeded(/*::getenv("LV2_PATH")*/); + return NULL; } @@ -301,7 +608,7 @@ Plugin_Module::get_all_plugins ( void ) for (std::vector::iterator i=plugins.begin(); i!=plugins.end(); i++, j++) { - Plugin_Info pi; + Plugin_Info pi(false); // pi[j].path = i->Name.c_str(); pi.path = NULL; @@ -314,6 +621,102 @@ Plugin_Module::get_all_plugins ( void ) pr.push_back( pi ); } + const Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); + for (uint i=0, count=lv2World.getPluginCount(); i(featureNodes.me)); + + if ( ! supported ) + continue; + + Plugin_Info pi(true); + + // get audio port count and check for supported ports + pi.audio_inputs = 0; + pi.audio_outputs = 0; + + for (uint j=0, count=lilvPlugin.get_num_ports(); j pe = ladspainfo->GetMenuList(); @@ -342,12 +745,24 @@ Plugin_Module::plugin_instances ( unsigned int n ) { DMESSAGE( "Destroying plugin instance" ); - LADSPA_Handle h = _idata->handle.back(); + if (_is_lv2) + { + LV2_Handle h = _idata->handle.back(); - if ( _idata->descriptor->deactivate ) - _idata->descriptor->deactivate( h ); - if ( _idata->descriptor->cleanup ) - _idata->descriptor->cleanup( h ); + if ( _idata->lv2.descriptor->deactivate ) + _idata->lv2.descriptor->deactivate( h ); + if ( _idata->lv2.descriptor->cleanup ) + _idata->lv2.descriptor->cleanup( h ); + } + else + { + LADSPA_Handle h = _idata->handle.back(); + + if ( _idata->descriptor->deactivate ) + _idata->descriptor->deactivate( h ); + if ( _idata->descriptor->cleanup ) + _idata->descriptor->cleanup( h ); + } _idata->handle.pop_back(); } @@ -356,14 +771,25 @@ Plugin_Module::plugin_instances ( unsigned int n ) { for ( int i = n - _idata->handle.size(); i--; ) { - LADSPA_Handle h; - DMESSAGE( "Instantiating plugin... with sample rate %lu", (unsigned long)sample_rate()); - if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) ) + void* h; + + if (_is_lv2) { - WARNING( "Failed to instantiate plugin" ); - return false; + if ( ! (h = _idata->lv2.descriptor->instantiate( _idata->lv2.descriptor, sample_rate(), _idata->lv2.rdf_data->Bundle, _idata->lv2.features ) ) ) + { + WARNING( "Failed to instantiate plugin" ); + return false; + } + } + else + { + if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) ) + { + WARNING( "Failed to instantiate plugin" ); + return false; + } } DMESSAGE( "Instantiated: %p", h ); @@ -374,22 +800,45 @@ Plugin_Module::plugin_instances ( unsigned int n ) int ij = 0; int oj = 0; - for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) + if (_is_lv2) { - if ( LADSPA_IS_PORT_CONTROL( _idata->descriptor->PortDescriptors[k] ) ) + for ( unsigned int k = 0; k < _idata->lv2.rdf_data->PortCount; ++k ) { - if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[k] ) ) - _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_input[ij++].buffer() ); - else if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[k] ) ) - _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_output[oj++].buffer() ); + if ( LV2_IS_PORT_CONTROL( _idata->lv2.rdf_data->Ports[k].Types ) ) + { + if ( LADSPA_IS_PORT_INPUT( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, (LADSPA_Data*)control_input[ij++].buffer() ); + else if ( LADSPA_IS_PORT_OUTPUT( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, (LADSPA_Data*)control_output[oj++].buffer() ); + } + // we need to connect non audio/control ports to NULL + else if ( ! LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, NULL ); } + + // connect ports to magic bogus value to aid debugging. + for ( unsigned int k = 0; k < _idata->lv2.rdf_data->PortCount; ++k ) + if ( LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, (float*)0x42 ); } + else + { + for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) + { + if ( LADSPA_IS_PORT_CONTROL( _idata->descriptor->PortDescriptors[k] ) ) + { + if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[k] ) ) + _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_input[ij++].buffer() ); + else if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[k] ) ) + _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_output[oj++].buffer() ); + } + } - // connect ports to magic bogus value to aid debugging. - for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) - if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) - _idata->descriptor->connect_port( h, k, (LADSPA_Data*)0x42 ); - + // connect ports to magic bogus value to aid debugging. + for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) + if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) + _idata->descriptor->connect_port( h, k, (LADSPA_Data*)0x42 ); + } } } @@ -411,19 +860,38 @@ Plugin_Module::bypass ( bool v ) nframes_t Plugin_Module::get_module_latency ( void ) const { - for ( unsigned int i = ncontrol_outputs(); i--; ) + // FIXME: we should probably cache this value + if (_is_lv2) { - if ( !strcasecmp( "latency", control_output[i].name() ) ) + unsigned int nport = 0; + + for ( unsigned int i = 0; i < _idata->lv2.rdf_data->PortCount; ++i ) { - return control_output[i].control_value(); + if ( LV2_IS_PORT_OUTPUT( _idata->lv2.rdf_data->Ports[i].Types ) && + LV2_IS_PORT_CONTROL( _idata->lv2.rdf_data->Ports[i].Types ) ) + { + if ( LV2_IS_PORT_DESIGNATION_LATENCY( _idata->lv2.rdf_data->Ports[i].Designation ) ) + return control_output[nport].control_value(); + ++nport; + } } - } + } + else + { + for ( unsigned int i = ncontrol_outputs(); i--; ) + { + if ( !strcasecmp( "latency", control_output[i].name() ) ) + { + return control_output[i].control_value(); + } + } + } return 0; } bool -Plugin_Module::load ( unsigned long id ) +Plugin_Module::load ( Module::Picked picked ) { if ( !ladspainfo ) { @@ -433,6 +901,13 @@ Plugin_Module::load ( unsigned long id ) plugin_discover_thread->join(); } + return picked.is_lv2 ? load_lv2(picked.uri) : load_ladspa(picked.unique_id); +} + +bool +Plugin_Module::load_ladspa ( unsigned long id ) +{ + _is_lv2 = false; _idata->descriptor = ladspainfo->GetDescriptorByID( id ); _plugin_ins = _plugin_outs = 0; @@ -662,10 +1137,205 @@ Plugin_Module::load ( unsigned long id ) return instances; } +bool +Plugin_Module::load_lv2 ( const char* uri ) +{ + _is_lv2 = true; + _idata->lv2.rdf_data = lv2_rdf_new( uri, false ); + + _plugin_ins = _plugin_outs = 0; + + if ( ! _idata->lv2.rdf_data ) + { + /* unknown plugin URI */ + WARNING( "Unknown plugin URI: %s", uri ); + label( "----" ); + return false; + } + + _idata->lv2.descriptor = lv2_lib_manager.get_descriptor_for_uri( _idata->lv2.rdf_data->Binary, uri ); + + label( _idata->lv2.rdf_data->Name ); + + if ( _idata->lv2.descriptor ) + { + MESSAGE( "Name: %s", _idata->lv2.rdf_data->Name ); + + if ( _idata->lv2.descriptor->extension_data ) + { + bool hasOptions = false; + bool hasState = false; + bool hasWorker = false; + + for (uint32_t i=0, count=_idata->lv2.rdf_data->ExtensionCount; ilv2.rdf_data->Extensions[i]); + + /**/ if ( ! extension) + continue; + else if ( ::strcmp(extension, LV2_OPTIONS__interface) == 0 ) + hasOptions = true; + else if ( ::strcmp(extension, LV2_STATE__interface) == 0 ) + hasState = true; + else if ( ::strcmp(extension, LV2_WORKER__interface) == 0 ) + hasWorker = true; + } + + if (hasOptions) + _idata->lv2.ext.options = (const LV2_Options_Interface*)_idata->lv2.descriptor->extension_data(LV2_OPTIONS__interface); + + if (hasState) + _idata->lv2.ext.state = (const LV2_State_Interface*)_idata->lv2.descriptor->extension_data(LV2_STATE__interface); + + if (hasWorker) + _idata->lv2.ext.worker = (const LV2_Worker_Interface*)_idata->lv2.descriptor->extension_data(LV2_WORKER__interface); + + // check if invalid + if ( _idata->lv2.ext.options != NULL && _idata->lv2.ext.options->get == NULL && _idata->lv2.ext.options->set == NULL ) + _idata->lv2.ext.options = NULL; + + if ( _idata->lv2.ext.state != NULL && ( _idata->lv2.ext.state->save == NULL || _idata->lv2.ext.state->restore == NULL )) + _idata->lv2.ext.state = NULL; + + if ( _idata->lv2.ext.worker != NULL && _idata->lv2.ext.worker->work == NULL ) + _idata->lv2.ext.worker = NULL; + } + else + { + _idata->lv2.ext.options = NULL; + _idata->lv2.ext.state = NULL; + _idata->lv2.ext.worker = NULL; + } + + for ( unsigned int i = 0; i < _idata->lv2.rdf_data->PortCount; ++i ) + { + if ( LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[i].Types ) ) + { + if ( LV2_IS_PORT_INPUT( _idata->lv2.rdf_data->Ports[i].Types ) ) + { + add_port( Port( this, Port::INPUT, Port::AUDIO, _idata->lv2.rdf_data->Ports[i].Name ) ); + _plugin_ins++; + } + else if (LV2_IS_PORT_OUTPUT(_idata->lv2.rdf_data->Ports[i].Types)) + { + _plugin_outs++; + add_port( Port( this, Port::OUTPUT, Port::AUDIO, _idata->lv2.rdf_data->Ports[i].Name ) ); + } + } + } + + MESSAGE( "Plugin has %i inputs and %i outputs", _plugin_ins, _plugin_outs); + + for ( unsigned int i = 0; i < _idata->lv2.rdf_data->PortCount; ++i ) + { + if ( LV2_IS_PORT_CONTROL( _idata->lv2.rdf_data->Ports[i].Types ) ) + { + const LV2_RDF_Port& rdfport ( _idata->lv2.rdf_data->Ports[i] ); + + Port::Direction d = Port::INPUT; + + if ( LV2_IS_PORT_INPUT( rdfport.Types ) ) + { + d = Port::INPUT; + } + else if ( LV2_IS_PORT_OUTPUT( rdfport.Types ) ) + { + d = Port::OUTPUT; + } + + Port p( this, d, Port::CONTROL, rdfport.Name ); + + if ( LV2_HAVE_MINIMUM_PORT_POINT( rdfport.Points.Hints ) ) + { + p.hints.ranged = true; + p.hints.minimum = rdfport.Points.Minimum; + } + else + { + p.hints.minimum = 0.0f; + } + + if ( LV2_HAVE_MAXIMUM_PORT_POINT( rdfport.Points.Hints ) ) + { + p.hints.ranged = true; + p.hints.maximum = rdfport.Points.Maximum; + } + else + { + // just in case + p.hints.maximum = p.hints.minimum + 0.1f; + } + + if ( LV2_HAVE_DEFAULT_PORT_POINT( rdfport.Points.Hints ) ) + { + p.hints.default_value = rdfport.Points.Default; + } + else + { + // just in case + p.hints.default_value = p.hints.minimum; + } + + if ( LV2_IS_PORT_SAMPLE_RATE( rdfport.Properties ) ) + { + p.hints.minimum *= sample_rate(); + p.hints.maximum *= sample_rate(); + p.hints.default_value *= sample_rate(); + } + + if ( LV2_IS_PORT_TOGGLED( rdfport.Properties ) ) + p.hints.type = Port::Hints::BOOLEAN; + if ( LV2_IS_PORT_INTEGER( rdfport.Properties ) ) + p.hints.type = Port::Hints::INTEGER; + if ( LV2_IS_PORT_LOGARITHMIC( rdfport.Properties ) ) + p.hints.type = Port::Hints::LOGARITHMIC; + + if ( LV2_IS_PORT_DESIGNATION_FREEWHEELING (rdfport.Designation) || + LV2_IS_PORT_DESIGNATION_SAMPLE_RATE (rdfport.Designation) || + LV2_IS_PORT_DESIGNATION_LATENCY (rdfport.Designation) || + LV2_IS_PORT_DESIGNATION_TIME (rdfport.Designation) || + LV2_IS_PORT_NOT_ON_GUI( rdfport.Properties ) ) + { + p.hints.visible = false; + + if ( LV2_IS_PORT_DESIGNATION_SAMPLE_RATE (rdfport.Designation) ) + p.hints.default_value = sample_rate(); + } + + float *control_value = new float; + + *control_value = p.hints.default_value; + + p.connect_to( control_value ); + + add_port( p ); + + DMESSAGE( "Plugin has control port \"%s\" (default: %f)", rdfport.Name, p.hints.default_value ); + } + } + } + else + { + WARNING( "Failed to load plugin" ); + delete _idata->lv2.rdf_data; + _idata->lv2.rdf_data = NULL; + return false; + } + + int instances = plugin_instances( 1 ); + + if ( instances ) + { + bypass( false ); + } + + return instances; +} + void Plugin_Module::set_input_buffer ( int n, void *buf ) { - LADSPA_Handle h; + void* h; if ( instances() > 1 ) { @@ -675,23 +1345,34 @@ Plugin_Module::set_input_buffer ( int n, void *buf ) else h = _idata->handle[0]; - for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i ) - if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[i] ) && - LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[i] ) ) - if ( n-- == 0 ) - _idata->descriptor->connect_port( h, i, (LADSPA_Data*)buf ); + if (_is_lv2) + { + for ( unsigned int i = 0; i < _idata->lv2.rdf_data->PortCount; ++i ) + if ( LV2_IS_PORT_INPUT( _idata->lv2.rdf_data->Ports[i].Types ) && + LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[i].Types ) ) + if ( n-- == 0 ) + _idata->lv2.descriptor->connect_port( h, i, (float*)buf ); + } + else + { + for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i ) + if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[i] ) && + LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[i] ) ) + if ( n-- == 0 ) + _idata->descriptor->connect_port( h, i, (LADSPA_Data*)buf ); + } } bool Plugin_Module::loaded ( void ) const { - return _idata->descriptor; + return _idata->handle.size() > 0 && ( _is_lv2 ? _idata->lv2.rdf_data && _idata->lv2.descriptor : _idata->descriptor != NULL ); } void Plugin_Module::set_output_buffer ( int n, void *buf ) { - LADSPA_Handle h; + void* h; if ( instances() > 1 ) { @@ -701,11 +1382,22 @@ Plugin_Module::set_output_buffer ( int n, void *buf ) else h = _idata->handle[0]; - for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i ) - if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[i] ) && - LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[i] ) ) - if ( n-- == 0 ) - _idata->descriptor->connect_port( h, i, (LADSPA_Data*)buf ); + if (_is_lv2) + { + for ( unsigned int i = 0; i < _idata->lv2.rdf_data->PortCount; ++i ) + if ( LV2_IS_PORT_OUTPUT( _idata->lv2.rdf_data->Ports[i].Types ) && + LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[i].Types ) ) + if ( n-- == 0 ) + _idata->lv2.descriptor->connect_port( h, i, (float*)buf ); + } + else + { + for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i ) + if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[i] ) && + LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[i] ) ) + if ( n-- == 0 ) + _idata->descriptor->connect_port( h, i, (LADSPA_Data*)buf ); + } } void @@ -722,9 +1414,18 @@ Plugin_Module::activate ( void ) if ( chain() ) chain()->client()->lock(); - if ( _idata->descriptor->activate ) - for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) - _idata->descriptor->activate( _idata->handle[i] ); + if (_is_lv2) + { + if ( _idata->lv2.descriptor->activate ) + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + _idata->lv2.descriptor->activate( _idata->handle[i] ); + } + else + { + if ( _idata->descriptor->activate ) + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + _idata->descriptor->activate( _idata->handle[i] ); + } _bypass = false; @@ -744,10 +1445,19 @@ Plugin_Module::deactivate( void ) chain()->client()->lock(); _bypass = true; - - if ( _idata->descriptor->deactivate ) - for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) - _idata->descriptor->deactivate( _idata->handle[i] ); + + if (_is_lv2) + { + if ( _idata->lv2.descriptor->deactivate ) + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + _idata->lv2.descriptor->deactivate( _idata->handle[i] ); + } + else + { + if ( _idata->descriptor->deactivate ) + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + _idata->descriptor->deactivate( _idata->handle[i] ); + } if ( chain() ) chain()->client()->unlock(); @@ -776,6 +1486,62 @@ Plugin_Module::handle_port_connection_change ( void ) } } +void +Plugin_Module::handle_sample_rate_change ( nframes_t sample_rate ) +{ + if ( ! _is_lv2 ) + return; + if ( ! _idata->lv2.rdf_data ) + return; + + _idata->lv2.options.sampleRate = sample_rate; + + if ( _idata->lv2.ext.options && _idata->lv2.ext.options->set ) + { + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + _idata->lv2.ext.options->set( _idata->handle[i], &(_idata->lv2.options.opts[Plugin_Module_Options::SampleRate]) ); + } + + unsigned int nport = 0; + + for ( unsigned int i = 0; i < _idata->lv2.rdf_data->PortCount; ++i ) + { + if ( LV2_IS_PORT_INPUT( _idata->lv2.rdf_data->Ports[i].Types ) && + LV2_IS_PORT_CONTROL( _idata->lv2.rdf_data->Ports[i].Types ) ) + { + if ( LV2_IS_PORT_DESIGNATION_SAMPLE_RATE( _idata->lv2.rdf_data->Ports[i].Designation ) ) + { + control_input[nport].control_value( sample_rate ); + break; + } + ++nport; + } + } +} + +void +Plugin_Module::resize_buffers ( nframes_t buffer_size ) +{ + Module::resize_buffers( buffer_size ); + + if ( ! _is_lv2 ) + return; + if ( ! _idata->lv2.rdf_data ) + return; + + _idata->lv2.options.maxBufferSize = buffer_size; + _idata->lv2.options.minBufferSize = buffer_size; + + if ( _idata->lv2.ext.options && _idata->lv2.ext.options->set ) + { + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + { + _idata->lv2.ext.options->set( _idata->handle[i], &(_idata->lv2.options.opts[Plugin_Module_Options::MaxBlockLenth]) ); + _idata->lv2.ext.options->set( _idata->handle[i], &(_idata->lv2.options.opts[Plugin_Module_Options::MinBlockLenth]) ); + } + } +} + bool @@ -796,55 +1562,118 @@ Plugin_Module::apply ( sample_t *buf, nframes_t nframes ) { // actually osc or UI THREAD_ASSERT( UI ); - LADSPA_Handle h; + void* h; - if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) ) + if (_is_lv2) { - WARNING( "Failed to instantiate plugin" ); - return false; + if ( ! (h = _idata->lv2.descriptor->instantiate( _idata->lv2.descriptor, sample_rate(), _idata->lv2.rdf_data->Bundle, _idata->lv2.features ) ) ) + { + WARNING( "Failed to instantiate plugin" ); + return false; + } + } + else + { + if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) ) + { + WARNING( "Failed to instantiate plugin" ); + return false; + } } int ij = 0; int oj = 0; - for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) + if (_is_lv2) { - if ( LADSPA_IS_PORT_CONTROL( _idata->descriptor->PortDescriptors[k] ) ) + for ( unsigned int k = 0; k < _idata->lv2.rdf_data->PortCount; ++k ) { - if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[k] ) ) - _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_input[ij++].buffer() ); - else if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[k] ) ) - _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_output[oj++].buffer() ); + if ( LV2_IS_PORT_CONTROL( _idata->lv2.rdf_data->Ports[k].Types ) ) + { + if ( LV2_IS_PORT_INPUT( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, (float*)control_input[ij++].buffer() ); + else if ( LV2_IS_PORT_OUTPUT( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, (float*)control_output[oj++].buffer() ); + } + // we need to connect non audio/control ports to NULL + else if ( ! LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, NULL ); } + + if ( _idata->lv2.descriptor->activate ) + _idata->lv2.descriptor->activate( h ); + } + else + { + for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) + { + if ( LADSPA_IS_PORT_CONTROL( _idata->descriptor->PortDescriptors[k] ) ) + { + if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[k] ) ) + _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_input[ij++].buffer() ); + else if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[k] ) ) + _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_output[oj++].buffer() ); + } + } + + if ( _idata->descriptor->activate ) + _idata->descriptor->activate( h ); } - - - if ( _idata->descriptor->activate ) - _idata->descriptor->activate( h ); int tframes = 512; float tmp[tframes]; memset( tmp, 0, sizeof( float ) * tframes ); - for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) - if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) - _idata->descriptor->connect_port( h, k, tmp ); - + if (_is_lv2) + { + for ( unsigned int k = 0; k < _idata->lv2.rdf_data->PortCount; ++k ) + if ( LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, tmp ); + } + else + { + for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) + if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) + _idata->descriptor->connect_port( h, k, tmp ); + } /* flush any parameter interpolation */ - _idata->descriptor->run( h, tframes ); - - for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) - if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) - _idata->descriptor->connect_port( h, k, buf ); - + if (_is_lv2) + { + _idata->lv2.descriptor->run( h, tframes ); + + for ( unsigned int k = 0; k < _idata->lv2.rdf_data->PortCount; ++k ) + if ( LV2_IS_PORT_AUDIO( _idata->lv2.rdf_data->Ports[k].Types ) ) + _idata->lv2.descriptor->connect_port( h, k, buf ); + } + else + { + _idata->descriptor->run( h, tframes ); + + for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) + if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) + _idata->descriptor->connect_port( h, k, buf ); + } + /* run for real */ - _idata->descriptor->run( h, nframes ); - - if ( _idata->descriptor->deactivate ) - _idata->descriptor->deactivate( h ); - if ( _idata->descriptor->cleanup ) - _idata->descriptor->cleanup( h ); + if (_is_lv2) + { + _idata->lv2.descriptor->run( h, nframes ); + + if ( _idata->lv2.descriptor->deactivate ) + _idata->lv2.descriptor->deactivate( h ); + if ( _idata->lv2.descriptor->cleanup ) + _idata->lv2.descriptor->cleanup( h ); + } + else + { + _idata->descriptor->run( h, nframes ); + + if ( _idata->descriptor->deactivate ) + _idata->descriptor->deactivate( h ); + if ( _idata->descriptor->cleanup ) + _idata->descriptor->cleanup( h ); + } return true; } @@ -870,8 +1699,16 @@ Plugin_Module::process ( nframes_t nframes ) } else { - for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) - _idata->descriptor->run( _idata->handle[i], nframes ); + if (_is_lv2) + { + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + _idata->lv2.descriptor->run( _idata->handle[i], nframes ); + } + else + { + for ( unsigned int i = 0; i < _idata->handle.size(); ++i ) + _idata->descriptor->run( _idata->handle[i], nframes ); + } _latency = get_module_latency(); } diff --git a/mixer/src/Plugin_Module.H b/mixer/src/Plugin_Module.H index 7409e8d..0c35ded 100644 --- a/mixer/src/Plugin_Module.H +++ b/mixer/src/Plugin_Module.H @@ -44,14 +44,14 @@ public: const char *type; bool favorite; - Plugin_Info ( ) + Plugin_Info ( bool is_lv2 ) { path = 0; id = 0; audio_inputs = 0; audio_outputs = 0; - type = "LADSPA"; + type = is_lv2 ? "LV2" : "LADSPA"; favorite = 0; } @@ -61,10 +61,13 @@ public: } }; - bool load ( unsigned long id ); + bool load ( Picked picked ); private: + bool load_ladspa ( unsigned long id ); + bool load_lv2 ( const char* uri ); + volatile nframes_t _latency; nframes_t _last_latency; @@ -90,6 +93,7 @@ private: int _plugin_ins; int _plugin_outs; bool _crosswire; + bool _is_lv2; static void *discover_thread ( void * ); @@ -141,6 +145,8 @@ public: virtual void process ( nframes_t ); void handle_port_connection_change ( void ); + void handle_sample_rate_change ( nframes_t sample_rate ); + void resize_buffers ( nframes_t buffer_size ); LOG_CREATE_FUNC( Plugin_Module ); diff --git a/mixer/src/lilv/lilvmm.hpp b/mixer/src/lilv/lilvmm.hpp new file mode 100644 index 0000000..1f08e9f --- /dev/null +++ b/mixer/src/lilv/lilvmm.hpp @@ -0,0 +1,363 @@ +/* + Copyright 2007-2014 David Robillard + + 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" + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +# define LILV_DEPRECATED __attribute__((__deprecated__)) +#else +# define LILV_DEPRECATED +#endif + +namespace Lilv { + +static inline const char* +uri_to_path(const char* uri) { + return lilv_uri_to_path(uri); +} + +#define LILV_WRAP0(RT, prefix, name) \ + inline RT name() { return lilv_ ## prefix ## _ ## name (me); } + +#define LILV_WRAP0_CONST(RT, prefix, name) \ + inline RT name() const { 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(LilvNode* node) : me(node) {} + inline Node(const LilvNode* node) : me(lilv_node_duplicate(node)) {} + inline Node(const Node& copy) : me(lilv_node_duplicate(copy.me)) {} + + 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_CONST(char*, node, get_turtle_token); + LILV_WRAP0_CONST(bool, node, is_uri); + LILV_WRAP0_CONST(const char*, node, as_uri); + LILV_WRAP0_CONST(bool, node, is_blank); + LILV_WRAP0_CONST(const char*, node, as_blank); + LILV_WRAP0_CONST(bool, node, is_literal); + LILV_WRAP0_CONST(bool, node, is_string); + LILV_WRAP0_CONST(const char*, node, as_string); + LILV_WRAP0_CONST(bool, node, is_float); + LILV_WRAP0_CONST(float, node, as_float); + LILV_WRAP0_CONST(bool, node, is_int); + LILV_WRAP0_CONST(int, node, as_int); + LILV_WRAP0_CONST(bool, node, is_bool); + LILV_WRAP0_CONST(bool, node, as_bool); + + Node& operator=(const Node& copy) { + lilv_node_free(me); + me = lilv_node_duplicate(copy.me); + return *this; + } + + 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(const 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(const 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); + + inline Node get_first() const { + return Node((const LilvNode*)lilv_nodes_get_first(me)); + } +}; + +struct UI { + inline UI(const LilvUI* c_obj) : me(c_obj) {} + LILV_WRAP_CONVERSION(const LilvUI); + + LILV_WRAP0(Node, ui, get_uri); + LILV_WRAP1(bool, ui, is_a, LilvNode*, ui_class); + LILV_WRAP0(Node, ui, get_bundle_uri); + LILV_WRAP0(Node, ui, get_binary_uri); +#if 0 /* needs custom lilv */ + LILV_WRAP0(Nodes, ui, get_supported_features); + LILV_WRAP0(Nodes, ui, get_required_features); + LILV_WRAP0(Nodes, ui, get_optional_features); + LILV_WRAP0(Nodes, ui, get_extension_data); +#endif + + 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, Node, pred); + LILV_WRAP1(bool, plugin, has_feature, 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, Node, type); + + inline Port get_port_by_index(unsigned index) { + return Port(me, lilv_plugin_get_port_by_index(me, index)); + } + + inline Port get_port_by_symbol(LilvNode* symbol) { + 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) { + return lilv_plugin_get_port_ranges_float( + me, min_values, max_values, def_values); + } + + inline unsigned get_num_ports_of_class(LilvNode* class_1, ...) { + 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(const 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, NULL)) {} + + 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) : NULL; + } + + 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) { + return lilv_instance_get_extension_data(me, uri); + } + + inline const LV2_Descriptor* get_descriptor() { + return lilv_instance_get_descriptor(me); + } + + inline LV2_Handle get_handle() { + return lilv_instance_get_handle(me); + } + + LilvInstance* me; +}; + +struct World { + inline World() : me(lilv_world_new()) {} + inline virtual ~World() { lilv_world_free(me); } + + inline LilvNode* new_uri(const char* uri) const { + return lilv_new_uri(me, uri); + } + inline LilvNode* new_file_uri(const char* host, const char* path) const { + return lilv_new_file_uri(me, host, path); + } + 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) { + return lilv_world_find_nodes(me, subject, predicate, object); + } + + LILV_WRAP2_VOID(world, set_option, const char*, uri, LilvNode*, value); +#if 0 /* needs custom lilv */ + LILV_WRAP1_VOID(world, load_all, const char*, lv2_path); +#else + LILV_WRAP0_VOID(world, load_all); +#endif + 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(const Plugins, world, get_all_plugins); + LILV_WRAP1(int, world, load_resource, const LilvNode*, resource); + + LilvWorld* me; +}; + +} /* namespace Lilv */ + +#endif /* LILV_LILVMM_HPP */ diff --git a/mixer/src/lv2/lv2_external_ui.h b/mixer/src/lv2/lv2_external_ui.h new file mode 100644 index 0000000..df769be --- /dev/null +++ b/mixer/src/lv2/lv2_external_ui.h @@ -0,0 +1,109 @@ +/* + LV2 External UI extension + This work is in public domain. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + If you have questions, contact Filipe Coelho (aka falkTX) + or ask in #lad channel, FreeNode IRC network. +*/ + +/** + @file lv2_external_ui.h + C header for the LV2 External UI extension . +*/ + +#ifndef LV2_EXTERNAL_UI_H +#define LV2_EXTERNAL_UI_H + +#include + +#define LV2_EXTERNAL_UI_URI "http://kxstudio.sf.net/ns/lv2ext/external-ui" +#define LV2_EXTERNAL_UI_PREFIX LV2_EXTERNAL_UI_URI "#" + +#define LV2_EXTERNAL_UI__Host LV2_EXTERNAL_UI_PREFIX "Host" +#define LV2_EXTERNAL_UI__Widget LV2_EXTERNAL_UI_PREFIX "Widget" + +/** This extension used to be defined by a lv2plug.in URI */ +#define LV2_EXTERNAL_UI_DEPRECATED_URI "http://lv2plug.in/ns/extensions/ui#external" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * When LV2_EXTERNAL_UI__Widget UI is instantiated, the returned + * LV2UI_Widget handle must be cast to pointer to LV2_External_UI_Widget. + * UI is created in invisible state. + */ +typedef struct _LV2_External_UI_Widget { + /** + * Host calls this function regulary. UI library implementing the + * callback may do IPC or redraw the UI. + * + * @param _this_ the UI context + */ + void (*run)(struct _LV2_External_UI_Widget * _this_); + + /** + * Host calls this function to make the plugin UI visible. + * + * @param _this_ the UI context + */ + void (*show)(struct _LV2_External_UI_Widget * _this_); + + /** + * Host calls this function to make the plugin UI invisible again. + * + * @param _this_ the UI context + */ + void (*hide)(struct _LV2_External_UI_Widget * _this_); + +} LV2_External_UI_Widget; + +#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr) +#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr) +#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr) + +/** + * On UI instantiation, host must supply LV2_EXTERNAL_UI__Host feature. + * LV2_Feature::data must be pointer to LV2_External_UI_Host. + */ +typedef struct _LV2_External_UI_Host { + /** + * Callback that plugin UI will call when UI (GUI window) is closed by user. + * This callback will be called during execution of LV2_External_UI_Widget::run() + * (i.e. not from background thread). + * + * After this callback is called, UI is defunct. Host must call LV2UI_Descriptor::cleanup(). + * If host wants to make the UI visible again, the UI must be reinstantiated. + * + * @note When using the depreated URI LV2_EXTERNAL_UI_DEPRECATED_URI, + * some hosts will not call LV2UI_Descriptor::cleanup() as they should, + * and may call show() again without re-initialization. + * + * @param controller Host context associated with plugin UI, as + * supplied to LV2UI_Descriptor::instantiate(). + */ + void (*ui_closed)(LV2UI_Controller controller); + + /** + * Optional (may be NULL) "user friendly" identifier which the UI + * may display to allow a user to easily associate this particular + * UI instance with the correct plugin instance as it is represented + * by the host (e.g. "track 1" or "channel 4"). + * + * If supplied by host, the string will be referenced only during + * LV2UI_Descriptor::instantiate() + */ + const char * plugin_human_id; + +} LV2_External_UI_Host; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV2_EXTERNAL_UI_H */ diff --git a/mixer/src/lv2/lv2_kxstudio_properties.h b/mixer/src/lv2/lv2_kxstudio_properties.h new file mode 100644 index 0000000..e8b42a6 --- /dev/null +++ b/mixer/src/lv2/lv2_kxstudio_properties.h @@ -0,0 +1,33 @@ +/* + LV2 KXStudio Properties Extension + Copyright 2014 Filipe Coelho + + 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 lv2_kxstudio_properties.h + C header for the LV2 KXStudio Properties extension . +*/ + +#ifndef LV2_KXSTUDIO_PROPERTIES_H +#define LV2_KXSTUDIO_PROPERTIES_H + +#define LV2_KXSTUDIO_PROPERTIES_URI "http://kxstudio.sf.net/ns/lv2ext/props" +#define LV2_KXSTUDIO_PROPERTIES_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#" + +#define LV2_KXSTUDIO_PROPERTIES__NonAutomable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomable" +#define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat" +#define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" + +#endif /* LV2_KXSTUDIO_PROPERTIES_H */ diff --git a/mixer/wscript b/mixer/wscript index 2094e37..1cdce16 100644 --- a/mixer/wscript +++ b/mixer/wscript @@ -29,6 +29,11 @@ def configure(conf): conf.check_cfg(package='lrdf', uselib_store='LRDF',args="--cflags --libs", atleast_version='0.4.0', mandatory=True) + conf.check_cfg(package='lv2', uselib_store='LV2',args="--cflags --libs", + atleast_version='1.10.0', mandatory=True) + conf.check_cfg(package='lilv-0', uselib_store='LILV',args="--cflags --libs", + atleast_version='0.20.0', mandatory=True) + conf.define('VERSION', PACKAGE_VERSION) conf.define('SYSTEM_PATH', '/'.join( [ conf.env.DATADIR, APPNAME ] ) ) conf.define('DOCUMENT_PATH', '/'.join( [ conf.env.DATADIR, 'doc' ] ) ) @@ -72,7 +77,7 @@ src/Spatialization_Console.C target = 'non-mixer', includes = ['.', 'src', '..', '../nonlib'], use = ['nonlib', 'fl_widgets'], - uselib = [ 'JACK', 'LIBLO', 'LRDF', 'NTK', 'NTK_IMAGES', 'PTHREAD', 'DL', 'M' ], + uselib = [ 'JACK', 'LIBLO', 'LRDF', 'LILV', 'NTK', 'NTK_IMAGES', 'PTHREAD', 'DL', 'M' ], install_path = '${BINDIR}') bld.program( source = 'src/midi-mapper.C',