From 119a3b5ac4a80f4ff0f639c27c64287e770ffef3 Mon Sep 17 00:00:00 2001 From: falkTX Date: Wed, 21 Aug 2013 06:56:30 +0100 Subject: [PATCH] More work on internal plugins and lv2 export --- .gitignore | 67 ++-- source/backend/Makefile.mk | 16 +- source/backend/plugin/NativePlugin.cpp | 9 +- source/includes/lv2/atom-util.h | 5 +- source/modules/carla_native/Makefile | 33 +- source/plugin/Makefile | 94 +++--- source/plugin/carla-native-base.cpp | 44 ++- source/plugin/carla-native-export.cpp | 38 ++- source/plugin/carla-native-plugin.cpp | 438 ++++++++++++++++++++----- source/utils/CarlaString.hpp | 9 +- 10 files changed, 522 insertions(+), 231 deletions(-) diff --git a/.gitignore b/.gitignore index bd0f61b21..0221a06fa 100644 --- a/.gitignore +++ b/.gitignore @@ -50,12 +50,13 @@ carla-bridge-native carla-bridge-posix32 carla-bridge-posix64 carla-bridge-lv2-cocoa +carla-bridge-lv2-external carla-bridge-lv2-gtk2 carla-bridge-lv2-gtk3 carla-bridge-lv2-qt4 carla-bridge-lv2-qt5 carla-bridge-lv2-x11 -carla-bridge-vst-cocoa +carla-bridge-vst-mac carla-bridge-vst-x11 carla-discovery-qtcreator @@ -90,38 +91,38 @@ src/dist/ *build-*Release/ # ZynAddSubFX UI -source/backend/native/zynaddsubfx/UI/ADnoteUI.cpp -source/backend/native/zynaddsubfx/UI/ADnoteUI.h -source/backend/native/zynaddsubfx/UI/BankUI.cpp -source/backend/native/zynaddsubfx/UI/BankUI.h -source/backend/native/zynaddsubfx/UI/ConfigUI.cpp -source/backend/native/zynaddsubfx/UI/ConfigUI.h -source/backend/native/zynaddsubfx/UI/EffUI.cpp -source/backend/native/zynaddsubfx/UI/EffUI.h -source/backend/native/zynaddsubfx/UI/EnvelopeUI.cpp -source/backend/native/zynaddsubfx/UI/EnvelopeUI.h -source/backend/native/zynaddsubfx/UI/FilterUI.cpp -source/backend/native/zynaddsubfx/UI/FilterUI.h -source/backend/native/zynaddsubfx/UI/LFOUI.cpp -source/backend/native/zynaddsubfx/UI/LFOUI.h -source/backend/native/zynaddsubfx/UI/MasterUI.cpp -source/backend/native/zynaddsubfx/UI/MasterUI.h -source/backend/native/zynaddsubfx/UI/MicrotonalUI.cpp -source/backend/native/zynaddsubfx/UI/MicrotonalUI.h -source/backend/native/zynaddsubfx/UI/OscilGenUI.cpp -source/backend/native/zynaddsubfx/UI/OscilGenUI.h -source/backend/native/zynaddsubfx/UI/PADnoteUI.cpp -source/backend/native/zynaddsubfx/UI/PADnoteUI.h -source/backend/native/zynaddsubfx/UI/PartUI.cpp -source/backend/native/zynaddsubfx/UI/PartUI.h -source/backend/native/zynaddsubfx/UI/PresetsUI.cpp -source/backend/native/zynaddsubfx/UI/PresetsUI.h -source/backend/native/zynaddsubfx/UI/ResonanceUI.cpp -source/backend/native/zynaddsubfx/UI/ResonanceUI.h -source/backend/native/zynaddsubfx/UI/SUBnoteUI.cpp -source/backend/native/zynaddsubfx/UI/SUBnoteUI.h -source/backend/native/zynaddsubfx/UI/VirKeyboard.cpp -source/backend/native/zynaddsubfx/UI/VirKeyboard.h +source/modules/carla_native/zynaddsubfx/UI/ADnoteUI.cpp +source/modules/carla_native/zynaddsubfx/UI/ADnoteUI.h +source/modules/carla_native/zynaddsubfx/UI/BankUI.cpp +source/modules/carla_native/zynaddsubfx/UI/BankUI.h +source/modules/carla_native/zynaddsubfx/UI/ConfigUI.cpp +source/modules/carla_native/zynaddsubfx/UI/ConfigUI.h +source/modules/carla_native/zynaddsubfx/UI/EffUI.cpp +source/modules/carla_native/zynaddsubfx/UI/EffUI.h +source/modules/carla_native/zynaddsubfx/UI/EnvelopeUI.cpp +source/modules/carla_native/zynaddsubfx/UI/EnvelopeUI.h +source/modules/carla_native/zynaddsubfx/UI/FilterUI.cpp +source/modules/carla_native/zynaddsubfx/UI/FilterUI.h +source/modules/carla_native/zynaddsubfx/UI/LFOUI.cpp +source/modules/carla_native/zynaddsubfx/UI/LFOUI.h +source/modules/carla_native/zynaddsubfx/UI/MasterUI.cpp +source/modules/carla_native/zynaddsubfx/UI/MasterUI.h +source/modules/carla_native/zynaddsubfx/UI/MicrotonalUI.cpp +source/modules/carla_native/zynaddsubfx/UI/MicrotonalUI.h +source/modules/carla_native/zynaddsubfx/UI/OscilGenUI.cpp +source/modules/carla_native/zynaddsubfx/UI/OscilGenUI.h +source/modules/carla_native/zynaddsubfx/UI/PADnoteUI.cpp +source/modules/carla_native/zynaddsubfx/UI/PADnoteUI.h +source/modules/carla_native/zynaddsubfx/UI/PartUI.cpp +source/modules/carla_native/zynaddsubfx/UI/PartUI.h +source/modules/carla_native/zynaddsubfx/UI/PresetsUI.cpp +source/modules/carla_native/zynaddsubfx/UI/PresetsUI.h +source/modules/carla_native/zynaddsubfx/UI/ResonanceUI.cpp +source/modules/carla_native/zynaddsubfx/UI/ResonanceUI.h +source/modules/carla_native/zynaddsubfx/UI/SUBnoteUI.cpp +source/modules/carla_native/zynaddsubfx/UI/SUBnoteUI.h +source/modules/carla_native/zynaddsubfx/UI/VirKeyboard.cpp +source/modules/carla_native/zynaddsubfx/UI/VirKeyboard.h # Other source/includes/rewire/ diff --git a/source/backend/Makefile.mk b/source/backend/Makefile.mk index 704f392fb..66e4fa64a 100644 --- a/source/backend/Makefile.mk +++ b/source/backend/Makefile.mk @@ -8,13 +8,7 @@ include ../../Makefile.mk # -------------------------------------------------------------- -BACKEND_FLAGS = -I. -I.. -I../../includes -I../../modules -I../../utils - -BUILD_C_FLAGS += $(BACKEND_FLAGS) -BUILD_CXX_FLAGS += $(BACKEND_FLAGS) - -# -------------------------------------------------------------- - +BUILD_CXX_FLAGS += -I. -I.. -I../../includes -I../../modules -I../../utils BUILD_CXX_FLAGS += -DWANT_NATIVE ifeq ($(CARLA_PLUGIN_SUPPORT),true) @@ -42,9 +36,7 @@ ifeq ($(HAVE_LINUXSAMPLER),true) BUILD_CXX_FLAGS += -DWANT_LINUXSAMPLER endif -ifeq ($(HAVE_OPENGL),true) -BUILD_CXX_FLAGS += -DWANT_OPENGL -endif +# -------------------------------------------------------------- ifeq ($(HAVE_AF_DEPS),true) BUILD_CXX_FLAGS += -DWANT_AUDIOFILE @@ -57,6 +49,10 @@ ifeq ($(HAVE_MF_DEPS),true) BUILD_CXX_FLAGS += -DWANT_MIDIFILE endif +ifeq ($(HAVE_OPENGL),true) +BUILD_CXX_FLAGS += -DWANT_OPENGL +endif + ifeq ($(HAVE_ZYN_DEPS),true) BUILD_CXX_FLAGS += -DWANT_ZYNADDSUBFX ifeq ($(HAVE_ZYN_UI_DEPS),true) diff --git a/source/backend/plugin/NativePlugin.cpp b/source/backend/plugin/NativePlugin.cpp index b94931f21..e0e542b3a 100644 --- a/source/backend/plugin/NativePlugin.cpp +++ b/source/backend/plugin/NativePlugin.cpp @@ -2151,20 +2151,17 @@ protected: return false; } - if (fMidiEventCount >= MAX_MIDI_EVENTS*2) - return false; - // reverse-find first free event, and put it there - for (uint32_t i=(MAX_MIDI_EVENTS*2)-1; i >= fMidiEventCount; --i) + for (uint32_t i=(MAX_MIDI_EVENTS*2)-1; i > fMidiEventCount; --i) { if (fMidiEvents[i].data[0] == 0) { std::memcpy(&fMidiEvents[i], event, sizeof(::MidiEvent)); - break; + return true; } } - return true; + return false; } void handleUiParameterChanged(const uint32_t index, const float value) diff --git a/source/includes/lv2/atom-util.h b/source/includes/lv2/atom-util.h index 95f495b4d..417eca921 100644 --- a/source/includes/lv2/atom-util.h +++ b/source/includes/lv2/atom-util.h @@ -99,6 +99,7 @@ lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, static inline const LV2_Atom_Event* lv2_atom_sequence_next(const LV2_Atom_Event* i) { + if (!i) return NULL; return (const LV2_Atom_Event*)((const uint8_t*)i + sizeof(LV2_Atom_Event) + lv2_atom_pad_size(i->body.size)); @@ -117,13 +118,13 @@ lv2_atom_sequence_next(const LV2_Atom_Event* i) @endcode */ #define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ - for (LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \ + for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \ !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ (iter) = lv2_atom_sequence_next(iter)) /** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ #define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ - for (LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \ + for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \ !lv2_atom_sequence_is_end(body, size, (iter)); \ (iter) = lv2_atom_sequence_next(iter)) diff --git a/source/modules/carla_native/Makefile b/source/modules/carla_native/Makefile index 339416d75..3f1c3f4a0 100644 --- a/source/modules/carla_native/Makefile +++ b/source/modules/carla_native/Makefile @@ -8,9 +8,17 @@ include ../../Makefile.mk # -------------------------------------------------------------- -BUILD_C_FLAGS += -I. -I.. -I../../includes +BUILD_C_FLAGS += -I. -I../../includes BUILD_CXX_FLAGS += -I. -I.. -I../../includes -I../../utils +# -------------------------------------------------------------- + +ifeq ($(HAVE_OPENGL),true) +GL_CXX_FLAGS = $(BUILD_CXX_FLAGS) +GL_CXX_FLAGS += -I../distrho +GL_CXX_FLAGS += $(shell pkg-config --cflags gl) +endif + ifeq ($(HAVE_AF_DEPS),true) AF_C_FLAGS = $(BUILD_C_FLAGS) AF_C_FLAGS += $(shell pkg-config --cflags sndfile) @@ -25,12 +33,6 @@ MF_CXX_FLAGS = $(BUILD_CXX_FLAGS) MF_CXX_FLAGS += $(shell pkg-config --cflags smf) endif -ifeq ($(HAVE_OPENGL),true) -GL_CXX_FLAGS = $(BUILD_CXX_FLAGS) -GL_CXX_FLAGS += -I../../modules/distrho -GL_CXX_FLAGS += $(shell pkg-config --cflags gl) -endif - ifeq ($(HAVE_ZYN_DEPS),true) ZYN_CXX_FLAGS = $(BUILD_CXX_FLAGS) ZYN_CXX_FLAGS += $(shell pkg-config --cflags fftw3 mxml zlib) @@ -54,7 +56,6 @@ OBJS = \ # Simple plugins (C++) OBJS += \ - midi-sequencer.cpp.o \ vex.cpp.o # AudioFile @@ -154,9 +155,6 @@ all: ../carla_native.a # -------------------------------------------------------------- -CDEPS = CarlaNative.h -CXXDEPS = CarlaNative.h CarlaNative.hpp - %.c.o: %.c $(CC) $< $(BUILD_C_FLAGS) -c -o $@ @@ -168,6 +166,9 @@ moc_%.cpp: %.hpp # -------------------------------------------------------------- +CDEPS = CarlaNative.h +CXXDEPS = CarlaNative.h CarlaNative.hpp + audio_decoder/%.c.o: audio_decoder/%.c $(CC) $< $(AF_C_FLAGS) -c -o $@ @@ -190,7 +191,7 @@ distrho-stereoenhancer.cpp.o: distrho-stereoenhancer.cpp stereoenhancer/*.cpp st $(CXX) $< $(GL_CXX_FLAGS) -Istereoenhancer -DDISTRHO_NAMESPACE=DISTRHO_StereoEnhancer -c -o $@ distrho-notes.cpp.o: distrho-notes.cpp notes/*.cpp notes/*.h notes/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) - $(CXX) $< $(QT_CXX_FLAGS) -Inotes -DDISTRHO_NAMESPACE=DISTRHO_Notes -c -o $@ + $(CXX) $< $(BUILD_CXX_FLAGS) -Inotes -DDISTRHO_NAMESPACE=DISTRHO_Notes -c -o $@ midi-file.cpp.o: midi-file.cpp midi-base.hpp $(CXXDEPS) $(CXX) $< $(MF_CXX_FLAGS) -c -o $@ @@ -204,10 +205,10 @@ nekofilter.c.o: nekofilter.c nekofilter/*.c nekofilter/*.h $(CDEPS) zynaddsubfx.cpp.o: zynaddsubfx.cpp $(CXXDEPS) $(ZYN_UI_FILES_H) $(CXX) $< $(ZYN_CXX_FLAGS) -c -o $@ -zynaddsubfx-src.cpp.o: zynaddsubfx-src.cpp $(ZYN_UI_FILES_H) $(ZYN_UI_FILES_CPP) +zynaddsubfx-src.cpp.o: zynaddsubfx-src.cpp $(ZYN_UI_FILES_H) $(CXX) $< $(ZYN_CXX_FLAGS) -c -o $@ -zynaddsubfx-ui.cpp.o: zynaddsubfx-ui.cpp $(ZYN_UI_FILES_H) +zynaddsubfx-ui.cpp.o: zynaddsubfx-ui.cpp $(ZYN_UI_FILES_H) $(ZYN_UI_FILES_CPP) $(CXX) $< $(ZYN_CXX_FLAGS) -c -o $@ zynaddsubfx/UI/%.cpp: zynaddsubfx/UI/%.fl @@ -219,8 +220,8 @@ zynaddsubfx/UI/%.h: zynaddsubfx/UI/%.fl # -------------------------------------------------------------- clean: - rm -f *.o ../carla_native.* - rm -f $(ZYN_UI_FILES_H) $(ZYN_UI_FILES_CPP) + rm -f $(OBJS) ../carla_native.* + rm -f $(ZYN_UI_FILES_H) $(ZYN_UI_FILES_CPP) debug: $(MAKE) DEBUG=true diff --git a/source/plugin/Makefile b/source/plugin/Makefile index 1c5fa310b..84b80a4c8 100644 --- a/source/plugin/Makefile +++ b/source/plugin/Makefile @@ -6,13 +6,7 @@ include ../Makefile.mk -BUILD_CXX_FLAGS += -I../backend -I../includes -I../modules -I../utils - -ifeq ($(HAVE_QT4),true) -BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore QtGui) -else -BUILD_CXX_FLAGS += $(shell pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets) -endif +BUILD_CXX_FLAGS += -I../includes -I../modules -I../utils # -------------------------------------------------------------- @@ -35,30 +29,34 @@ endif # -------------------------------------------------------------- # Common -LINK_FLAGS += $(shell pkg-config --libs liblo) - -ifeq ($(HAVE_QT4),true) -LINK_FLAGS += $(shell pkg-config --libs QtCore QtGui QtXml) -else -LINK_FLAGS += $(shell pkg-config --libs Qt5Core Qt5Gui Qt5Xml Qt5Widgets) -endif +# LINK_FLAGS += $(shell pkg-config --libs liblo) +# +# ifeq ($(HAVE_QT4),true) +# LINK_FLAGS += $(shell pkg-config --libs QtCore QtGui QtXml) +# else +# LINK_FLAGS += $(shell pkg-config --libs Qt5Core Qt5Gui Qt5Xml Qt5Widgets) +# endif # -------------------------------------------------------------- # Plugin -ifeq ($(HAVE_FLUIDSYNTH),true) -LINK_FLAGS += $(shell pkg-config --libs fluidsynth) -endif - -ifeq ($(HAVE_LINUXSAMPLER),true) -LINK_FLAGS += $(shell pkg-config --libs linuxsampler) -endif +# ifeq ($(HAVE_FLUIDSYNTH),true) +# LINK_FLAGS += $(shell pkg-config --libs fluidsynth) +# endif +# +# ifeq ($(HAVE_LINUXSAMPLER),true) +# LINK_FLAGS += $(shell pkg-config --libs linuxsampler) +# endif # -------------------------------------------------------------- # Native DGL_LIBS = -lX11 +ifeq ($(HAVE_OPENGL),true) +LINK_FLAGS += $(shell pkg-config --libs gl) $(DGL_LIBS) +endif + ifeq ($(HAVE_AF_DEPS),true) LINK_FLAGS += $(shell pkg-config --libs sndfile) ifeq ($(HAVE_FFMPEG),true) @@ -70,10 +68,6 @@ ifeq ($(HAVE_MF_DEPS),true) LINK_FLAGS += $(shell pkg-config --libs smf) endif -ifeq ($(HAVE_OPENGL),true) -LINK_FLAGS += $(shell pkg-config --libs gl) $(DGL_LIBS) -endif - ifeq ($(HAVE_ZYN_DEPS),true) LINK_FLAGS += $(shell pkg-config --libs fftw3 mxml zlib) ifeq ($(HAVE_ZYN_UI_DEPS),true) @@ -85,31 +79,30 @@ LINK_FLAGS += $(EXTRA_LIBS) # -------------------------------------------------------------- -# LIBS = ../backend/libcarla_engine_xx.a -# LIBS += ../backend/libcarla_plugin.a -LIBS += ../backend/libcarla_native.a -LIBS += ../modules/rtmempool.a -LIBS += ../modules/widgets.a +LIBS = ../modules/carla_native.a +LIBS += ../modules/juce_audio_basics.a LIBS += ../modules/juce_core.a +LIBS += ../modules/rtmempool.a -ifeq ($(CARLA_PLUGIN_SUPPORT),true) -LIBS += ../modules/lilv.a -endif +# ifeq ($(CARLA_PLUGIN_SUPPORT),true) +# LIBS += ../modules/lilv.a +# endif ifeq ($(HAVE_OPENGL),true) LIBS += ../modules/dgl.a endif ifeq ($(WIN32),true) -TARGETS = carla-native.lv2/carla-native.dll -TARGETS += carla-native-export.exe +TARGETS = carla-native-export.exe +TARGETS += carla-native.lv2/carla-native.dll else +TARGETS = carla-native-export ifeq ($(MACOS),true) -TARGETS = carla-native.lv2/carla-native.dylib +TARGETS += carla-native.lv2/carla-native.dylib else -TARGETS = carla-native.lv2/carla-native.so +LIBS += -ldl -lrt +TARGETS += carla-native.lv2/carla-native.so endif -TARGETS += carla-native-export endif # -------------------------------------------------------------- @@ -125,17 +118,16 @@ debug: # -------------------------------------------------------------- -%.cpp.o: %.cpp ../backend/CarlaNative.h +carla-native-base.cpp.o: carla-native-base.cpp ../modules/carla_native/CarlaNative.h $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ -carla-native.lv2/carla-native.dll: carla-native-plugin.cpp.o $(LIBS) - $(CXX) $^ -shared $(LINK_FLAGS) -o $@ +carla-native-export.cpp.o: carla-native-export.cpp carla-native-base.cpp ../modules/carla_native/CarlaNative.h + $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ -carla-native.lv2/carla-native.dylib: carla-native-plugin.cpp.o $(LIBS) - $(CXX) $^ -dynamiclib $(LINK_FLAGS) -o $@ +carla-native-plugin.cpp.o: carla-native-plugin.cpp carla-native-base.cpp ../modules/carla_native/CarlaNative.h + $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ -carla-native.lv2/carla-native.so: carla-native-plugin.cpp.o $(LIBS) - $(CXX) $^ -shared $(LINK_FLAGS) -o $@ +# -------------------------------------------------------------- carla-native-export: carla-native-export.cpp.o $(LIBS) $(CXX) $^ $(LINK_FLAGS) -o $@ @@ -145,13 +137,19 @@ carla-native-export.exe: carla-native-export.cpp.o $(LIBS) $(CXX) $^ $(LINK_FLAGS) -o $@ ./carla-native-export.exe +carla-native.lv2/carla-native.dll: carla-native-plugin.cpp.o $(LIBS) + $(CXX) $^ -shared $(LINK_FLAGS) -o $@ + +carla-native.lv2/carla-native.dylib: carla-native-plugin.cpp.o $(LIBS) + $(CXX) $^ -dynamiclib $(LINK_FLAGS) -o $@ + +carla-native.lv2/carla-native.so: carla-native-plugin.cpp.o $(LIBS) + $(CXX) $^ -shared $(LINK_FLAGS) -o $@ + # -------------------------------------------------------------- .FORCE: .PHONY: .FORCE -../backend/libcarla_%.a: .FORCE - $(MAKE) -C ../backend/$* - ../modules/%.a: .FORCE $(MAKE) -C ../modules $* diff --git a/source/plugin/carla-native-base.cpp b/source/plugin/carla-native-base.cpp index ab78be87c..f1965523e 100644 --- a/source/plugin/carla-native-base.cpp +++ b/source/plugin/carla-native-base.cpp @@ -15,7 +15,7 @@ * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ -#include "CarlaNative.h" +#include "carla_native/CarlaNative.h" #include "RtList.hpp" #include "lv2/lv2.h" @@ -25,18 +25,17 @@ extern "C" { -// Simple plugins +// Simple plugins (C) void carla_register_native_plugin_bypass(); void carla_register_native_plugin_lfo(); -//void carla_register_native_plugin_midiSequencer(); +void carla_register_native_plugin_midiGain(); void carla_register_native_plugin_midiSplit(); void carla_register_native_plugin_midiThrough(); void carla_register_native_plugin_midiTranspose(); void carla_register_native_plugin_nekofilter(); -//void carla_register_native_plugin_sunvoxfile(); -// Carla -//void carla_register_native_plugin_carla(); +// Simple plugins (C++) +void carla_register_native_plugin_vex(); #ifdef WANT_AUDIOFILE // AudioFile @@ -50,15 +49,15 @@ void carla_register_native_plugin_midifile(); #ifdef WANT_OPENGL // DISTRHO plugins (OpenGL) -void carla_register_native_plugin_3BandEQ(); -void carla_register_native_plugin_3BandSplitter(); -void carla_register_native_plugin_Nekobi(); -void carla_register_native_plugin_PingPongPan(); -void carla_register_native_plugin_StereoEnhancer(); +// void carla_register_native_plugin_3BandEQ(); +// void carla_register_native_plugin_3BandSplitter(); +// void carla_register_native_plugin_Nekobi(); +// void carla_register_native_plugin_PingPongPan(); +// void carla_register_native_plugin_StereoEnhancer(); #endif // DISTRHO plugins (Qt) -void carla_register_native_plugin_Notes(); +// void carla_register_native_plugin_Notes(); #ifdef WANT_ZYNADDSUBFX // ZynAddSubFX @@ -72,18 +71,17 @@ void carla_register_native_plugin_zynaddsubfx(); struct PluginListManager { PluginListManager() { - // Simple plugins + // Simple plugins (C) carla_register_native_plugin_bypass(); carla_register_native_plugin_lfo(); - //carla_register_native_plugin_midiSequencer(); // unfinished + carla_register_native_plugin_midiGain(); carla_register_native_plugin_midiSplit(); carla_register_native_plugin_midiThrough(); carla_register_native_plugin_midiTranspose(); carla_register_native_plugin_nekofilter(); - //carla_register_native_plugin_sunvoxfile(); // unfinished - // Carla - //carla_register_native_plugin_carla(); // kinda unfinished + // Simple plugins (C++) + carla_register_native_plugin_vex(); #ifdef WANT_AUDIOFILE // AudioFile @@ -97,15 +95,15 @@ struct PluginListManager { #ifdef WANT_OPENGL // DISTRHO plugins (OpenGL) - carla_register_native_plugin_3BandEQ(); - carla_register_native_plugin_3BandSplitter(); - carla_register_native_plugin_Nekobi(); - carla_register_native_plugin_PingPongPan(); - carla_register_native_plugin_StereoEnhancer(); // unfinished + //carla_register_native_plugin_3BandEQ(); + //carla_register_native_plugin_3BandSplitter(); + //carla_register_native_plugin_Nekobi(); + //carla_register_native_plugin_PingPongPan(); + //carla_register_native_plugin_StereoEnhancer(); // unfinished #endif // DISTRHO plugins (Qt) - carla_register_native_plugin_Notes(); // unfinished + //carla_register_native_plugin_Notes(); // unfinished #ifdef WANT_ZYNADDSUBFX // ZynAddSubFX diff --git a/source/plugin/carla-native-export.cpp b/source/plugin/carla-native-export.cpp index d4be343b5..f21450879 100644 --- a/source/plugin/carla-native-export.cpp +++ b/source/plugin/carla-native-export.cpp @@ -24,12 +24,14 @@ #include "lv2/instance-access.h" #include "lv2/midi.h" #include "lv2/options.h" +#include "lv2/port-props.h" #include "lv2/state.h" #include "lv2/time.h" #include "lv2/ui.h" #include "lv2/units.h" #include "lv2/urid.h" #include "lv2/lv2_external_ui.h" +#include "lv2/lv2_programs.h" #include @@ -52,7 +54,7 @@ static StringArray gUsedSymbols; const String nameToSymbol(const String& name, const uint32_t portIndex) { - String symbol, trimmedName = name.trimStart().trimEnd().toLowerCase(); + String symbol, trimmedName = name.trim().toLowerCase(); if (trimmedName.isEmpty()) { @@ -133,11 +135,13 @@ void writeManifestFile() text += "\n"; text += " a <" LV2_EXTERNAL_UI__Widget "> ;\n"; text += " ui:binary ;\n"; + text += " lv2:extensionData <" LV2_PROGRAMS__UIInterface "> ;\n"; text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> .\n"; text += "\n"; text += "\n"; text += " a <" LV2_EXTERNAL_UI_DEPRECATED_URI "> ;\n"; text += " ui:binary ;\n"; + text += " lv2:extensionData <" LV2_PROGRAMS__UIInterface "> ;\n"; text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> .\n"; // ------------------------------------------------------------------- @@ -216,7 +220,8 @@ void writePluginFile(const PluginDescriptor* const pluginDesc) text += " lv2:requiredFeature <" LV2_BUF_SIZE__boundedBlockLength "> ,\n"; text += " <" LV2_URID__map "> ;\n"; text += " lv2:extensionData <" LV2_OPTIONS__interface "> ,\n"; - text += " <" LV2_STATE__interface "> ;\n"; + text += " <" LV2_STATE__interface "> ,\n"; + text += " <" LV2_PROGRAMS__Interface "> ;\n"; text += "\n"; // ------------------------------------------------------------------- @@ -247,7 +252,7 @@ void writePluginFile(const PluginDescriptor* const pluginDesc) } text += " lv2:designation lv2:control ;\n"; - text += " lv2:index 0" + String(portIndex++) + " ;\n"; + text += " lv2:index " + String(portIndex++) + " ;\n"; if (pluginDesc->midiIns > 1) { @@ -425,6 +430,30 @@ void writePluginFile(const PluginDescriptor* const pluginDesc) text += " lv2:minimum " + String::formatted("%f", paramInfo->ranges.min) + " ;\n"; text += " lv2:maximum " + String::formatted("%f", paramInfo->ranges.max) + " ;\n"; + if (paramInfo->hints & PARAMETER_IS_ENABLED) + { + if ((paramInfo->hints & PARAMETER_IS_AUTOMABLE) == 0) + text += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ;\n"; + if (paramInfo->hints & PARAMETER_IS_BOOLEAN) + text += " lv2:portProperty lv2:toggled ;\n"; + if (paramInfo->hints & PARAMETER_IS_INTEGER) + text += " lv2:portProperty lv2:integer ;\n"; + if (paramInfo->hints & PARAMETER_IS_LOGARITHMIC) + text += " lv2:portProperty <" LV2_PORT_PROPS__logarithmic "> ;\n"; + if (paramInfo->hints & PARAMETER_USES_SAMPLE_RATE) + text += " lv2:portProperty lv2:toggled ;\n"; + if (paramInfo->hints & PARAMETER_USES_SCALEPOINTS) + text += " lv2:portProperty lv2:enumeration ;\n"; + if (paramInfo->hints & PARAMETER_USES_CUSTOM_TEXT) + pass(); // TODO: custom lv2 extension for this + } + else + { + text += " lv2:portProperty <" LV2_PORT_PROPS__notOnGUI "> ;\n"; + } + + // TODO - scalepoints + if (paramUnit.isNotEmpty()) { text += " units:unit [\n"; @@ -435,9 +464,6 @@ void writePluginFile(const PluginDescriptor* const pluginDesc) text += " ] ;\n"; } -// if (! filter->isParameterAutomatable(i)) -// text += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ;\n"; - if (i+1 == paramCount) text += " ] ;\n\n"; else diff --git a/source/plugin/carla-native-plugin.cpp b/source/plugin/carla-native-plugin.cpp index 065821dbe..d6b354f6e 100644 --- a/source/plugin/carla-native-plugin.cpp +++ b/source/plugin/carla-native-plugin.cpp @@ -20,20 +20,18 @@ #include "CarlaString.hpp" #include "lv2/atom.h" +#include "lv2/atom-util.h" #include "lv2/buf-size.h" #include "lv2/instance-access.h" +#include "lv2/midi.h" #include "lv2/options.h" #include "lv2/state.h" +#include "lv2/time.h" #include "lv2/ui.h" #include "lv2/lv2_external_ui.h" +#include "lv2/lv2_programs.h" -#include - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) -# include -#else -# include -#endif +using juce::FloatVectorOperations; // ----------------------------------------------------------------------- // LV2 descriptor functions @@ -48,8 +46,11 @@ public: fDescriptor(desc), fMidiEventCount(0), fIsProcessing(false), + fNeedsDryWetFix(false), + fVolume(1.0f), fBufferSize(0), - fSampleRate(sampleRate) + fSampleRate(sampleRate), + fUridMap(nullptr) { run = extui_run; show = extui_show; @@ -88,8 +89,6 @@ public: return; } - fBufferSize = 1024; - for (int i=0; options[i].key != 0; ++i) { if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength)) @@ -104,11 +103,11 @@ public: fUridMap = uridMap; - fUI.offset += (desc->midiIns > 0) ? desc->midiIns : 1; - fUI.offset += desc->midiOuts; - fUI.offset += 1; // freewheel - fUI.offset += desc->audioIns; - fUI.offset += desc->audioOuts; + fUI.portOffset += (desc->midiIns > 0) ? desc->midiIns : 1; + fUI.portOffset += desc->midiOuts; + fUI.portOffset += 1; // freewheel + fUI.portOffset += desc->audioIns; + fUI.portOffset += desc->audioOuts; } ~NativePlugin() @@ -131,7 +130,7 @@ public: } if (fBufferSize == 0) { - carla_stderr("Plugin is missing bufferSize value"); + carla_stderr("Host is missing bufferSize feature"); return false; } @@ -142,7 +141,10 @@ public: carla_zeroStruct(fMidiEvents, kMaxMidiEvents*2); carla_zeroStruct(fTimeInfo); + fPorts.init(fDescriptor, fHandle); + fUris.map(fUridMap); + return true; } @@ -154,13 +156,13 @@ public: fPorts.connectPort(fDescriptor, port, dataLocation); } - void lv2_activate() + void lv2_activate() const { if (fDescriptor->activate != nullptr) fDescriptor->activate(fHandle); } - void lv2_deactivate() + void lv2_deactivate() const { if (fDescriptor->deactivate != nullptr) fDescriptor->deactivate(fHandle); @@ -197,14 +199,194 @@ public: } } - fDescriptor->process(fHandle, fPorts.audioIns, fPorts.audioOuts, frames, fMidiEventCount, fMidiEvents); + LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], iter) + { + const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter); + + if (event == nullptr) + continue; + if (event->body.size > 4) + continue; + if (event->time.frames >= frames) + break; + + if (event->body.type == fUris.midiEvent) + { + if (fMidiEventCount >= kMaxMidiEvents*2) + continue; + + const uint8_t* const data((const uint8_t*)(event + 1)); + + fMidiEvents[fMidiEventCount].port = 0; + fMidiEvents[fMidiEventCount].time = event->time.frames; + fMidiEvents[fMidiEventCount].size = event->body.size; + + for (uint32_t i=0; i < event->body.size; ++i) + fMidiEvents[fMidiEventCount].data[i] = data[i]; + + fMidiEventCount += 1; + continue; + } + + if (event->body.type == fUris.atomBlank) + { + const LV2_Atom_Object* const obj((LV2_Atom_Object*)&event->body); + + if (obj->body.otype != fUris.timePos) + continue; + + LV2_Atom* bar = nullptr; + LV2_Atom* barBeat = nullptr; + LV2_Atom* beatsPerBar = nullptr; + LV2_Atom* bpm = nullptr; + LV2_Atom* beatUnit = nullptr; + LV2_Atom* frame = nullptr; + LV2_Atom* speed = nullptr; + + lv2_atom_object_get(obj, + fUris.timeBar, &bar, + fUris.timeBarBeat, &barBeat, + fUris.timeBeatsPerBar, &beatsPerBar, + fUris.timeBeatsPerMinute, &bpm, + fUris.timeBeatUnit, &beatUnit, + fUris.timeFrame, &frame, + fUris.timeSpeed, &speed, + nullptr); + + if (bpm != nullptr && bpm->type == fUris.atomFloat) + { + fTimeInfo.bbt.beatsPerMinute = ((LV2_Atom_Float*)bpm)->body; + fTimeInfo.bbt.valid = true; + } + + if (beatsPerBar != nullptr && beatsPerBar->type == fUris.atomFloat) + { + float beatsPerBarValue = ((LV2_Atom_Float*)beatsPerBar)->body; + fTimeInfo.bbt.beatsPerBar = beatsPerBarValue; + + if (bar != nullptr && bar->type == fUris.atomLong) + { + //float barValue = ((LV2_Atom_Long*)bar)->body; + //curPosInfo.ppqPositionOfLastBarStart = barValue * beatsPerBarValue; + + if (barBeat != nullptr && barBeat->type == fUris.atomFloat) + { + //float barBeatValue = ((LV2_Atom_Float*)barBeat)->body; + //curPosInfo.ppqPosition = curPosInfo.ppqPositionOfLastBarStart + barBeatValue; + } + } + } + + if (beatUnit != nullptr && beatUnit->type == fUris.atomFloat) + fTimeInfo.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body; + + if (frame != nullptr && frame->type == fUris.atomLong) + fTimeInfo.frame = ((LV2_Atom_Long*)frame)->body; + + if (speed != nullptr && speed->type == fUris.atomFloat) + fTimeInfo.playing = ((LV2_Atom_Float*)speed)->body == 1.0f; + } + } + + for (uint32_t i=1; i < fDescriptor->midiIns; ++i) + { + LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], iter) + { + const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter); + + if (event == nullptr) + continue; + if (event->body.type != fUris.midiEvent) + continue; + if (event->body.size > 4) + continue; + if (event->time.frames >= frames) + break; + if (fMidiEventCount >= kMaxMidiEvents*2) + break; + + const uint8_t* const data((const uint8_t*)(event + 1)); + + fMidiEvents[fMidiEventCount].port = i; + fMidiEvents[fMidiEventCount].time = event->time.frames; + fMidiEvents[fMidiEventCount].size = event->body.size; + + for (uint32_t j=0; j < event->body.size; ++j) + fMidiEvents[fMidiEventCount].data[j] = data[j]; + + fMidiEventCount += 1; + } + } + + fIsProcessing = true; + fDescriptor->process(fHandle, fPorts.audioIns, fPorts.audioOuts, frames, fMidiEvents, fMidiEventCount); + fIsProcessing = false; + + if (fVolume != 1.0f) + { + for (uint32_t i=0; i < fDescriptor->audioOuts; ++i) + FloatVectorOperations::multiply(fPorts.audioOuts[i], fVolume, frames); + } updateParameterOutputs(); } // ------------------------------------------------------------------- - void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, LV2UI_Widget* widget, + uint32_t lv2_get_options(LV2_Options_Option* const /*options*/) const + { + return 0; + } + + uint32_t lv2_set_options(const LV2_Options_Option* const /*options*/) + { + return 0; + } + + const LV2_Program_Descriptor* lv2_get_program(const uint32_t index) const + { + if (fDescriptor->get_midi_program_count == nullptr) + return nullptr; + if (fDescriptor->get_midi_program_info == nullptr) + return nullptr; + if (index >= fDescriptor->get_midi_program_count(fHandle)) + return nullptr; + + const MidiProgram* const midiProg(fDescriptor->get_midi_program_info(fHandle, index)); + + if (midiProg == nullptr) + return nullptr; + + static LV2_Program_Descriptor progDesc; + + progDesc.bank = midiProg->bank; + progDesc.program = midiProg->program; + progDesc.name = midiProg->name; + + return &progDesc; + } + + void lv2_select_program(uint32_t bank, uint32_t program) const + { + if (fDescriptor->set_midi_program == nullptr) + return; + + fDescriptor->set_midi_program(fHandle, 0, bank, program); + } + + LV2_State_Status lv2_save(const LV2_State_Store_Function /*store*/, const LV2_State_Handle /*handle*/, const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const + { + return LV2_STATE_ERR_UNKNOWN; + } + + LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function /*retrieve*/, const LV2_State_Handle /*handle*/, const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const + { + return LV2_STATE_ERR_UNKNOWN; + } + + // ------------------------------------------------------------------- + + bool lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features) { for (int i=0; features[i] != nullptr; ++i) @@ -217,25 +399,29 @@ public: } } - if (fUI.host != nullptr) - fHost.uiName = fUI.host->plugin_human_id; + if (fUI.host == nullptr) + return false; fUI.writeFunction = writeFunction; fUI.controller = controller; *widget = this; + + fHost.uiName = fUI.host->plugin_human_id; + + return true; } - void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) + void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) const { if (format != 0 || bufferSize != sizeof(float) || buffer == nullptr) return; - if (portIndex >= fUI.offset || ! fUI.isVisible) + if (portIndex >= fUI.portOffset || ! fUI.isVisible) return; if (fDescriptor->ui_set_parameter_value == nullptr) return; const float value(*(const float*)buffer); - fDescriptor->ui_set_parameter_value(fHandle, portIndex-fUI.offset, value); + fDescriptor->ui_set_parameter_value(fHandle, portIndex-fUI.portOffset, value); } void lv2ui_cleanup() @@ -255,11 +441,19 @@ public: // ------------------------------------------------------------------- + void lv2ui_select_program(uint32_t bank, uint32_t program) const + { + if (fDescriptor->ui_set_midi_program == nullptr) + return; + + fDescriptor->ui_set_midi_program(fHandle, 0, bank, program); + } + + // ------------------------------------------------------------------- + protected: void handleUiRun() { - // TODO - idle Qt if needed - if (fDescriptor->ui_idle != nullptr) fDescriptor->ui_idle(fHandle); } @@ -282,24 +476,24 @@ protected: // ------------------------------------------------------------------- - uint32_t handleGetBufferSize() + uint32_t handleGetBufferSize() const { return fBufferSize; } - double handleGetSampleRate() + double handleGetSampleRate() const { return fSampleRate; } - bool handleIsOffline() + bool handleIsOffline() const { CARLA_SAFE_ASSERT_RETURN(fIsProcessing, false); - return (fPorts.freewheel != nullptr && *fPorts.freewheel > 0.5f); + return (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f); } - const TimeInfo* handleGetTimeInfo() + const TimeInfo* handleGetTimeInfo() const { CARLA_SAFE_ASSERT_RETURN(fIsProcessing, nullptr); @@ -313,26 +507,23 @@ protected: CARLA_SAFE_ASSERT_RETURN(event != nullptr, false); CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false); - if (fMidiEventCount >= kMaxMidiEvents*2) - return false; - // reverse-find first free event, and put it there - for (uint32_t i=(kMaxMidiEvents*2)-1; i >= fMidiEventCount; --i) + for (uint32_t i=(kMaxMidiEvents*2)-1; i > fMidiEventCount; --i) { if (fMidiEvents[i].data[0] == 0) { std::memcpy(&fMidiEvents[i], event, sizeof(MidiEvent)); - break; + return true; } } - return true; + return false; } void handleUiParameterChanged(const uint32_t index, const float value) { if (fUI.writeFunction != nullptr && fUI.controller != nullptr) - fUI.writeFunction(fUI.controller, index+fUI.offset, sizeof(float), 0, &value); + fUI.writeFunction(fUI.controller, index+fUI.portOffset, sizeof(float), 0, &value); } void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) @@ -351,27 +542,19 @@ protected: fUI.isVisible = false; } - const char* handleUiOpenFile(const bool isDir, const char* const title, const char* const filter) + const char* handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const { - static CarlaString retStr; - QFileDialog::Options options(isDir ? QFileDialog::ShowDirsOnly : 0x0); - - retStr = QFileDialog::getOpenFileName(nullptr, title, "", filter, nullptr, options).toUtf8().constData(); - - return retStr.isNotEmpty() ? (const char*)retStr : nullptr; + // TODO + return nullptr; } - const char* handleUiSaveFile(const bool isDir, const char* const title, const char* const filter) + const char* handleUiSaveFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const { - static CarlaString retStr; - QFileDialog::Options options(isDir ? QFileDialog::ShowDirsOnly : 0x0); - - retStr = QFileDialog::getSaveFileName(nullptr, title, "", filter, nullptr, options).toUtf8().constData(); - - return retStr.isNotEmpty() ? (const char*)retStr : nullptr; + // TODO + return nullptr; } - intptr_t handleDispatcher(const ::HostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) + intptr_t handleDispatcher(const HostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) { carla_debug("NativePlugin::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", opcode, index, value, ptr, opt); @@ -382,19 +565,16 @@ protected: case HOST_OPCODE_NULL: break; case HOST_OPCODE_SET_VOLUME: - //setVolume(opt, true, true); + fVolume = opt; break; case HOST_OPCODE_SET_DRYWET: - //setDryWet(opt, true, true); + carla_stdout("Plugin asked dryWet custom value %f", opt); + fNeedsDryWetFix = true; break; case HOST_OPCODE_SET_BALANCE_LEFT: - //setBalanceLeft(opt, true, true); - break; case HOST_OPCODE_SET_BALANCE_RIGHT: - //setBalanceRight(opt, true, true); - break; case HOST_OPCODE_SET_PANNING: - //setPanning(opt, true, true); + // nothing break; case HOST_OPCODE_GET_PARAMETER_MIDI_CC: case HOST_OPCODE_SET_PARAMETER_MIDI_CC: @@ -404,6 +584,7 @@ protected: case HOST_OPCODE_RELOAD_PARAMETERS: case HOST_OPCODE_RELOAD_MIDI_PROGRAMS: case HOST_OPCODE_RELOAD_ALL: + // nothing break; case HOST_OPCODE_UI_UNAVAILABLE: handleUiClosed(); @@ -445,6 +626,8 @@ private: TimeInfo fTimeInfo; bool fIsProcessing; + bool fNeedsDryWetFix; + float fVolume; // Lv2 host data uint32_t fBufferSize; @@ -452,19 +635,67 @@ private: const LV2_URID_Map* fUridMap; + struct URIDs { + LV2_URID atomBlank; + LV2_URID atomFloat; + LV2_URID atomLong; + LV2_URID atomSequence; + LV2_URID midiEvent; + LV2_URID timePos; + LV2_URID timeBar; + LV2_URID timeBarBeat; + LV2_URID timeBeatsPerBar; + LV2_URID timeBeatsPerMinute; + LV2_URID timeBeatUnit; + LV2_URID timeFrame; + LV2_URID timeSpeed; + + URIDs() + : atomBlank(0), + atomFloat(0), + atomLong(0), + atomSequence(0), + midiEvent(0), + timePos(0), + timeBar(0), + timeBarBeat(0), + timeBeatsPerBar(0), + timeBeatsPerMinute(0), + timeBeatUnit(0), + timeFrame(0), + timeSpeed(0) {} + + void map(const LV2_URID_Map* const uridMap) + { + atomBlank = uridMap->map(uridMap->handle, LV2_ATOM__Blank); + atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float); + atomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long); + atomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence); + midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent); + timePos = uridMap->map(uridMap->handle, LV2_TIME__Position); + timeBar = uridMap->map(uridMap->handle, LV2_TIME__bar); + timeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat); + timeBeatUnit = uridMap->map(uridMap->handle, LV2_TIME__beatUnit); + timeFrame = uridMap->map(uridMap->handle, LV2_TIME__frame); + timeSpeed = uridMap->map(uridMap->handle, LV2_TIME__speed); + timeBeatsPerBar = uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar); + timeBeatsPerMinute = uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute); + } + } fUris; + struct UI { const LV2_External_UI_Host* host; LV2UI_Write_Function writeFunction; LV2UI_Controller controller; + uint32_t portOffset; bool isVisible; - uint32_t offset; UI() : host(nullptr), writeFunction(nullptr), controller(nullptr), - isVisible(false), - offset(0) {} + portOffset(0), + isVisible(false) {} } fUI; struct Ports { @@ -528,6 +759,8 @@ private: void init(const PluginDescriptor* const desc, PluginHandle handle) { + CARLA_SAFE_ASSERT_RETURN(desc != nullptr && handle != nullptr,) + if (desc->midiIns > 0) { eventsIn = new LV2_Atom_Sequence*[desc->midiIns]; @@ -749,11 +982,11 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sa if (pluginLabel == nullptr) { - carla_stderr("Failed to find carla native plugin with URI: \"%s\"", lv2Descriptor->URI); + carla_stderr("Failed to find carla native plugin with URI \"%s\"", lv2Descriptor->URI); return nullptr; } - carla_debug("lv2_instantiate() - looking up label %s", pluginLabel); + carla_debug("lv2_instantiate() - looking up label \"%s\"", pluginLabel); for (NonRtList::Itenerator it = sPluginDescsMgr.descs.begin(); it.valid(); it.next()) { @@ -768,7 +1001,7 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sa if (pluginDesc == nullptr) { - carla_stderr("Failed to find carla native plugin with label: \"%s\"", pluginLabel); + carla_stderr("Failed to find carla native plugin with label \"%s\"", pluginLabel); return nullptr; } @@ -815,45 +1048,56 @@ static void lv2_cleanup(LV2_Handle instance) delete instancePtr; } -#if 0 static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options) { - carla_debug("lv2_()", ); + carla_debug("lv2_get_options(%p, %p)", instance, options); return instancePtr->lv2_get_options(options); } static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options) { - carla_debug("lv2_()", ); + carla_debug("lv2_set_options(%p, %p)", instance, options); return instancePtr->lv2_set_options(options); } +static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index) +{ + carla_debug("lv2_get_program(%p, %i)", instance, index); + return instancePtr->lv2_get_program(index); +} + +static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program) +{ + carla_debug("lv2_select_program(%p, %i, %i)", instance, bank, program); + return instancePtr->lv2_select_program(bank, program); +} + static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features) { - carla_debug("lv2_()", ); + carla_debug("lv2_save(%p, %p, %p, %i, %p)", instance, store, handle, flags, features); return instancePtr->lv2_save(store, handle, flags, features); } static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features) { - carla_debug("lv2_()", ); + carla_debug("lv2_restore(%p, %p, %p, %i, %p)", instance, retrieve, handle, flags, features); return instancePtr->lv2_restore(retrieve, handle, flags, features); } -#endif static const void* lv2_extension_data(const char* uri) { - carla_debug("lv2_extension_data(%s)", uri); + carla_debug("lv2_extension_data(\"%s\")", uri); -#if 0 - static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options }; - static const LV2_State_Interface state = { lv2_save, lv2_restore }; + static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options }; + static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program }; + static const LV2_State_Interface state = { lv2_save, lv2_restore }; if (std::strcmp(uri, LV2_OPTIONS__interface) == 0) return &options; + if (std::strcmp(uri, LV2_PROGRAMS__Interface) == 0) + return &programs; if (std::strcmp(uri, LV2_STATE__interface) == 0) return &state; -#endif return nullptr; } @@ -883,7 +1127,11 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, cons return nullptr; } - plugin->lv2ui_instantiate(writeFunction, controller, widget, features); + if (! plugin->lv2ui_instantiate(writeFunction, controller, widget, features)) + { + carla_stderr("Host doesn't support external UI"); + return nullptr; + } return (LV2UI_Handle)plugin; } @@ -902,12 +1150,31 @@ static void lv2ui_cleanup(LV2UI_Handle ui) uiPtr->lv2ui_cleanup(); } +static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program) +{ + carla_debug("lv2ui_select_program(%p, %i, %i)", ui, bank, program); + uiPtr->lv2ui_select_program(bank, program); +} + +static const void* lv2ui_extension_data(const char* uri) +{ + carla_debug("lv2ui_extension_data(\"%s\")", uri); + + static const LV2_Programs_UI_Interface uiprograms = { lv2ui_select_program }; + + if (std::strcmp(uri, LV2_PROGRAMS__UIInterface) == 0) + return &uiprograms; + + return nullptr; +} + #undef uiPtr // ----------------------------------------------------------------------- // Startup code -CARLA_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index) +CARLA_EXPORT +const LV2_Descriptor* lv2_descriptor(uint32_t index) { carla_debug("lv2_descriptor(%i)", index); @@ -936,7 +1203,7 @@ CARLA_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index) tmpURI += pluginDesc->label; } - carla_debug("lv2_descriptor(%i) - not found, allocating new with uri: %s", index, (const char*)tmpURI); + carla_debug("lv2_descriptor(%i) - not found, allocating new with uri \"%s\"", index, (const char*)tmpURI); const LV2_Descriptor* const lv2Desc(new const LV2_Descriptor{ /* URI */ carla_strdup(tmpURI), @@ -951,10 +1218,11 @@ CARLA_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index) sPluginDescsMgr.lv2Descs.append(lv2Desc); - return sPluginDescsMgr.lv2Descs.getLast(); + return lv2Desc; } -CARLA_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) +CARLA_EXPORT +const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) { carla_debug("lv2ui_descriptor(%i)", index); @@ -963,7 +1231,7 @@ CARLA_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) /* instantiate */ lv2ui_instantiate, /* cleanup */ lv2ui_cleanup, /* port_event */ lv2ui_port_event, - /* extension_data */ nullptr + /* extension_data */ lv2ui_extension_data }; static const LV2UI_Descriptor lv2UiDescOld = { @@ -971,7 +1239,7 @@ CARLA_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) /* instantiate */ lv2ui_instantiate, /* cleanup */ lv2ui_cleanup, /* port_event */ lv2ui_port_event, - /* extension_data */ nullptr + /* extension_data */ lv2ui_extension_data }; switch (index) diff --git a/source/utils/CarlaString.hpp b/source/utils/CarlaString.hpp index 172e072ea..fab93dae2 100644 --- a/source/utils/CarlaString.hpp +++ b/source/utils/CarlaString.hpp @@ -381,7 +381,10 @@ public: CarlaString& operator+=(const char* const strBuf) { - const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; + if (strBuf == nullptr) + return *this; + + const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1; char newBuf[newBufSize]; std::strcpy(newBuf, fBuffer); @@ -403,7 +406,9 @@ public: char newBuf[newBufSize]; std::strcpy(newBuf, fBuffer); - std::strcat(newBuf, strBuf); + + if (strBuf != nullptr) + std::strcat(newBuf, strBuf); return CarlaString(newBuf); }