From a30575155f53dfa3c3d788446eaa8ffbb0693f1c Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 3 Aug 2013 00:20:02 +0100 Subject: [PATCH] Continue cleanup; Initial Carla-as-plugin code (new version) --- .gitignore | 2 + source/backend/native/Makefile | 10 +- source/backend/native/audio-file.cpp | 1 + source/backend/native/distrho-3bandeq.cpp | 1 + .../backend/native/distrho-3bandsplitter.cpp | 1 + source/backend/native/distrho-nekobi.cpp | 1 + source/backend/native/distrho-notes.cpp | 1 + source/backend/native/distrho-pingpongpan.cpp | 1 + .../backend/native/distrho-stereoenhancer.cpp | 1 + source/backend/native/midi-file.cpp | 1 + source/backend/native/midi-sequencer.cpp | 1 + source/backend/native/sunvox-file.cpp | 1 + source/backend/native/zynaddsubfx.cpp | 1 + source/backend/plugin/NativePlugin.cpp | 8 +- source/backend/standalone/Makefile | 2 +- source/modules/utils/RtList.hpp | 2 + source/modules/widgets/Makefile | 2 +- source/plugin/Makefile | 91 +++- source/plugin/carla-native-base.cpp | 145 ++++++ source/plugin/carla-native-export.cpp | 450 ++++++++++++++++++ source/plugin/carla-native-plugin.cpp | 91 ++++ 21 files changed, 779 insertions(+), 35 deletions(-) create mode 100644 source/plugin/carla-native-base.cpp create mode 100644 source/plugin/carla-native-export.cpp create mode 100644 source/plugin/carla-native-plugin.cpp diff --git a/.gitignore b/.gitignore index 0779a0072..cf6d26b96 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,8 @@ carla-discovery-native carla-discovery-posix32 carla-discovery-posix64 +carla-native-export + data/windows/Carla data/windows/CarlaControl source/tests/ANSI diff --git a/source/backend/native/Makefile b/source/backend/native/Makefile index 54e4c1394..9f5ba0f5b 100644 --- a/source/backend/native/Makefile +++ b/source/backend/native/Makefile @@ -201,11 +201,11 @@ zynaddsubfx-ui.cpp.o: zynaddsubfx-ui.cpp $(ZYN_UI_FILES_H) # -------------------------------------------------------------- -# %.c.o: %.c -# $(CC) $< $(BUILD_C_FLAGS) -c -o $@ -# -# %.cpp.o: %.cpp -# $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ +%.c.o: %.c + $(CC) $< $(BUILD_C_FLAGS) -c -o $@ + +%.cpp.o: %.cpp + $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ moc_%.cpp: %.hpp $(MOC) $< -DMOC_PARSING -o $@ diff --git a/source/backend/native/audio-file.cpp b/source/backend/native/audio-file.cpp index 6404547fd..6cc45e09a 100644 --- a/source/backend/native/audio-file.cpp +++ b/source/backend/native/audio-file.cpp @@ -262,6 +262,7 @@ static const PluginDescriptor audiofileDesc = { // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_audiofile() { carla_register_native_plugin(&audiofileDesc); diff --git a/source/backend/native/distrho-3bandeq.cpp b/source/backend/native/distrho-3bandeq.cpp index 1e07b4244..6474e1916 100644 --- a/source/backend/native/distrho-3bandeq.cpp +++ b/source/backend/native/distrho-3bandeq.cpp @@ -50,6 +50,7 @@ END_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_3BandEQ() { USE_NAMESPACE_DISTRHO diff --git a/source/backend/native/distrho-3bandsplitter.cpp b/source/backend/native/distrho-3bandsplitter.cpp index f93328983..389dc4d15 100644 --- a/source/backend/native/distrho-3bandsplitter.cpp +++ b/source/backend/native/distrho-3bandsplitter.cpp @@ -50,6 +50,7 @@ END_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_3BandSplitter() { USE_NAMESPACE_DISTRHO diff --git a/source/backend/native/distrho-nekobi.cpp b/source/backend/native/distrho-nekobi.cpp index 627d196a9..1ee04cccf 100644 --- a/source/backend/native/distrho-nekobi.cpp +++ b/source/backend/native/distrho-nekobi.cpp @@ -50,6 +50,7 @@ END_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_Nekobi() { USE_NAMESPACE_DISTRHO diff --git a/source/backend/native/distrho-notes.cpp b/source/backend/native/distrho-notes.cpp index c55b26846..ce0d922f5 100644 --- a/source/backend/native/distrho-notes.cpp +++ b/source/backend/native/distrho-notes.cpp @@ -49,6 +49,7 @@ END_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_Notes() { USE_NAMESPACE_DISTRHO diff --git a/source/backend/native/distrho-pingpongpan.cpp b/source/backend/native/distrho-pingpongpan.cpp index 777d5f273..1ac8ba6f3 100644 --- a/source/backend/native/distrho-pingpongpan.cpp +++ b/source/backend/native/distrho-pingpongpan.cpp @@ -50,6 +50,7 @@ END_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_PingPongPan() { USE_NAMESPACE_DISTRHO diff --git a/source/backend/native/distrho-stereoenhancer.cpp b/source/backend/native/distrho-stereoenhancer.cpp index 4140249c5..d1e379144 100644 --- a/source/backend/native/distrho-stereoenhancer.cpp +++ b/source/backend/native/distrho-stereoenhancer.cpp @@ -50,6 +50,7 @@ END_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_StereoEnhancer() { USE_NAMESPACE_DISTRHO diff --git a/source/backend/native/midi-file.cpp b/source/backend/native/midi-file.cpp index a00cc430c..d5800518a 100644 --- a/source/backend/native/midi-file.cpp +++ b/source/backend/native/midi-file.cpp @@ -237,6 +237,7 @@ static const PluginDescriptor midifileDesc = { // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_midifile() { carla_register_native_plugin(&midifileDesc); diff --git a/source/backend/native/midi-sequencer.cpp b/source/backend/native/midi-sequencer.cpp index 71f6c7958..d7719c182 100644 --- a/source/backend/native/midi-sequencer.cpp +++ b/source/backend/native/midi-sequencer.cpp @@ -251,6 +251,7 @@ static const PluginDescriptor midiSequencerDesc = { // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_midiSequencer() { carla_register_native_plugin(&midiSequencerDesc); diff --git a/source/backend/native/sunvox-file.cpp b/source/backend/native/sunvox-file.cpp index d209cfd34..2daa78471 100644 --- a/source/backend/native/sunvox-file.cpp +++ b/source/backend/native/sunvox-file.cpp @@ -177,6 +177,7 @@ static const PluginDescriptor sunvoxfileDesc = { // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_sunvoxfile() { carla_register_native_plugin(&sunvoxfileDesc); diff --git a/source/backend/native/zynaddsubfx.cpp b/source/backend/native/zynaddsubfx.cpp index d767c2844..8fa6c5bb8 100644 --- a/source/backend/native/zynaddsubfx.cpp +++ b/source/backend/native/zynaddsubfx.cpp @@ -2169,6 +2169,7 @@ static const PluginDescriptor zynaddsubfxDesc = { // ----------------------------------------------------------------------- +CARLA_EXPORT void carla_register_native_plugin_zynaddsubfx() { carla_register_native_plugin(&fxAlienWahDesc); diff --git a/source/backend/plugin/NativePlugin.cpp b/source/backend/plugin/NativePlugin.cpp index feee7cf65..43dcf14c3 100644 --- a/source/backend/plugin/NativePlugin.cpp +++ b/source/backend/plugin/NativePlugin.cpp @@ -60,11 +60,11 @@ 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_StereoEnhancer(); #endif // DISTRHO plugins (Qt) -// void carla_register_native_plugin_Notes(); +void carla_register_native_plugin_Notes(); #ifdef WANT_ZYNADDSUBFX // ZynAddSubFX @@ -104,11 +104,11 @@ void carla_register_all_plugins() 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_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/backend/standalone/Makefile b/source/backend/standalone/Makefile index 32f342022..a62a6e83d 100644 --- a/source/backend/standalone/Makefile +++ b/source/backend/standalone/Makefile @@ -8,7 +8,7 @@ include ../Makefile.mk # -------------------------------------------------------------- -BUILD_CXX_FLAGS += -I../../theme +BUILD_CXX_FLAGS += -I../../modules/theme BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo) ifeq ($(HAVE_QT4),true) diff --git a/source/modules/utils/RtList.hpp b/source/modules/utils/RtList.hpp index 205047267..b6bc423ab 100644 --- a/source/modules/utils/RtList.hpp +++ b/source/modules/utils/RtList.hpp @@ -20,6 +20,8 @@ #include "CarlaUtils.hpp" +#include + extern "C" { #include "rtmempool/list.h" #include "rtmempool/rtmempool.h" diff --git a/source/modules/widgets/Makefile b/source/modules/widgets/Makefile index 3a54148e5..fe96718b9 100644 --- a/source/modules/widgets/Makefile +++ b/source/modules/widgets/Makefile @@ -8,7 +8,7 @@ include ../../Makefile.mk # -------------------------------------------------------------- -BUILD_CXX_FLAGS += -I. -I../../includes -I../utils +BUILD_CXX_FLAGS += -I. -I.. -I../utils -I../../includes ifeq ($(HAVE_QT4),true) BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore QtGui) diff --git a/source/plugin/Makefile b/source/plugin/Makefile index 9135e162e..935f1a6dd 100644 --- a/source/plugin/Makefile +++ b/source/plugin/Makefile @@ -6,6 +6,26 @@ include ../Makefile.mk +BUILD_CXX_FLAGS += -I../backend -I../includes -I../modules -I../modules/utils + +# -------------------------------------------------------------- + +ifeq ($(HAVE_OPENGL),true) +BUILD_CXX_FLAGS += -DWANT_OPENGL +endif + +ifeq ($(HAVE_AF_DEPS),true) +BUILD_CXX_FLAGS += -DWANT_AUDIOFILE +endif + +ifeq ($(HAVE_MF_DEPS),true) +BUILD_CXX_FLAGS += -DWANT_MIDIFILE +endif + +ifeq ($(HAVE_ZYN_DEPS),true) +BUILD_CXX_FLAGS += -DWANT_ZYNADDSUBFX +endif + # -------------------------------------------------------------- # Common @@ -59,50 +79,73 @@ LINK_FLAGS += $(EXTRA_LIBS) # -------------------------------------------------------------- -LIBS = ../backend/libcarla_engine_plugin.a -LIBS += ../backend/libcarla_plugin.a +# LIBS = ../backend/libcarla_engine_xx.a +# LIBS += ../backend/libcarla_plugin.a LIBS += ../backend/libcarla_native.a -LIBS += ../libs/rtmempool.a -LIBS += ../libs/widgets.a +LIBS += ../modules/rtmempool.a +LIBS += ../modules/widgets.a +LIBS += ../modules/juce_core.a ifeq ($(CARLA_PLUGIN_SUPPORT),true) -LIBS += ../libs/lilv.a +LIBS += ../modules/lilv.a endif ifeq ($(HAVE_OPENGL),true) -LIBS += ../libs/dgl.a +LIBS += ../modules/dgl.a +endif + +ifeq ($(WIN32),true) +TARGETS = carla-native.lv2/carla-native.dll +TARGETS += carla-native-export.exe +else +ifeq ($(MACOS),true) +TARGETS = carla-native.lv2/carla-native.dylib +else +TARGETS = carla-native.lv2/carla-native.so +endif +TARGETS += carla-native-export endif # -------------------------------------------------------------- -all: dssi vst -# all: dssi lv2 vst +all: $(TARGETS) + +clean: + rm -f *.o + rm -f carla-native.lv2/* -dssi: carla-dssi.so -vst: carla-vst.so -lv2: carla.lv2/carla-lv2.so +debug: + $(MAKE) DEBUG=true # -------------------------------------------------------------- -carla-dssi.so: ../backend/engine/CarlaEnginePlugin.cpp.dssi.o $(LIBS) - $(CXX) $^ -shared $(LINK_FLAGS) -o $@ +%.cpp.o: %.cpp ../backend/CarlaNative.h + $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ -carla-vst.so: ../backend/engine/CarlaEnginePlugin.cpp.vst.o $(LIBS) +carla-native.lv2/carla-native.dll: carla-native-plugin.cpp.o $(LIBS) $(CXX) $^ -shared $(LINK_FLAGS) -o $@ -carla.lv2/carla-lv2.so: ../backend/engine/CarlaEnginePlugin.cpp.lv2.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 $@ -clean: - rm -f *.dll *.dylib *.so - rm -f carla.lv2/*.dll carla.lv2/*.dylib carla.lv2/*.so +carla-native-export: carla-native-export.cpp.o $(LIBS) + $(CXX) $^ $(LINK_FLAGS) -o $@ + ./carla-native-export -debug: - $(MAKE) DEBUG=true +carla-native-export.exe: carla-native-export.cpp.o $(LIBS) + $(CXX) $^ $(LINK_FLAGS) -o $@ + ./carla-native-export.exe # -------------------------------------------------------------- -../backend/engine/CarlaEnginePlugin.cpp.%.o: ../backend/engine/CarlaEnginePlugin.cpp - make -C ../backend/engine CarlaEnginePlugin.cpp.$*.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 new file mode 100644 index 000000000..b5b090a2c --- /dev/null +++ b/source/plugin/carla-native-base.cpp @@ -0,0 +1,145 @@ +/* + * Carla Native Plugins + * Copyright (C) 2013 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. + */ + +#include "CarlaNative.h" +#include "RtList.hpp" + +#include "lv2/lv2.h" + +// ----------------------------------------------------------------------- +// Plugin register calls + +extern "C" { + +// Simple plugins +void carla_register_native_plugin_bypass(); +void carla_register_native_plugin_lfo(); +//void carla_register_native_plugin_midiSequencer(); +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(); + +#if 0 //ndef BUILD_BRIDGE +// Carla +void carla_register_native_plugin_carla(); +#endif + +#ifdef WANT_AUDIOFILE +// AudioFile +void carla_register_native_plugin_audiofile(); +#endif + +#ifdef WANT_MIDIFILE +// MidiFile +void carla_register_native_plugin_midifile(); +#endif + +#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(); +#endif + +// DISTRHO plugins (Qt) +void carla_register_native_plugin_Notes(); + +#ifdef WANT_ZYNADDSUBFX +// ZynAddSubFX +void carla_register_native_plugin_zynaddsubfx(); +#endif +} + +// ----------------------------------------------------------------------- +// Plugin List + +struct PluginListManager { + PluginListManager() + { + // Simple plugins + carla_register_native_plugin_bypass(); + carla_register_native_plugin_lfo(); + //carla_register_native_plugin_midiSequencer(); // unfinished + 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 + +#if 0 //ndef BUILD_BRIDGE + // Carla + carla_register_native_plugin_carla(); // kinda unfinished +#endif + +#ifdef WANT_AUDIOFILE + // AudioFile + carla_register_native_plugin_audiofile(); +#endif + +#ifdef WANT_MIDIFILE + // MidiFile + carla_register_native_plugin_midifile(); +#endif + +#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 +#endif + + // DISTRHO plugins (Qt) + carla_register_native_plugin_Notes(); // unfinished + +#ifdef WANT_ZYNADDSUBFX + // ZynAddSubFX + carla_register_native_plugin_zynaddsubfx(); +#endif + } + + ~PluginListManager() + { + for (auto it = lv2Descs.begin(); it.valid(); it.next()) + { + const LV2_Descriptor*& lv2Desc(*it); + + delete[] lv2Desc->URI; + delete lv2Desc; + } + + descs.clear(); + lv2Descs.clear(); + } + + NonRtList descs; + NonRtList lv2Descs; +}; + +static PluginListManager sPluginDescsMgr; + +void carla_register_native_plugin(const PluginDescriptor* desc) +{ + sPluginDescsMgr.descs.append(desc); +} + +// ----------------------------------------------------------------------- diff --git a/source/plugin/carla-native-export.cpp b/source/plugin/carla-native-export.cpp new file mode 100644 index 000000000..3b670fddf --- /dev/null +++ b/source/plugin/carla-native-export.cpp @@ -0,0 +1,450 @@ +/* + * Carla Native Plugins + * Copyright (C) 2013 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. + */ + +#include "carla-native-base.cpp" + +#include "JuceHeader.h" + +#include "lv2/atom.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/units.h" +#include "lv2/urid.h" +#include "lv2/lv2_external_ui.h" + +#include + +#if JUCE_WINDOWS +# define PLUGIN_EXT ".dll" +#elif JUCE_MAC +# define PLUGIN_EXT ".dylib" +#else +# define PLUGIN_EXT ".so" +#endif + +using juce::String; +using juce::StringArray; +using juce::juce_wchar; + +// ----------------------------------------------------------------------- +// Converts a parameter name to an LV2 compatible symbol + +static StringArray gUsedSymbols; + +const String nameToSymbol(const String& name, const uint32_t portIndex) +{ + String symbol, trimmedName = name.trimStart().trimEnd().toLowerCase(); + + if (trimmedName.isEmpty()) + { + symbol += "lv2_port_"; + symbol += String(portIndex+1); + } + else + { + for (int i=0; i < trimmedName.length(); ++i) + { + const juce_wchar c = trimmedName[i]; + if (i == 0 && std::isdigit(c)) + symbol += "_"; + else if (std::isalpha(c) || std::isdigit(c)) + symbol += c; + else + symbol += "_"; + } + } + + // Do not allow identical symbols + if (gUsedSymbols.contains(symbol)) + { + int offset = 2; + String offsetStr = "_2"; + symbol += offsetStr; + + while (gUsedSymbols.contains(symbol)) + { + offset += 1; + String newOffsetStr = "_" + String(offset); + symbol = symbol.replace(offsetStr, newOffsetStr); + offsetStr = newOffsetStr; + } + } + + gUsedSymbols.add(symbol); + + return symbol; +} + +// ----------------------------------------------------------------------- + +void writeManifestFile() +{ + String text; + + // ------------------------------------------------------------------- + // Header + + text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; + text += "@prefix rdfs: .\n"; + text += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; + text += "\n"; + + // ------------------------------------------------------------------- + // Plugins + + for (NonRtList::Itenerator it = sPluginDescsMgr.descs.begin(); it.valid(); it.next()) + { + const PluginDescriptor*& pluginDesc(*it); + const String label(pluginDesc->label); + + if (label == "carla") + text += "\n"; + else + text += "\n"; + + text += " a lv2:Plugin ;\n"; + text += " lv2:binary ;\n"; + text += " rdfs:seeAlso <" + label + ".ttl> .\n"; + text += "\n"; + } + + // ------------------------------------------------------------------- + // UI + + text += "\n"; + text += " a <" LV2_EXTERNAL_UI__Widget "> ;\n"; + text += " ui:binary ;\n"; + text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> .\n"; + + // ------------------------------------------------------------------- + // Write file now + + std::fstream manifest("carla-native.lv2/manifest.ttl", std::ios::out); + manifest << text.toRawUTF8(); + manifest.close(); +} + +// ----------------------------------------------------------------------- + +static uint32_t host_getBufferSize(HostHandle) { return 512; } +static double host_getSampleRate(HostHandle) { return 44100.0; } +static bool host_isOffline(HostHandle) { return true; } +static intptr_t host_dispatcher(HostHandle, HostDispatcherOpcode, int32_t, intptr_t, void*, float) { return 0; } + +void writePluginFile(const PluginDescriptor* const pluginDesc) +{ + const String pluginLabel(pluginDesc->label); + const String pluginFile("carla-native.lv2/" + pluginLabel + ".ttl"); + + uint32_t portIndex = 0; + String text; + + gUsedSymbols.clear(); + + carla_stdout("Generating data for %s...", pluginDesc->name); + + // ------------------------------------------------------------------- + // Init plugin + + HostDescriptor hostDesc; + hostDesc.handle = nullptr; + hostDesc.resourceDir = ""; + hostDesc.uiName = ""; + hostDesc.get_buffer_size = host_getBufferSize; + hostDesc.get_sample_rate = host_getSampleRate; + hostDesc.is_offline = host_isOffline; + hostDesc.get_time_info = nullptr; + hostDesc.write_midi_event = nullptr; + hostDesc.ui_parameter_changed = nullptr; + hostDesc.ui_midi_program_changed = nullptr; + hostDesc.ui_custom_data_changed = nullptr; + hostDesc.ui_closed = nullptr; + hostDesc.ui_open_file = nullptr; + hostDesc.ui_save_file = nullptr; + hostDesc.dispatcher = host_dispatcher; + + PluginHandle pluginHandle = pluginDesc->instantiate(&hostDesc); + + CARLA_SAFE_ASSERT_RETURN(pluginHandle != nullptr,) + + // ------------------------------------------------------------------- + // Header + + text += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; + text += "@prefix doap: .\n"; + text += "@prefix foaf: .\n"; + text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; + text += "@prefix rdfs: .\n"; + text += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; + text += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n"; + text += "\n"; + + // ------------------------------------------------------------------- + // Plugin + + if (pluginLabel == "carla") + text += "\n"; + else + text += "\n"; + + //text += " a " + getPluginType() + " ;\n"; + + 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 += "\n"; + + // ------------------------------------------------------------------- + // UIs + + if (pluginDesc->hints & PLUGIN_HAS_GUI) + { + text += " ui:ui ;\n"; + text += "\n"; + } + + // ------------------------------------------------------------------- + // MIDI inputs + + for (uint32_t i=0; i < pluginDesc->midiIns; ++i) + { + if (i == 0) + text += " lv2:port [\n"; + else + text += " [\n"; + + text += " a lv2:InputPort, atom:AtomPort ;\n"; + text += " atom:bufferType atom:Sequence ;\n"; + + if (i == 0) + { + text += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n"; + text += " <" LV2_TIME__Position "> ;\n"; + text += " lv2:designation lv2:control ;\n"; + } + else + { + text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; + } + + text += " lv2:index " + String(portIndex++) + " ;\n"; + + if (pluginDesc->midiIns > 1) + { + text += " lv2:symbol \"lv2_events_in_" + String(i+1) + "\" ;\n"; + text += " lv2:name \"Events Input #" + String(i+1) + "\" ;\n"; + } + else + { + text += " lv2:symbol \"lv2_events_in\" ;\n"; + text += " lv2:name \"Events Input\" ;\n"; + } + + if (i+1 == pluginDesc->midiIns) + text += " ] ;\n\n"; + else + text += " ] ,\n"; + } + + // ------------------------------------------------------------------- + // MIDI outputs + + for (uint32_t i=0; i < pluginDesc->midiOuts; ++i) + { + if (i == 0) + text += " lv2:port [\n"; + else + text += " [\n"; + + text += " a lv2:OutputPort, atom:AtomPort ;\n"; + text += " atom:bufferType atom:Sequence ;\n"; + text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; + text += " lv2:index " + String(portIndex++) + " ;\n"; + + if (pluginDesc->midiOuts > 1) + { + text += " lv2:symbol \"lv2_midi_out_" + String(i+1) + "\" ;\n"; + text += " lv2:name \"MIDI Output #" + String(i+1) + "\" ;\n"; + } + else + { + text += " lv2:symbol \"lv2_midi_out\" ;\n"; + text += " lv2:name \"MIDI Output\" ;\n"; + } + + if (i+1 == pluginDesc->midiOuts) + text += " ] ;\n\n"; + else + text += " ] ,\n"; + } + + // ------------------------------------------------------------------- + // Freewheel port + + text += " lv2:port [\n"; + text += " a lv2:InputPort, lv2:ControlPort ;\n"; + text += " lv2:index " + String(portIndex++) + " ;\n"; + text += " lv2:symbol \"lv2_freewheel\" ;\n"; + text += " lv2:name \"Freewheel\" ;\n"; + text += " lv2:default 0.0 ;\n"; + text += " lv2:minimum 0.0 ;\n"; + text += " lv2:maximum 1.0 ;\n"; + text += " lv2:designation <" LV2_CORE__freeWheeling "> ;\n"; + text += " lv2:portProperty lv2:toggled ;\n"; + text += " ] ;\n"; + text += "\n"; + + // ------------------------------------------------------------------- + // Audio inputs + + for (uint32_t i=0; i < pluginDesc->audioIns; ++i) + { + if (i == 0) + text += " lv2:port [\n"; + else + text += " [\n"; + + text += " a lv2:InputPort, lv2:AudioPort ;\n"; + text += " lv2:index " + String(portIndex++) + " ;\n"; + text += " lv2:symbol \"lv2_audio_in_" + String(i+1) + "\" ;\n"; + text += " lv2:name \"Audio Input " + String(i+1) + "\" ;\n"; + + if (i+1 == pluginDesc->audioIns) + text += " ] ;\n\n"; + else + text += " ] ,\n"; + } + + // ------------------------------------------------------------------- + // Audio outputs + + for (uint32_t i=0; i < pluginDesc->audioOuts; ++i) + { + if (i == 0) + text += " lv2:port [\n"; + else + text += " [\n"; + + text += " a lv2:OutputPort, lv2:AudioPort ;\n"; + text += " lv2:index " + String(portIndex++) + " ;\n"; + text += " lv2:symbol \"lv2_audio_out_" + String(i+1) + "\" ;\n"; + text += " lv2:name \"Audio Output " + String(i+1) + "\" ;\n"; + + if (i+1 == pluginDesc->audioOuts) + text += " ] ;\n\n"; + else + text += " ] ,\n"; + } + + // ------------------------------------------------------------------- + // Parameters + + const uint32_t paramCount(pluginDesc->get_parameter_count != nullptr ? pluginDesc->get_parameter_count(pluginHandle) : 0); + + if (paramCount > 0) + { + CARLA_SAFE_ASSERT_RETURN(pluginDesc->get_parameter_info != nullptr,) + CARLA_SAFE_ASSERT_RETURN(pluginDesc->get_parameter_value != nullptr,) + } + + for (uint32_t i=0; i < paramCount; ++i) + { + const Parameter* paramInfo(pluginDesc->get_parameter_info(pluginHandle, i)); + const String paramName(paramInfo->name); + const String paramUnit(paramInfo->unit != nullptr ? paramInfo->unit : ""); + const float paramValue(pluginDesc->get_parameter_value(pluginHandle, i)); + + CARLA_SAFE_ASSERT_RETURN(paramInfo != nullptr,) + + if (i == 0) + text += " lv2:port [\n"; + else + text += " [\n"; + + text += " a lv2:InputPort, lv2:ControlPort ;\n"; + text += " lv2:index " + String(portIndex++) + " ;\n"; + text += " lv2:symbol \"" + nameToSymbol(paramName, i) + "\" ;\n"; + + if (paramName.isNotEmpty()) + text += " lv2:name \"" + paramName + "\" ;\n"; + else + text += " lv2:name \"Port " + String(i+1) + "\" ;\n"; + + text += " lv2:default " + String::formatted("%f", paramValue) + " ;\n"; + text += " lv2:minimum 0.0 ;\n"; + text += " lv2:maximum 1.0 ;\n"; + + if (paramUnit.isNotEmpty()) + { + text += " units:unit [\n"; + text += " a units:Unit ;\n"; + text += " rdfs:label \"" + paramUnit + "\" ;\n"; + text += " units:symbol \"" + paramUnit + "\" ;\n"; + text += " units:render \"%f " + paramUnit + "\" ;\n"; + text += " ] ;\n"; + } + +// if (! filter->isParameterAutomatable(i)) +// text += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ;\n"; + + if (i+1 == paramCount) + text += " ] ;\n\n"; + else + text += " ] ,\n"; + } + + text += " doap:name \"" + String(pluginDesc->name) + "\" ;\n"; + text += " doap:maintainer [ foaf:name \"" + String(pluginDesc->maker) + "\" ] .\n"; + + // ------------------------------------------------------------------- + // Write file now + + std::fstream pluginStream(pluginFile.toRawUTF8(), std::ios::out); + pluginStream << text.toRawUTF8(); + pluginStream.close(); + + // ------------------------------------------------------------------- + // Cleanup plugin + + if (pluginDesc->cleanup != nullptr) + pluginDesc->cleanup(pluginHandle); +} + +// ----------------------------------------------------------------------- + +int main() +{ + writeManifestFile(); + + for (NonRtList::Itenerator it = sPluginDescsMgr.descs.begin(); it.valid(); it.next()) + { + const PluginDescriptor*& pluginDesc(*it); + writePluginFile(pluginDesc); + } + + carla_stdout("Done."); + + return 0; +} + +// ----------------------------------------------------------------------- diff --git a/source/plugin/carla-native-plugin.cpp b/source/plugin/carla-native-plugin.cpp new file mode 100644 index 000000000..4422384f6 --- /dev/null +++ b/source/plugin/carla-native-plugin.cpp @@ -0,0 +1,91 @@ +/* + * Carla Native Plugins + * Copyright (C) 2013 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. + */ + +#include "carla-native-base.cpp" + +#include "CarlaString.hpp" + +// ----------------------------------------------------------------------- +// LV2 descriptor functions + +// ----------------------------------------------------------------------- +// Static LV2 Descriptor objects + +// ----------------------------------------------------------------------- +// Startup code + +// CARLA_EXPORT void lv2_generate_ttl(const char* basename) +// { +// createLv2Files (basename); +// } + +CARLA_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index) +{ + if (index >= sPluginDescsMgr.descs.count()) + return nullptr; + if (index < sPluginDescsMgr.lv2Descs.count()) + return sPluginDescsMgr.lv2Descs.getAt(index); + + const PluginDescriptor*& pluginDesc(sPluginDescsMgr.descs.getAt(index)); + + CarlaString tmpURI; + + if (std::strcmp(pluginDesc->label, "carla") == 0) + { + tmpURI = "http://kxstudio.sf.net/carla"; + } + else + { + tmpURI = "http://kxstudio.sf.net/carla/plugins/"; + tmpURI += pluginDesc->label; + } + + LV2_Descriptor* lv2Desc(new LV2_Descriptor); + + lv2Desc->URI = carla_strdup(tmpURI); + lv2Desc->instantiate = nullptr; + lv2Desc->connect_port = nullptr; + lv2Desc->activate = nullptr; + lv2Desc->run = nullptr; + lv2Desc->deactivate = nullptr; + lv2Desc->cleanup = nullptr; + lv2Desc->extension_data = nullptr; + + sPluginDescsMgr.lv2Descs.append(lv2Desc); + + return lv2Desc; +} + +// CARLA_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) +// { +// switch (index) +// { +// case 0: +// return &JuceLv2UI_External; +// case 1: +// return &JuceLv2UI_Parent; +// default: +// return nullptr; +// } +// } + +// ----------------------------------------------------------------------- + +int main() +{ + return 0; +}