diff --git a/source/Makefile.mk b/source/Makefile.mk index 1b19baaea..8a9c313f0 100644 --- a/source/Makefile.mk +++ b/source/Makefile.mk @@ -37,7 +37,7 @@ BUILD_C_FLAGS = $(BASE_FLAGS) -std=c99 -Wc++-compat -Wunsuffixed-float-constan BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS) LINK_FLAGS = $(LDFLAGS) -# BUILD_CXX_FLAGS += -Wzero-as-null-pointer-constant +BUILD_CXX_FLAGS += -Wzero-as-null-pointer-constant ifneq ($(DEBUG),true) BUILD_CXX_FLAGS += -DQT_NO_DEBUG -DQT_NO_DEBUG_STREAM -DQT_NO_DEBUG_OUTPUT @@ -60,6 +60,9 @@ BUILD_CXX_FLAGS += -DVESTIGE_HEADER # -------------------------------------------------------------- +HAVE_JACK = $(shell pkg-config --exists jack && echo true) +HAVE_ZYN_DEPS = $(shell pkg-config --exists fftw3 mxml && echo true) + ifeq ($(CARLA_PLUGIN_SUPPORT),true) HAVE_SUIL = $(shell pkg-config --exists suil-0 && echo true) endif @@ -73,16 +76,3 @@ ifeq ($(CARLA_RTAUDIO_SUPPORT),true) HAVE_ALSA = $(shell pkg-config --exists alsa && echo true) HAVE_PULSEAUDIO = $(shell pkg-config --exists libpulse-simple && echo true) endif - -HAVE_ZYN_DEPS = $(shell pkg-config --exists fftw3 mxml && echo true) - -# -------------------------------------------------------------- - -ifeq ($(CARLA_PLUGIN_SUPPORT),true) -BUILD_C_FLAGS += -DWANT_LV2 -BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST -endif - -ifeq ($(HAVE_ZYN_DEPS),true) -BUILD_CXX_FLAGS += -DWANT_ZYNADDSUBFX -endif diff --git a/source/backend/Makefile b/source/backend/Makefile index a3326041f..6a08a9511 100644 --- a/source/backend/Makefile +++ b/source/backend/Makefile @@ -1,32 +1,19 @@ #!/usr/bin/make -f -# Makefile for carla backend # -# ----------------------------------------- # +# Makefile for carla backend and standalone # +# -------------------------------------------------------------- # # Created by falkTX # -all: +all: carla_standalone # -------------------------------------------------------------- -# carla_backend.so: carla_engine.so carla_native.so carla_plugin.so carla_standalone.so -# $(CXX) $^ - -carla_engine.so: - $(MAKE) -C engine - -carla_native.so: - $(MAKE) -C native - -carla_plugin.so: - $(MAKE) -C plugin - -carla_standalone.so: +carla_standalone: $(MAKE) -C standalone # -------------------------------------------------------------- clean: - rm -f *.so $(MAKE) clean -C engine $(MAKE) clean -C native $(MAKE) clean -C plugin diff --git a/source/backend/Makefile.mk b/source/backend/Makefile.mk new file mode 100644 index 000000000..2ae27041e --- /dev/null +++ b/source/backend/Makefile.mk @@ -0,0 +1,48 @@ +#!/usr/bin/make -f +# Makefile for carla-backend # +# ------------------------------------ # +# Created by falkTX +# + +include ../Makefile.mk + +# -------------------------------------------------------------- + +BUILD_C_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes +BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../libs -I../../utils +BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore) + +LINK_FLAGS += $(shell pkg-config --libs QtCore) + +# -------------------------------------------------------------- + +ifeq ($(HAVE_JACK),true) +BUILD_CXX_FLAGS += -DWANT_JACK +endif + +ifeq ($(HAVE_FLUIDSYNTH),true) +BUILD_CXX_FLAGS += -DWANT_FLUIDSYNTH +endif + +ifeq ($(HAVE_LINUXSAMPLER),true) +BUILD_CXX_FLAGS += -DWANT_LINUXSAMPLER +endif + +ifeq ($(HAVE_SUIL),true) +BUILD_CXX_FLAGS += -DWANT_SUIL +endif + +ifeq ($(HAVE_ZYN_DEPS),true) +BUILD_CXX_FLAGS += -DWANT_ZYNADDSUBFX +endif + +# -------------------------------------------------------------- + +ifeq ($(CARLA_PLUGIN_SUPPORT),true) +BUILD_C_FLAGS += -DWANT_LV2 +BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST +endif + +ifeq ($(CARLA_RTAUDIO_SUPPORT),true) +BUILD_CXX_FLAGS += -DWANT_RTAUDIO +endif diff --git a/source/backend/carla_standalone.hpp b/source/backend/carla_standalone.hpp new file mode 100644 index 000000000..1628ca1a1 --- /dev/null +++ b/source/backend/carla_standalone.hpp @@ -0,0 +1,181 @@ +/* + * Carla Standalone API + * Copyright (C) 2011-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 GPL.txt file + */ + +#ifndef __CARLA_STANDALONE_HPP__ +#define __CARLA_STANDALONE_HPP__ + +#include "carla_backend.hpp" + +// TODO - create struct for internal plugin info +// TODO - dont strdup() on const-char* returns, use static char[STR_MAX] + +CARLA_BACKEND_START_NAMESPACE + +/*! + * @defgroup CarlaBackendStandalone Carla Backend Standalone + * + * The Carla Backend Standalone API + * + * @{ + */ + +#if 0 +struct PluginInfo { + PluginType type; + PluginCategory category; + unsigned int hints; + const char* binary; + const char* name; + const char* label; + const char* maker; + const char* copyright; + long uniqueId; + + PluginInfo() + : type(PLUGIN_NONE), + category(PLUGIN_CATEGORY_NONE), + hints(0x0), + binary(nullptr), + name(nullptr), + label(nullptr), + maker(nullptr), + copyright(nullptr), + uniqueId(0) {} +}; + +struct PortCountInfo { + uint32_t ins; + uint32_t outs; + uint32_t total; + + PortCountInfo() + : ins(0), + outs(0), + total(0) {} +}; + +struct ParameterInfo { + const char* name; + const char* symbol; + const char* unit; + uint32_t scalePointCount; + + ParameterInfo() + : name(nullptr), + symbol(nullptr), + unit(nullptr), + scalePointCount(0) {} +}; + +struct ScalePointInfo { + double value; + const char* label; + + ScalePointInfo() + : value(0.0), + label(nullptr) {} +}; +#endif + +CARLA_EXPORT const char* carla_get_extended_license_text(); + +CARLA_EXPORT unsigned int carla_get_engine_driver_count(); +CARLA_EXPORT const char* carla_get_engine_driver_name(unsigned int index); + +#if 0 +CARLA_EXPORT unsigned int get_internal_plugin_count(); +CARLA_EXPORT const PluginInfo* get_internal_plugin_info(unsigned int pluginId); + +CARLA_EXPORT bool engine_init(const char* driverName, const char* clientName); +CARLA_EXPORT bool engine_close(); +CARLA_EXPORT bool is_engine_running(); + +CARLA_EXPORT int add_plugin(BinaryType btype, PluginType ptype, const char* filename, const char* name, const char* label, void* extraPtr); +CARLA_EXPORT bool remove_plugin(unsigned int pluginId); + +CARLA_EXPORT const PluginInfo* get_plugin_info(unsigned int pluginId); +CARLA_EXPORT const PortCountInfo* get_audio_port_count_info(unsigned int pluginId); +CARLA_EXPORT const PortCountInfo* get_midi_port_count_info(unsigned int pluginId); +CARLA_EXPORT const PortCountInfo* get_parameter_count_info(unsigned int pluginId); +CARLA_EXPORT const ParameterInfo* get_parameter_info(unsigned short plugin_id, uint32_t parameterId); +CARLA_EXPORT const ScalePointInfo* get_parameter_scalepoint_info(unsigned int pluginId, uint32_t parameterId, uint32_t scalePointId); + +CARLA_EXPORT const ParameterData* get_parameter_data(unsigned int pluginId, uint32_t parameterId); +CARLA_EXPORT const ParameterRanges* get_parameter_ranges(unsigned int pluginId, uint32_t parameterId); +CARLA_EXPORT const MidiProgramData* get_midi_program_data(unsigned int pluginId, uint32_t midiProgramId); +CARLA_EXPORT const CustomData* get_custom_data(unsigned int pluginId, uint32_t customDataId); +CARLA_EXPORT const char* get_chunk_data(unsigned int pluginId); + +CARLA_EXPORT uint32_t get_parameter_count(unsigned int pluginId); +CARLA_EXPORT uint32_t get_program_count(unsigned int pluginId); +CARLA_EXPORT uint32_t get_midi_program_count(unsigned int pluginId); +CARLA_EXPORT uint32_t get_custom_data_count(unsigned int pluginId); + +CARLA_EXPORT const char* get_parameter_text(unsigned int pluginId, uint32_t parameterId); +CARLA_EXPORT const char* get_program_name(unsigned int pluginId, uint32_t programId); +CARLA_EXPORT const char* get_midi_program_name(unsigned int pluginId, uint32_t midiProgramId); +CARLA_EXPORT const char* get_real_plugin_name(unsigned int pluginId); + +CARLA_EXPORT int32_t get_current_program_index(unsigned int pluginId); +CARLA_EXPORT int32_t get_current_midi_program_index(unsigned int pluginId); + +CARLA_EXPORT double get_default_parameter_value(unsigned int pluginId, uint32_t parameterId); +CARLA_EXPORT double get_current_parameter_value(unsigned int pluginId, uint32_t parameterId); + +CARLA_EXPORT double get_input_peak_value(unsigned int pluginId, unsigned short portId); +CARLA_EXPORT double get_output_peak_value(unsigned int pluginId, unsigned short portId); + +CARLA_EXPORT void set_active(unsigned int pluginId, bool onOff); +CARLA_EXPORT void set_drywet(unsigned int pluginId, double value); +CARLA_EXPORT void set_volume(unsigned int pluginId, double value); +CARLA_EXPORT void set_balance_left(unsigned int pluginId, double value); +CARLA_EXPORT void set_balance_right(unsigned int pluginId, double value); + +CARLA_EXPORT void set_parameter_value(unsigned int pluginId, uint32_t parameterId, double value); +CARLA_EXPORT void set_parameter_midi_channel(unsigned int pluginId, uint32_t parameterId, uint8_t channel); +CARLA_EXPORT void set_parameter_midi_cc(unsigned int pluginId, uint32_t parameterId, int16_t cc); +CARLA_EXPORT void set_program(unsigned int pluginId, uint32_t programId); +CARLA_EXPORT void set_midi_program(unsigned int pluginId, uint32_t midiProgramId); + +CARLA_EXPORT void set_custom_data(unsigned int pluginId, const char* type, const char* key, const char* value); +CARLA_EXPORT void set_chunk_data(unsigned int pluginId, const char* chunkData); + +CARLA_EXPORT void show_gui(unsigned int pluginId, bool yesNo); +CARLA_EXPORT void idle_guis(); + +CARLA_EXPORT void send_midi_note(unsigned int pluginId, uint8_t channel, uint8_t note, uint8_t velocity); +CARLA_EXPORT void prepare_for_save(unsigned int pluginId); + +CARLA_EXPORT uint32_t get_buffer_size(); +CARLA_EXPORT double get_sample_rate(); + +CARLA_EXPORT const char* get_last_error(); +CARLA_EXPORT const char* get_host_osc_url(); + +CARLA_EXPORT void set_callback_function(CallbackFunc func); +CARLA_EXPORT void set_option(OptionsType option, int value, const char* valueStr); + +CARLA_EXPORT void nsm_announce(const char* url, int pid); +CARLA_EXPORT void nsm_reply_open(); +CARLA_EXPORT void nsm_reply_save(); +#endif + +/**@}*/ + +CARLA_BACKEND_END_NAMESPACE + +#endif // __CARLA_STANDALONE_HPP__ diff --git a/source/backend/engine/Makefile b/source/backend/engine/Makefile index 3340bd689..d006c5409 100644 --- a/source/backend/engine/Makefile +++ b/source/backend/engine/Makefile @@ -4,45 +4,39 @@ # Created by falkTX # -include ../../Makefile.mk +include ../Makefile.mk # -------------------------------------------------------------- -BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../libs -I../../utils -BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore) # liblo -isystem /opt/kxstudio/include/ +# BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo) +BUILD_CXX_FLAGS += -isystem /opt/kxstudio/include/ LINK_FLAGS += -shared -LINK_FLAGS += $(shell pkg-config --libs liblo QtCore) +LINK_FLAGS += $(shell pkg-config --libs liblo) ifeq ($(HAVE_JACK),true) +BUILD_CXX_FLAGS += -DCARLA_ENGINE_JACK BUILD_CXX_FLAGS += $(shell pkg-config --cflags jack) -D__UNIX_JACK__ LINK_FLAGS += $(shell pkg-config --libs jack) -WANT_JACK = true +endif + +ifeq ($(CARLA_RTAUDIO_SUPPORT),true) +BUILD_CXX_FLAGS += -DCARLA_ENGINE_RTAUDIO -DHAVE_GETTIMEOFDAY +BUILD_CXX_FLAGS += -Irtaudio-4.0.11 -Irtmidi-2.0.1 +ifeq ($(DEBUG),true) +BUILD_CXX_FLAGS += -D__RTAUDIO_DEBUG__ -D__RTMIDI_DEBUG__ +else +BUILD_CXX_FLAGS += -D_FORTIFY_SOURCE=2 endif ifeq ($(HAVE_ALSA),true) BUILD_CXX_FLAGS += $(shell pkg-config --cflags alsa) -D__LINUX_ALSA__ -D__LINUX_ALSASEQ__ LINK_FLAGS += $(shell pkg-config --libs alsa) -WANT_RTAUDIO = true endif ifeq ($(HAVE_PULSEAUDIO),true) BUILD_CXX_FLAGS += $(shell pkg-config --cflags libpulse-simple) -D__LINUX_PULSE__ LINK_FLAGS += $(shell pkg-config --libs libpulse-simple) -WANT_RTAUDIO = true -endif - -ifeq ($(WANT_JACK),true) -BUILD_CXX_FLAGS += -DCARLA_ENGINE_JACK -endif - -ifeq ($(WANT_RTAUDIO),true) -BUILD_CXX_FLAGS += -DCARLA_ENGINE_RTAUDIO -DHAVE_GETTIMEOFDAY -BUILD_CXX_FLAGS += -Irtaudio-4.0.11 -Irtmidi-2.0.1 -ifeq ($(DEBUG),true) -BUILD_CXX_FLAGS += -D__RTAUDIO_DEBUG__ -D__RTMIDI_DEBUG__ -else -BUILD_CXX_FLAGS += -D_FORTIFY_SOURCE=2 endif endif @@ -50,19 +44,19 @@ endif OBJS = \ carla_engine.cpp.o \ - jack.cpp.o + jack.cpp.o \ + rtaudio.cpp.o # carla_engine_osc.cpp.o \ # carla_engine_thread.cpp.o \ -# rtaudio.cpp.o -ifeq ($(WANT_RTAUDIO),true) -# OBJS += \ -# rtaudio-4.0.11/RtAudio.cpp.o \ -# rtmidi-2.0.1/RtMidi.cpp.o +ifeq ($(CARLA_RTAUDIO_SUPPORT),true) +OBJS += \ + rtaudio-4.0.11/RtAudio.cpp.o \ + rtmidi-2.0.1/RtMidi.cpp.o endif -TARGET = ../carla_engine.so +TARGET = ../libcarla_engine.so # -------------------------------------------------------------- diff --git a/source/backend/native/Makefile b/source/backend/native/Makefile index 918f312e8..9fafc986b 100644 --- a/source/backend/native/Makefile +++ b/source/backend/native/Makefile @@ -8,12 +8,11 @@ include ../../Makefile.mk # -------------------------------------------------------------- -BUILD_C_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../utils -I../../libs/distrho-plugin-toolkit -BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore QtGui) +BUILD_CXX_FLAGS += -I../../libs/distrho-plugin-toolkit +BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtGui) LINK_FLAGS += -shared -LINK_FLAGS += $(shell pkg-config --libs QtCore QtGui) -lGL +LINK_FLAGS += $(shell pkg-config --libs QtGui) -lGL ifeq ($(HAVE_ZYN_DEPS),true) ZYN_CXX_FLAGS = $(BUILD_CXX_FLAGS) @@ -42,7 +41,7 @@ OBJS += \ zynaddsubfx-src.cpp.o endif -TARGET = ../carla_native.so +TARGET = ../libcarla_native.so # -------------------------------------------------------------- diff --git a/source/backend/plugin/Makefile b/source/backend/plugin/Makefile index 15092da9c..9fd09c4c9 100644 --- a/source/backend/plugin/Makefile +++ b/source/backend/plugin/Makefile @@ -8,24 +8,23 @@ include ../../Makefile.mk # -------------------------------------------------------------- -BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../libs -I../../utils -BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo QtCore QtGui) +BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo QtGui) LINK_FLAGS += -shared -LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui) +LINK_FLAGS += $(shell pkg-config --libs liblo QtGui) ifeq ($(HAVE_SUIL),true) -BUILD_CXX_FLAGS += $(shell pkg-config --cflags suil-0) -DWANT_SUIL +BUILD_CXX_FLAGS += $(shell pkg-config --cflags suil-0) LINK_FLAGS += $(shell pkg-config --libs suil-0) endif ifeq ($(HAVE_FLUIDSYNTH),true) -BUILD_CXX_FLAGS += $(shell pkg-config --cflags fluidsynth) -DWANT_FLUIDSYNTH +BUILD_CXX_FLAGS += $(shell pkg-config --cflags fluidsynth) LINK_FLAGS += $(shell pkg-config --libs fluidsynth) endif ifeq ($(HAVE_LINUXSAMPLER),true) -BUILD_CXX_FLAGS += $(shell pkg-config --cflags linuxsampler) -DWANT_LINUXSAMPLER +BUILD_CXX_FLAGS += $(shell pkg-config --cflags linuxsampler) LINK_FLAGS += $(shell pkg-config --libs linuxsampler) endif @@ -43,7 +42,7 @@ OBJS = \ # fluidsynth.cpp.o \ # linuxsampler.cpp.o -TARGET = ../carla_plugin.so +TARGET = ../libcarla_plugin.so # -------------------------------------------------------------- diff --git a/source/backend/standalone/Makefile b/source/backend/standalone/Makefile new file mode 100644 index 000000000..e68634b59 --- /dev/null +++ b/source/backend/standalone/Makefile @@ -0,0 +1,35 @@ +#!/usr/bin/make -f +# Makefile for carla-standalone # +# --------------------------------------- # +# Created by falkTX +# + +include ../Makefile.mk + +# -------------------------------------------------------------- + +# LINK_FLAGS += -shared +LINK_FLAGS += -Wl,-rpath,. -L.. -lcarla_engine -lcarla_native -lcarla_plugin + +# -------------------------------------------------------------- + +OBJS = \ + carla_standalone.cpp.o + +TARGET = ../carla_standalone +#lib*.so + +# -------------------------------------------------------------- + +all: $(TARGET) + +clean: + rm -f $(OBJS) $(TARGET) + +# -------------------------------------------------------------- + +%.cpp.o: %.cpp + $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ + +$(TARGET): $(OBJS) + $(CXX) $^ $(LINK_FLAGS) -o $@ diff --git a/source/backend/standalone/carla_standalone.cpp b/source/backend/standalone/carla_standalone.cpp new file mode 100644 index 000000000..002a78298 --- /dev/null +++ b/source/backend/standalone/carla_standalone.cpp @@ -0,0 +1,1965 @@ +/* + * Carla Standalone + * Copyright (C) 2011-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 GPL.txt file + */ + +#include "carla_standalone.hpp" +#include "carla_engine.hpp" +#include "carla_plugin.hpp" +#include "carla_native.h" + +int main(int argc, char* argv[]) +{ + CARLA_BACKEND_USE_NAMESPACE + std::printf("%s\n", carla_get_extended_license_text()); + return 0; +} + +CARLA_BACKEND_START_NAMESPACE + +// ------------------------------------------------------------------------------------------------------------------- + +#if 0 +// Single, standalone engine +struct CarlaBackendStandalone { + CarlaBackend::EngineOptions options; + CarlaBackend::CarlaEngine* engine; + CarlaBackend::CallbackFunc callback; + CarlaString lastError; + CarlaString procName; + bool started; + + CarlaBackendStandalone() + : engine(nullptr), + callback(nullptr), + started(false) {} + +} standalone; +#endif + +// ------------------------------------------------------------------------------------------------------------------- + +const char* carla_get_extended_license_text() +{ + qDebug("carla_get_extended_license_text()"); + + static CarlaString retText; + + if (retText.isEmpty()) + { + retText = "

This current Carla build is using the following features and 3rd-party code:

"; + retText += ""; + +#ifdef WANT_LINUXSAMPLER + retText += "

(*) Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors.

"; +#endif + } + + return retText; +} + +unsigned int carla_get_engine_driver_count() +{ + qDebug("carla_get_engine_driver_count()"); + + return CarlaEngine::getDriverCount(); +} + +const char* carla_get_engine_driver_name(unsigned int index) +{ + qDebug("carla_get_engine_driver_name(%i)", index); + + return CarlaEngine::getDriverName(index); +} + +CARLA_BACKEND_END_NAMESPACE + +#if 0 +// ------------------------------------------------------------------------------------------------------------------- + +unsigned int get_internal_plugin_count() +{ + qDebug("CarlaBackendStandalone::get_internal_plugin_count()"); + + return CarlaBackend::CarlaPlugin::getNativePluginCount(); +} + +const PluginInfo* get_internal_plugin_info(unsigned int pluginId) +{ + qDebug("CarlaBackendStandalone::get_internal_plugin_info(%i)", pluginId); + + static PluginInfo info; + + const PluginDescriptor* const nativePlugin = CarlaBackend::CarlaPlugin::getNativePluginDescriptor(pluginId); + + CARLA_ASSERT(nativePlugin); + + // as internal plugin, this must never fail + if (! nativePlugin) + return nullptr; + + info.type = CarlaBackend::PLUGIN_INTERNAL; + info.category = static_cast(nativePlugin->category); + info.hints = 0x0; + info.name = nativePlugin->name; + info.label = nativePlugin->label; + info.maker = nativePlugin->maker; + info.copyright = nativePlugin->copyright; + + if (nativePlugin->hints & PLUGIN_IS_SYNTH) + info.hints |= CarlaBackend::PLUGIN_IS_SYNTH; + if (nativePlugin->hints & PLUGIN_HAS_GUI) + info.hints |= CarlaBackend::PLUGIN_HAS_GUI; + if (nativePlugin->hints & PLUGIN_USES_SINGLE_THREAD) + info.hints |= CarlaBackend::PLUGIN_USES_SINGLE_THREAD; + + return &info; +} + +// ------------------------------------------------------------------------------------------------------------------- + +bool engine_init(const char* driverName, const char* clientName) +{ + qDebug("CarlaBackendStandalone::engine_init(\"%s\", \"%s\")", driverName, clientName); + CARLA_ASSERT(! standalone.engine); + + standalone.engine = CarlaBackend::CarlaEngine::newDriverByName(driverName); + + if (! standalone.engine) + { + standalone.lastError = "The seleted audio driver is not available!"; + return false; + } + +#ifndef Q_OS_WIN + // TODO: make this an option, put somewhere else + if (! getenv("WINE_RT")) + { + carla_setenv("WINE_RT", "15"); + carla_setenv("WINE_SVR_RT", "10"); + } +#endif + + standalone.engine->setCallback(standalone.callback, nullptr); + + standalone.engine->setOption(CarlaBackend::OPTION_PROCESS_MODE, standalone.options.processMode, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_PROCESS_HIGH_PRECISION, standalone.options.processHighPrecision, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_MAX_PARAMETERS, standalone.options.maxParameters, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_PREFERRED_BUFFER_SIZE, standalone.options.preferredBufferSize, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_PREFERRED_SAMPLE_RATE, standalone.options.preferredSampleRate, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_FORCE_STEREO, standalone.options.forceStereo, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_USE_DSSI_VST_CHUNKS, standalone.options.useDssiVstChunks, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_PREFER_PLUGIN_BRIDGES, standalone.options.preferPluginBridges, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_PREFER_UI_BRIDGES, standalone.options.preferUiBridges, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_OSC_UI_TIMEOUT, standalone.options.oscUiTimeout, nullptr); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_POSIX32, 0, standalone.options.bridge_posix32); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_POSIX64, 0, standalone.options.bridge_posix64); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_WIN32, 0, standalone.options.bridge_win32); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_WIN64, 0, standalone.options.bridge_win64); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_LV2_GTK2, 0, standalone.options.bridge_lv2gtk2); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_LV2_GTK3, 0, standalone.options.bridge_lv2gtk3); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_LV2_QT4, 0, standalone.options.bridge_lv2qt4); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_LV2_QT5, 0, standalone.options.bridge_lv2qt5); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_LV2_COCOA, 0, standalone.options.bridge_lv2cocoa); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_LV2_WINDOWS, 0, standalone.options.bridge_lv2win); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_LV2_X11, 0, standalone.options.bridge_lv2qt4); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_VST_COCOA, 0, standalone.options.bridge_vstcocoa); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_VST_HWND, 0, standalone.options.bridge_vsthwnd); + standalone.engine->setOption(CarlaBackend::OPTION_PATH_BRIDGE_VST_X11, 0, standalone.options.bridge_vstx11); + + if (standalone.procName.isNotEmpty()) + standalone.engine->setOption(CarlaBackend::OPTION_PROCESS_NAME, 0, standalone.procName); + + standalone.started = standalone.engine->init(clientName); + + if (standalone.started) + { + standalone.lastError = "no error"; + } + else if (standalone.engine) + { + delete standalone.engine; + standalone.engine = nullptr; + } + + return standalone.started; +} + +bool engine_close() +{ + qDebug("CarlaBackendStandalone::engine_close()"); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + { + standalone.lastError = "Engine is not started"; + return false; + } + + standalone.engine->aboutToClose(); + standalone.engine->removeAllPlugins(); + bool closed = standalone.engine->close(); + + standalone.started = false; + + // cleanup static data + get_plugin_info(0); + get_parameter_info(0, 0); + get_parameter_scalepoint_info(0, 0, 0); + get_chunk_data(0); + get_program_name(0, 0); + get_midi_program_name(0, 0); + get_real_plugin_name(0); + + delete standalone.engine; + standalone.engine = nullptr; + + return closed; +} + +bool is_engine_running() +{ + qDebug("CarlaBackendStandalone::is_engine_running()"); + + return standalone.engine && standalone.engine->isRunning(); +} + +// ------------------------------------------------------------------------------------------------------------------- + +short add_plugin(CarlaBackend::BinaryType btype, CarlaBackend::PluginType ptype, const char* filename, const char* const name, const char* label, void* extraStuff) +{ + qDebug("CarlaBackendStandalone::add_plugin(%s, %s, \"%s\", \"%s\", \"%s\", %p)", CarlaBackend::BinaryType2Str(btype), CarlaBackend::PluginType2Str(ptype), filename, name, label, extraStuff); + CARLA_ASSERT(standalone.engine); + + if (btype != CarlaBackend::BINARY_NATIVE && ! extraStuff) + { + switch (btype) + { + case CarlaBackend::BINARY_NONE: + case CarlaBackend::BINARY_OTHER: + break; + case CarlaBackend::BINARY_POSIX32: + extraStuff = (void*)(const char*)standalone.options.bridge_posix32; + break; + case CarlaBackend::BINARY_POSIX64: + extraStuff = (void*)(const char*)standalone.options.bridge_posix64; + break; + case CarlaBackend::BINARY_WIN32: + extraStuff = (void*)(const char*)standalone.options.bridge_win32; + break; + case CarlaBackend::BINARY_WIN64: + extraStuff = (void*)(const char*)standalone.options.bridge_win64; + break; + } + } + + if (standalone.engine && standalone.engine->isRunning()) + return standalone.engine->addPlugin(btype, ptype, filename, name, label, extraStuff); + + standalone.lastError = "Engine is not started"; + return -1; +} + +bool remove_plugin(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::remove_plugin(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (standalone.engine) + return standalone.engine->removePlugin(pluginId); + + standalone.lastError = "Engine is not started"; + return false; +} + +// ------------------------------------------------------------------------------------------------------------------- + +const PluginInfo* get_plugin_info(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_plugin_info(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + static PluginInfo info; + + // reset + info.type = CarlaBackend::PLUGIN_NONE; + info.category = CarlaBackend::PLUGIN_CATEGORY_NONE; + info.hints = 0x0; + info.binary = nullptr; + info.name = nullptr; + info.uniqueId = 0; + + // cleanup + if (info.label) + { + free((void*)info.label); + info.label = nullptr; + } + + if (info.maker) + { + free((void*)info.maker); + info.maker = nullptr; + } + + if (info.copyright) + { + free((void*)info.copyright); + info.copyright = nullptr; + } + + if (! standalone.engine) + return &info; + + if (! standalone.started) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + char strBufLabel[STR_MAX] = { 0 }; + char strBufMaker[STR_MAX] = { 0 }; + char strBufCopyright[STR_MAX] = { 0 }; + + info.type = plugin->type(); + info.category = plugin->category(); + info.hints = plugin->hints(); + info.binary = plugin->filename(); + info.name = plugin->name(); + info.uniqueId = plugin->uniqueId(); + + plugin->getLabel(strBufLabel); + info.label = strdup(strBufLabel); + + plugin->getMaker(strBufMaker); + info.maker = strdup(strBufMaker); + + plugin->getCopyright(strBufCopyright); + info.copyright = strdup(strBufCopyright); + + return &info; + } + + qCritical("CarlaBackendStandalone::get_plugin_info(%i) - could not find plugin", pluginId); + return &info; +} + +const PortCountInfo* get_audio_port_count_info(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_audio_port_count_info(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + static PortCountInfo info; + + // reset + info.ins = 0; + info.outs = 0; + info.total = 0; + + if (! standalone.engine) + return &info; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + info.ins = plugin->audioInCount(); + info.outs = plugin->audioOutCount(); + info.total = info.ins + info.outs; + return &info; + } + + qCritical("CarlaBackendStandalone::get_audio_port_count_info(%i) - could not find plugin", pluginId); + return &info; +} + +const PortCountInfo* get_midi_port_count_info(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_midi_port_count_info(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + static PortCountInfo info; + + // reset + info.ins = 0; + info.outs = 0; + info.total = 0; + + if (! standalone.engine) + return &info; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + info.ins = plugin->midiInCount(); + info.outs = plugin->midiOutCount(); + info.total = info.ins + info.outs; + return &info; + } + + qCritical("CarlaBackendStandalone::get_midi_port_count_info(%i) - could not find plugin", pluginId); + return &info; +} + +const PortCountInfo* get_parameter_count_info(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_parameter_count_info(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + static PortCountInfo info; + + // reset + info.ins = 0; + info.outs = 0; + info.total = 0; + + if (! standalone.engine) + return &info; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + plugin->getParameterCountInfo(&info.ins, &info.outs, &info.total); + return &info; + } + + qCritical("CarlaBackendStandalone::get_parameter_count_info(%i) - could not find plugin", pluginId); + return &info; +} + +const ParameterInfo* get_parameter_info(unsigned short pluginId, uint32_t parameter_id) +{ + qDebug("CarlaBackendStandalone::get_parameter_info(%i, %i)", pluginId, parameter_id); + CARLA_ASSERT(standalone.engine); + + static ParameterInfo info; + + // reset + info.scalePointCount = 0; + + // cleanup + if (info.name) + { + free((void*)info.name); + info.name = nullptr; + } + + if (info.symbol) + { + free((void*)info.symbol); + info.symbol = nullptr; + } + + if (info.unit) + { + free((void*)info.unit); + info.unit = nullptr; + } + + if (! standalone.engine) + return &info; + + if (! standalone.started) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + { + char strBufName[STR_MAX] = { 0 }; + char strBufSymbol[STR_MAX] = { 0 }; + char strBufUnit[STR_MAX] = { 0 }; + + info.scalePointCount = plugin->parameterScalePointCount(parameter_id); + + plugin->getParameterName(parameter_id, strBufName); + info.name = strdup(strBufName); + + plugin->getParameterSymbol(parameter_id, strBufSymbol); + info.symbol = strdup(strBufSymbol); + + plugin->getParameterUnit(parameter_id, strBufUnit); + info.unit = strdup(strBufUnit); + } + else + qCritical("CarlaBackendStandalone::get_parameter_info(%i, %i) - parameter_id out of bounds", pluginId, parameter_id); + + return &info; + } + + qCritical("CarlaBackendStandalone::get_parameter_info(%i, %i) - could not find plugin", pluginId, parameter_id); + return &info; +} + +const ScalePointInfo* get_parameter_scalepoint_info(unsigned short pluginId, uint32_t parameter_id, uint32_t scalepoint_id) +{ + qDebug("CarlaBackendStandalone::get_parameter_scalepoint_info(%i, %i, %i)", pluginId, parameter_id, scalepoint_id); + CARLA_ASSERT(standalone.engine); + + static ScalePointInfo info; + + // reset + info.value = 0.0; + + // cleanup + if (info.label) + { + free((void*)info.label); + info.label = nullptr; + } + + if (! standalone.engine) + return &info; + + if (! standalone.started) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + { + if (scalepoint_id < plugin->parameterScalePointCount(parameter_id)) + { + char strBufLabel[STR_MAX] = { 0 }; + + info.value = plugin->getParameterScalePointValue(parameter_id, scalepoint_id); + + plugin->getParameterScalePointLabel(parameter_id, scalepoint_id, strBufLabel); + info.label = strdup(strBufLabel); + } + else + qCritical("CarlaBackendStandalone::get_parameter_scalepoint_info(%i, %i, %i) - scalepoint_id out of bounds", pluginId, parameter_id, scalepoint_id); + } + else + qCritical("CarlaBackendStandalone::get_parameter_scalepoint_info(%i, %i, %i) - parameter_id out of bounds", pluginId, parameter_id, parameter_id); + + return &info; + } + + qCritical("CarlaBackendStandalone::get_parameter_scalepoint_info(%i, %i, %i) - could not find plugin", pluginId, parameter_id, scalepoint_id); + return &info; +} + +const GuiInfo* get_gui_info(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_gui_info(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + static GuiInfo info; + + // reset + info.type = CarlaBackend::GUI_NONE; + info.resizable = false; + + if (! standalone.engine) + return &info; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + plugin->getGuiInfo(&info.type, &info.resizable); + return &info; + } + + qCritical("CarlaBackendStandalone::get_gui_info(%i) - could not find plugin", pluginId); + return &info; +} + +// ------------------------------------------------------------------------------------------------------------------- + +const CarlaBackend::ParameterData* get_parameter_data(unsigned short pluginId, uint32_t parameter_id) +{ + qDebug("CarlaBackendStandalone::get_parameter_data(%i, %i)", pluginId, parameter_id); + CARLA_ASSERT(standalone.engine); + + static CarlaBackend::ParameterData data; + + if (! standalone.engine) + return &data; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + return plugin->parameterData(parameter_id); + + qCritical("CarlaBackendStandalone::get_parameter_data(%i, %i) - parameter_id out of bounds", pluginId, parameter_id); + return &data; + } + + qCritical("CarlaBackendStandalone::get_parameter_data(%i, %i) - could not find plugin", pluginId, parameter_id); + return &data; +} + +const CarlaBackend::ParameterRanges* get_parameter_ranges(unsigned short pluginId, uint32_t parameter_id) +{ + qDebug("CarlaBackendStandalone::get_parameter_ranges(%i, %i)", pluginId, parameter_id); + CARLA_ASSERT(standalone.engine); + + static CarlaBackend::ParameterRanges ranges; + + if (! standalone.engine) + return &ranges; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + return plugin->parameterRanges(parameter_id); + + qCritical("CarlaBackendStandalone::get_parameter_ranges(%i, %i) - parameter_id out of bounds", pluginId, parameter_id); + return &ranges; + } + + qCritical("CarlaBackendStandalone::get_parameter_ranges(%i, %i) - could not find plugin", pluginId, parameter_id); + return &ranges; +} + +const CarlaBackend::MidiProgramData* get_midi_program_data(unsigned short pluginId, uint32_t midi_program_id) +{ + qDebug("CarlaBackendStandalone::get_midi_program_data(%i, %i)", pluginId, midi_program_id); + CARLA_ASSERT(standalone.engine); + + static CarlaBackend::MidiProgramData data; + + if (! standalone.engine) + return &data; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (midi_program_id < plugin->midiProgramCount()) + return plugin->midiProgramData(midi_program_id); + + qCritical("CarlaBackendStandalone::get_midi_program_data(%i, %i) - midi_program_id out of bounds", pluginId, midi_program_id); + return &data; + } + + qCritical("CarlaBackendStandalone::get_midi_program_data(%i, %i) - could not find plugin", pluginId, midi_program_id); + return &data; +} + +const CarlaBackend::CustomData* get_custom_data(unsigned short pluginId, uint32_t custom_data_id) +{ + qDebug("CarlaBackendStandalone::get_custom_data(%i, %i)", pluginId, custom_data_id); + CARLA_ASSERT(standalone.engine); + + static CarlaBackend::CustomData data; + + if (! standalone.engine) + return &data; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (custom_data_id < plugin->customDataCount()) + return plugin->customData(custom_data_id); + + qCritical("CarlaBackendStandalone::get_custom_data(%i, %i) - custom_data_id out of bounds", pluginId, custom_data_id); + return &data; + } + + qCritical("CarlaBackendStandalone::get_custom_data(%i, %i) - could not find plugin", pluginId, custom_data_id); + return &data; +} + +const char* get_chunk_data(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_chunk_data(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + static const char* chunk_data = nullptr; + + // cleanup + if (chunk_data) + { + free((void*)chunk_data); + chunk_data = nullptr; + } + + if (! standalone.engine) + return nullptr; + + if (! standalone.started) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (plugin->hints() & CarlaBackend::PLUGIN_USES_CHUNKS) + { + void* data = nullptr; + const int32_t dataSize = plugin->chunkData(&data); + + if (data && dataSize >= 4) + { + const QByteArray chunk((const char*)data, dataSize); + chunk_data = strdup(chunk.toBase64().constData()); + } + else + qCritical("CarlaBackendStandalone::get_chunk_data(%i) - got invalid chunk data", pluginId); + } + else + qCritical("CarlaBackendStandalone::get_chunk_data(%i) - plugin does not support chunks", pluginId); + + return chunk_data; + } + + qCritical("CarlaBackendStandalone::get_chunk_data(%i) - could not find plugin", pluginId); + return nullptr; +} + +// ------------------------------------------------------------------------------------------------------------------- + +uint32_t get_parameter_count(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_parameter_count(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->parameterCount(); + + qCritical("CarlaBackendStandalone::get_parameter_count(%i) - could not find plugin", pluginId); + return 0; +} + +uint32_t get_program_count(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_program_count(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->programCount(); + + qCritical("CarlaBackendStandalone::get_program_count(%i) - could not find plugin", pluginId); + return 0; +} + +uint32_t get_midi_program_count(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_midi_program_count(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->midiProgramCount(); + + qCritical("CarlaBackendStandalone::get_midi_program_count(%i) - could not find plugin", pluginId); + return 0; +} + +uint32_t get_custom_data_count(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_custom_data_count(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->customDataCount(); + + qCritical("CarlaBackendStandalone::get_custom_data_count(%i) - could not find plugin", pluginId); + return 0; +} + +// ------------------------------------------------------------------------------------------------------------------- + +const char* get_parameter_text(unsigned short pluginId, uint32_t parameter_id) +{ + qDebug("CarlaBackendStandalone::get_parameter_text(%i, %i)", pluginId, parameter_id); + CARLA_ASSERT(standalone.engine); + + static char textBuf[STR_MAX]; + memset(textBuf, 0, sizeof(char)*STR_MAX); + + if (! standalone.engine) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + { + plugin->getParameterText(parameter_id, textBuf); + return textBuf; + } + + qCritical("CarlaBackendStandalone::get_parameter_text(%i, %i) - parameter_id out of bounds", pluginId, parameter_id); + return nullptr; + } + + qCritical("CarlaBackendStandalone::get_parameter_text(%i, %i) - could not find plugin", pluginId, parameter_id); + return nullptr; +} + +const char* get_program_name(unsigned short pluginId, uint32_t program_id) +{ + qDebug("CarlaBackendStandalone::get_program_name(%i, %i)", pluginId, program_id); + CARLA_ASSERT(standalone.engine); + + static const char* program_name = nullptr; + + // cleanup + if (program_name) + { + free((void*)program_name); + program_name = nullptr; + } + + if (! standalone.engine) + return nullptr; + + if (! standalone.started) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (program_id < plugin->programCount()) + { + char strBuf[STR_MAX] = { 0 }; + + plugin->getProgramName(program_id, strBuf); + program_name = strdup(strBuf); + + return program_name; + } + + qCritical("CarlaBackendStandalone::get_program_name(%i, %i) - program_id out of bounds", pluginId, program_id); + return nullptr; + } + + qCritical("CarlaBackendStandalone::get_program_name(%i, %i) - could not find plugin", pluginId, program_id); + return nullptr; +} + +const char* get_midi_program_name(unsigned short pluginId, uint32_t midi_program_id) +{ + qDebug("CarlaBackendStandalone::get_midi_program_name(%i, %i)", pluginId, midi_program_id); + CARLA_ASSERT(standalone.engine); + + static const char* midi_program_name = nullptr; + + // cleanup + if (midi_program_name) + { + free((void*)midi_program_name); + midi_program_name = nullptr; + } + + if (! standalone.engine) + return nullptr; + + if (! standalone.started) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (midi_program_id < plugin->midiProgramCount()) + { + char strBuf[STR_MAX] = { 0 }; + + plugin->getMidiProgramName(midi_program_id, strBuf); + midi_program_name = strdup(strBuf); + + return midi_program_name; + } + + qCritical("CarlaBackendStandalone::get_midi_program_name(%i, %i) - program_id out of bounds", pluginId, midi_program_id); + return nullptr; + } + + qCritical("CarlaBackendStandalone::get_midi_program_name(%i, %i) - could not find plugin", pluginId, midi_program_id); + return nullptr; +} + +const char* get_real_plugin_name(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_real_plugin_name(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + static const char* real_plugin_name = nullptr; + + // cleanup + if (real_plugin_name) + { + free((void*)real_plugin_name); + real_plugin_name = nullptr; + } + + if (! standalone.engine) + return nullptr; + + if (! standalone.started) + return nullptr; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + char strBuf[STR_MAX] = { 0 }; + + plugin->getRealName(strBuf); + real_plugin_name = strdup(strBuf); + + return real_plugin_name; + } + + qCritical("CarlaBackendStandalone::get_real_plugin_name(%i) - could not find plugin", pluginId); + return nullptr; +} + +// ------------------------------------------------------------------------------------------------------------------- + +int32_t get_current_program_index(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_current_program_index(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return -1; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->currentProgram(); + + qCritical("CarlaBackendStandalone::get_current_program_index(%i) - could not find plugin", pluginId); + return -1; +} + +int32_t get_current_midi_program_index(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::get_current_midi_program_index(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return -1; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->currentMidiProgram(); + + qCritical("CarlaBackendStandalone::get_current_midi_program_index(%i) - could not find plugin", pluginId); + return -1; +} + +// ------------------------------------------------------------------------------------------------------------------- + +double get_default_parameter_value(unsigned short pluginId, uint32_t parameter_id) +{ + qDebug("CarlaBackendStandalone::get_default_parameter_value(%i, %i)", pluginId, parameter_id); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0.0; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + return plugin->parameterRanges(parameter_id)->def; + + qCritical("CarlaBackendStandalone::get_default_parameter_value(%i, %i) - parameter_id out of bounds", pluginId, parameter_id); + return 0.0; + } + + qCritical("CarlaBackendStandalone::get_default_parameter_value(%i, %i) - could not find plugin", pluginId, parameter_id); + return 0.0; +} + +double get_current_parameter_value(unsigned short pluginId, uint32_t parameter_id) +{ + qDebug("CarlaBackendStandalone::get_current_parameter_value(%i, %i)", pluginId, parameter_id); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0.0; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + return plugin->getParameterValue(parameter_id); + + qCritical("CarlaBackendStandalone::get_current_parameter_value(%i, %i) - parameter_id out of bounds", pluginId, parameter_id); + return 0.0; + } + + qCritical("CarlaBackendStandalone::get_current_parameter_value(%i, %i) - could not find plugin", pluginId, parameter_id); + return 0.0; +} + +// ------------------------------------------------------------------------------------------------------------------- + +double get_input_peak_value(unsigned short pluginId, unsigned short port_id) +{ + CARLA_ASSERT(standalone.engine); + CARLA_ASSERT(port_id == 1 || port_id == 2); + + if (! standalone.engine) + return 0.0; + +#if 0 + if (pluginId >= standalone.engine->maxPluginNumber()) + { + qCritical("CarlaBackendStandalone::get_input_peak_value(%i, %i) - invalid plugin value", pluginId, port_id); + return 0.0; + } +#endif + + if (port_id == 1 || port_id == 2) + return standalone.engine->getInputPeak(pluginId, port_id-1); + + qCritical("CarlaBackendStandalone::get_input_peak_value(%i, %i) - invalid port value", pluginId, port_id); + return 0.0; +} + +double get_output_peak_value(unsigned short pluginId, unsigned short port_id) +{ + CARLA_ASSERT(standalone.engine); + CARLA_ASSERT(port_id == 1 || port_id == 2); + + if (! standalone.engine) + return 0.0; + +#if 0 + if (pluginId >= standalone.engine->maxPluginNumber()) + { + qCritical("CarlaBackendStandalone::get_input_peak_value(%i, %i) - invalid plugin value", pluginId, port_id); + return 0.0; + } +#endif + + if (port_id == 1 || port_id == 2) + return standalone.engine->getOutputPeak(pluginId, port_id-1); + + qCritical("CarlaBackendStandalone::get_output_peak_value(%i, %i) - invalid port value", pluginId, port_id); + return 0.0; +} + +// ------------------------------------------------------------------------------------------------------------------- + +void set_active(unsigned short pluginId, bool onOff) +{ + qDebug("CarlaBackendStandalone::set_active(%i, %s)", pluginId, bool2str(onOff)); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->setActive(onOff, true, false); + + qCritical("CarlaBackendStandalone::set_active(%i, %s) - could not find plugin", pluginId, bool2str(onOff)); +} + +void set_drywet(unsigned short pluginId, double value) +{ + qDebug("CarlaBackendStandalone::set_drywet(%i, %g)", pluginId, value); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->setDryWet(value, true, false); + + qCritical("CarlaBackendStandalone::set_drywet(%i, %g) - could not find plugin", pluginId, value); +} + +void set_volume(unsigned short pluginId, double value) +{ + qDebug("CarlaBackendStandalone::set_volume(%i, %g)", pluginId, value); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->setVolume(value, true, false); + + qCritical("CarlaBackendStandalone::set_volume(%i, %g) - could not find plugin", pluginId, value); +} + +void set_balance_left(unsigned short pluginId, double value) +{ + qDebug("CarlaBackendStandalone::set_balance_left(%i, %g)", pluginId, value); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->setBalanceLeft(value, true, false); + + qCritical("CarlaBackendStandalone::set_balance_left(%i, %g) - could not find plugin", pluginId, value); +} + +void set_balance_right(unsigned short pluginId, double value) +{ + qDebug("CarlaBackendStandalone::set_balance_right(%i, %g)", pluginId, value); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->setBalanceRight(value, true, false); + + qCritical("CarlaBackendStandalone::set_balance_right(%i, %g) - could not find plugin", pluginId, value); +} + +// ------------------------------------------------------------------------------------------------------------------- + +void set_parameter_value(unsigned short pluginId, uint32_t parameter_id, double value) +{ + qDebug("CarlaBackendStandalone::set_parameter_value(%i, %i, %g)", pluginId, parameter_id, value); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + return plugin->setParameterValue(parameter_id, value, true, true, false); + + qCritical("CarlaBackendStandalone::set_parameter_value(%i, %i, %g) - parameter_id out of bounds", pluginId, parameter_id, value); + return; + } + + qCritical("CarlaBackendStandalone::set_parameter_value(%i, %i, %g) - could not find plugin", pluginId, parameter_id, value); +} + +void set_parameter_midi_channel(unsigned short pluginId, uint32_t parameter_id, uint8_t channel) +{ + qDebug("CarlaBackendStandalone::set_parameter_midi_channel(%i, %i, %i)", pluginId, parameter_id, channel); + CARLA_ASSERT(standalone.engine); + CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); + + if (channel >= MAX_MIDI_CHANNELS) + { + qCritical("CarlaBackendStandalone::set_parameter_midi_channel(%i, %i, %i) - invalid channel number", pluginId, parameter_id, channel); + return; + } + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + return plugin->setParameterMidiChannel(parameter_id, channel, true, false); + + qCritical("CarlaBackendStandalone::set_parameter_midi_channel(%i, %i, %i) - parameter_id out of bounds", pluginId, parameter_id, channel); + return; + } + + qCritical("CarlaBackendStandalone::set_parameter_midi_channel(%i, %i, %i) - could not find plugin", pluginId, parameter_id, channel); +} + +void set_parameter_midi_cc(unsigned short pluginId, uint32_t parameter_id, int16_t cc) +{ + qDebug("CarlaBackendStandalone::set_parameter_midi_cc(%i, %i, %i)", pluginId, parameter_id, cc); + CARLA_ASSERT(standalone.engine); + CARLA_ASSERT(cc >= -1 && cc <= 0x5F); + + if (cc < -1) + { + cc = -1; + } + else if (cc > 0x5F) // 95 + { + qCritical("CarlaBackendStandalone::set_parameter_midi_cc(%i, %i, %i) - invalid cc number", pluginId, parameter_id, cc); + return; + } + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (parameter_id < plugin->parameterCount()) + return plugin->setParameterMidiCC(parameter_id, cc, true, false); + + qCritical("CarlaBackendStandalone::set_parameter_midi_cc(%i, %i, %i) - parameter_id out of bounds", pluginId, parameter_id, cc); + return; + } + + qCritical("CarlaBackendStandalone::set_parameter_midi_cc(%i, %i, %i) - could not find plugin", pluginId, parameter_id, cc); +} + +void set_program(unsigned short pluginId, uint32_t program_id) +{ + qDebug("CarlaBackendStandalone::set_program(%i, %i)", pluginId, program_id); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (program_id < plugin->programCount()) + return plugin->setProgram(program_id, true, true, false, true); + + qCritical("CarlaBackendStandalone::set_program(%i, %i) - program_id out of bounds", pluginId, program_id); + return; + } + + qCritical("CarlaBackendStandalone::set_program(%i, %i) - could not find plugin", pluginId, program_id); +} + +void set_midi_program(unsigned short pluginId, uint32_t midi_program_id) +{ + qDebug("CarlaBackendStandalone::set_midi_program(%i, %i)", pluginId, midi_program_id); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (midi_program_id < plugin->midiProgramCount()) + return plugin->setMidiProgram(midi_program_id, true, true, false, true); + + qCritical("CarlaBackendStandalone::set_midi_program(%i, %i) - midi_program_id out of bounds", pluginId, midi_program_id); + return; + } + + qCritical("CarlaBackendStandalone::set_midi_program(%i, %i) - could not find plugin", pluginId, midi_program_id); +} + +// ------------------------------------------------------------------------------------------------------------------- + +void set_custom_data(unsigned short pluginId, const char* type, const char* key, const char* value) +{ + qDebug("CarlaBackendStandalone::set_custom_data(%i, \"%s\", \"%s\", \"%s\")", pluginId, type, key, value); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->setCustomData(type, key, value, true); + + qCritical("CarlaBackendStandalone::set_custom_data(%i, \"%s\", \"%s\", \"%s\") - could not find plugin", pluginId, type, key, value); +} + +void set_chunk_data(unsigned short pluginId, const char* chunk_data) +{ + qDebug("CarlaBackendStandalone::set_chunk_data(%i, \"%s\")", pluginId, chunk_data); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + { + if (plugin->hints() & CarlaBackend::PLUGIN_USES_CHUNKS) + return plugin->setChunkData(chunk_data); + + qCritical("CarlaBackendStandalone::set_chunk_data(%i, \"%s\") - plugin does not support chunks", pluginId, chunk_data); + return; + } + + qCritical("CarlaBackendStandalone::set_chunk_data(%i, \"%s\") - could not find plugin", pluginId, chunk_data); +} + +void set_gui_container(unsigned short pluginId, uintptr_t gui_addr) +{ + qDebug("CarlaBackendStandalone::set_gui_container(%i, " P_UINTPTR ")", pluginId, gui_addr); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->setGuiContainer((GuiContainer*)CarlaBackend::getPointerFromAddress(gui_addr)); + + qCritical("CarlaBackendStandalone::set_gui_container(%i, " P_UINTPTR ") - could not find plugin", pluginId, gui_addr); +} + +// ------------------------------------------------------------------------------------------------------------------- + +void show_gui(unsigned short pluginId, bool yesno) +{ + qDebug("CarlaBackendStandalone::show_gui(%i, %s)", pluginId, bool2str(yesno)); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->showGui(yesno); + + qCritical("CarlaBackendStandalone::show_gui(%i, %s) - could not find plugin", pluginId, bool2str(yesno)); +} + +void idle_guis() +{ + CARLA_ASSERT(standalone.engine); + + if (standalone.engine) + standalone.engine->idlePluginGuis(); +} + +// ------------------------------------------------------------------------------------------------------------------- + +void send_midi_note(unsigned short pluginId, uint8_t channel, uint8_t note, uint8_t velocity) +{ + qDebug("CarlaBackendStandalone::send_midi_note(%i, %i, %i, %i)", pluginId, channel, note, velocity); + CARLA_ASSERT(standalone.engine); + + if (! (standalone.engine && standalone.engine->isRunning())) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->sendMidiSingleNote(channel, note, velocity, true, true, false); + + qCritical("CarlaBackendStandalone::send_midi_note(%i, %i, %i, %i) - could not find plugin", pluginId, channel, note, velocity); +} + +void prepare_for_save(unsigned short pluginId) +{ + qDebug("CarlaBackendStandalone::prepare_for_save(%i)", pluginId); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return; + + CarlaBackend::CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId); + + if (plugin) + return plugin->prepareForSave(); + + qCritical("CarlaBackendStandalone::prepare_for_save(%i) - could not find plugin", pluginId); +} + +// ------------------------------------------------------------------------------------------------------------------- + +uint32_t get_buffer_size() +{ + qDebug("CarlaBackendStandalone::get_buffer_size()"); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0; + + return standalone.engine->getBufferSize(); +} + +double get_sample_rate() +{ + qDebug("CarlaBackendStandalone::get_sample_rate()"); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return 0.0; + + return standalone.engine->getSampleRate(); +} + +// ------------------------------------------------------------------------------------------------------------------- + +const char* get_last_error() +{ + qDebug("CarlaBackendStandalone::get_last_error()"); + + if (standalone.engine) + return standalone.engine->getLastError(); + + return standalone.lastError; +} + +const char* get_host_osc_url() +{ + qDebug("CarlaBackendStandalone::get_host_osc_url()"); + CARLA_ASSERT(standalone.engine); + + if (! standalone.engine) + return nullptr; + + return standalone.engine->getOscServerPathTCP(); +} + +// ------------------------------------------------------------------------------------------------------------------- + +void set_callback_function(CarlaBackend::CallbackFunc func) +{ + qDebug("CarlaBackendStandalone::set_callback_function(%p)", func); + + standalone.callback = func; + + if (standalone.engine) + standalone.engine->setCallback(func, nullptr); +} + +void set_option(CarlaBackend::OptionsType option, int value, const char* value_str) +{ + qDebug("CarlaBackendStandalone::set_option(%s, %i, \"%s\")", CarlaBackend::OptionsType2Str(option), value, value_str); + + if (standalone.engine) + standalone.engine->setOption(option, value, value_str); + + switch (option) + { + case CarlaBackend::OPTION_PROCESS_NAME: + standalone.procName = value_str; + break; + + case CarlaBackend::OPTION_PROCESS_MODE: + if (value < CarlaBackend::PROCESS_MODE_SINGLE_CLIENT || value > CarlaBackend::PROCESS_MODE_PATCHBAY) + return qCritical("CarlaBackendStandalone::set_option(%s, %i, \"%s\") - invalid value", OptionsType2Str(option), value, value_str); + + standalone.options.processMode = static_cast(value); + break; + + case CarlaBackend::OPTION_PROCESS_HIGH_PRECISION: + standalone.options.processHighPrecision = value; + break; + + case CarlaBackend::OPTION_MAX_PARAMETERS: + standalone.options.maxParameters = (value > 0) ? value : CarlaBackend::MAX_PARAMETERS; + break; + + case CarlaBackend::OPTION_PREFERRED_BUFFER_SIZE: + standalone.options.preferredBufferSize = value; + break; + + case CarlaBackend::OPTION_PREFERRED_SAMPLE_RATE: + standalone.options.preferredSampleRate = value; + break; + + case CarlaBackend::OPTION_FORCE_STEREO: + standalone.options.forceStereo = value; + break; + + case CarlaBackend::OPTION_USE_DSSI_VST_CHUNKS: + standalone.options.useDssiVstChunks = value; + break; + + case CarlaBackend::OPTION_PREFER_PLUGIN_BRIDGES: + standalone.options.preferPluginBridges = value; + break; + + case CarlaBackend::OPTION_PREFER_UI_BRIDGES: + standalone.options.preferUiBridges = value; + break; + + case CarlaBackend::OPTION_OSC_UI_TIMEOUT: + standalone.options.oscUiTimeout = value; + break; + + case CarlaBackend::OPTION_PATH_BRIDGE_POSIX32: + standalone.options.bridge_posix32 = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_POSIX64: + standalone.options.bridge_posix64 = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_WIN32: + standalone.options.bridge_win32 = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_WIN64: + standalone.options.bridge_win64 = value_str; + break; + + case CarlaBackend::OPTION_PATH_BRIDGE_LV2_GTK2: + standalone.options.bridge_lv2gtk2 = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_LV2_GTK3: + standalone.options.bridge_lv2gtk3 = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_LV2_QT4: + standalone.options.bridge_lv2qt4 = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_LV2_QT5: + standalone.options.bridge_lv2qt5 = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_LV2_COCOA: + standalone.options.bridge_lv2cocoa = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_LV2_WINDOWS: + standalone.options.bridge_lv2win = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_LV2_X11: + standalone.options.bridge_lv2x11 = value_str; + break; + + case CarlaBackend::OPTION_PATH_BRIDGE_VST_COCOA: + standalone.options.bridge_vstcocoa = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_VST_HWND: + standalone.options.bridge_vsthwnd = value_str; + break; + case CarlaBackend::OPTION_PATH_BRIDGE_VST_X11: + standalone.options.bridge_vstx11 = value_str; + break; + } +} + +// ------------------------------------------------------------------------------------------------------------------- + +#define NSM_API_VERSION_MAJOR 1 +#define NSM_API_VERSION_MINOR 0 + +class CarlaNSM +{ +public: + CarlaNSM() + { + m_controlAddr = nullptr; + m_serverThread = nullptr; + m_isOpened = false; + m_isSaved = false; + } + + ~CarlaNSM() + { + if (m_controlAddr) + lo_address_free(m_controlAddr); + + if (m_serverThread) + { + lo_server_thread_stop(m_serverThread); + lo_server_thread_del_method(m_serverThread, "/reply", "ssss"); + lo_server_thread_del_method(m_serverThread, "/nsm/client/open", "sss"); + lo_server_thread_del_method(m_serverThread, "/nsm/client/save", ""); + lo_server_thread_free(m_serverThread); + } + } + + void announce(const char* const url, const int pid) + { + lo_address addr = lo_address_new_from_url(url); + int proto = lo_address_get_protocol(addr); + + if (! m_serverThread) + { + // create new OSC thread + m_serverThread = lo_server_thread_new_with_proto(nullptr, proto, error_handler); + + // register message handlers and start OSC thread + lo_server_thread_add_method(m_serverThread, "/reply", "ssss", _reply_handler, this); + lo_server_thread_add_method(m_serverThread, "/nsm/client/open", "sss", _nsm_open_handler, this); + lo_server_thread_add_method(m_serverThread, "/nsm/client/save", "", _nsm_save_handler, this); + lo_server_thread_start(m_serverThread); + } + + lo_send_from(addr, lo_server_thread_get_server(m_serverThread), LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii", + "Carla", ":switch:", "carla", NSM_API_VERSION_MAJOR, NSM_API_VERSION_MINOR, pid); + + lo_address_free(addr); + } + + void replyOpen() + { + m_isOpened = true; + } + + void replySave() + { + m_isSaved = true; + } + +protected: + int reply_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg) + { + qDebug("CarlaNSM::reply_handler(%s, %i, %p, %s, %p)", path, argc, argv, types, msg); + + m_controlAddr = lo_address_new_from_url(lo_address_get_url(lo_message_get_source(msg))); + + const char* const method = &argv[0]->s; + + if (strcmp(method, "/nsm/server/announce") == 0 && standalone.callback) + standalone.callback(nullptr, CarlaBackend::CALLBACK_NSM_ANNOUNCE, 0, 0, 0, 0.0, nullptr); // FIXME? + + return 0; + } + + int nsm_open_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg) + { + qDebug("CarlaNSM::nsm_open_handler(\"%s\", \"%s\", %p, %i, %p)", path, types, argv, argc, msg); + + if (! standalone.callback) + return 1; + + const char* const projectPath = &argv[0]->s; + const char* const clientId = &argv[2]->s; + + standalone.callback(nullptr, CarlaBackend::CALLBACK_NSM_OPEN1, 0, 0, 0, 0.0, clientId); + standalone.callback(nullptr, CarlaBackend::CALLBACK_NSM_OPEN2, 0, 0, 0, 0.0, projectPath); + + for (int i=0; i < 30 && ! m_isOpened; i++) + carla_msleep(100); + + if (m_controlAddr) + lo_send_from(m_controlAddr, lo_server_thread_get_server(m_serverThread), LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/open", "OK"); + + return 0; + } + + int nsm_save_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg) + { + qDebug("CarlaNSM::nsm_save_handler(\"%s\", \"%s\", %p, %i, %p)", path, types, argv, argc, msg); + + if (! standalone.callback) + return 1; + + standalone.callback(nullptr, CarlaBackend::CALLBACK_NSM_SAVE, 0, 0, 0, 0.0, nullptr); + + for (int i=0; i < 30 && ! m_isSaved; i++) + carla_msleep(100); + + if (m_controlAddr) + lo_send_from(m_controlAddr, lo_server_thread_get_server(m_serverThread), LO_TT_IMMEDIATE, "/reply", "ss", "/nsm/client/save", "OK"); + + return 0; + } + +private: + lo_address m_controlAddr; + lo_server_thread m_serverThread; + bool m_isOpened, m_isSaved; + + static int _reply_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg, void* const data) + { + CARLA_ASSERT(data); + CarlaNSM* const _this_ = (CarlaNSM*)data; + return _this_->reply_handler(path, types, argv, argc, msg); + } + + static int _nsm_open_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg, void* const data) + { + CARLA_ASSERT(data); + CarlaNSM* const _this_ = (CarlaNSM*)data; + return _this_->nsm_open_handler(path, types, argv, argc, msg); + } + + static int _nsm_save_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg, void* const data) + { + CARLA_ASSERT(data); + CarlaNSM* const _this_ = (CarlaNSM*)data; + return _this_->nsm_save_handler(path, types, argv, argc, msg); + } + + static void error_handler(const int num, const char* const msg, const char* const path) + { + qCritical("CarlaNSM::error_handler(%i, \"%s\", \"%s\")", num, msg, path); + } +}; + +static CarlaNSM carlaNSM; + +void nsm_announce(const char* url, int pid) +{ + carlaNSM.announce(url, pid); +} + +void nsm_reply_open() +{ + carlaNSM.replyOpen(); +} + +void nsm_reply_save() +{ + carlaNSM.replySave(); +} + +#endif + +// ------------------------------------------------------------------------------------------------------------------- + +#if 0 +//def QTCREATOR_TEST + +#include +#include + +QDialog* vstGui = nullptr; + +void main_callback(void* ptr, CarlaBackend::CallbackType action, unsigned short pluginId, int value1, int value2, double value3) +{ + switch (action) + { + case CarlaBackend::CALLBACK_SHOW_GUI: + if (vstGui && ! value1) + vstGui->close(); + break; + case CarlaBackend::CALLBACK_RESIZE_GUI: + vstGui->setFixedSize(value1, value2); + break; + default: + break; + } + + Q_UNUSED(ptr); + Q_UNUSED(pluginId); + Q_UNUSED(value3); +} + +void run_tests_standalone(short idMax) +{ + for (short id = 0; id <= idMax; id++) + { + qDebug("------------------- TEST @%i: non-parameter calls --------------------", id); + get_plugin_info(id); + get_audio_port_count_info(id); + get_midi_port_count_info(id); + get_parameter_count_info(id); + get_gui_info(id); + get_chunk_data(id); + get_parameter_count(id); + get_program_count(id); + get_midi_program_count(id); + get_custom_data_count(id); + get_real_plugin_name(id); + get_current_program_index(id); + get_current_midi_program_index(id); + + qDebug("------------------- TEST @%i: parameter calls [-1] --------------------", id); + get_parameter_info(id, -1); + get_parameter_scalepoint_info(id, -1, -1); + get_parameter_data(id, -1); + get_parameter_ranges(id, -1); + get_midi_program_data(id, -1); + get_custom_data(id, -1); + get_parameter_text(id, -1); + get_program_name(id, -1); + get_midi_program_name(id, -1); + get_default_parameter_value(id, -1); + get_current_parameter_value(id, -1); + get_input_peak_value(id, -1); + get_output_peak_value(id, -1); + + qDebug("------------------- TEST @%i: parameter calls [0] --------------------", id); + get_parameter_info(id, 0); + get_parameter_scalepoint_info(id, 0, -1); + get_parameter_scalepoint_info(id, 0, 0); + get_parameter_data(id, 0); + get_parameter_ranges(id, 0); + get_midi_program_data(id, 0); + get_custom_data(id, 0); + get_parameter_text(id, 0); + get_program_name(id, 0); + get_midi_program_name(id, 0); + get_default_parameter_value(id, 0); + get_current_parameter_value(id, 0); + get_input_peak_value(id, 0); + get_input_peak_value(id, 1); + get_input_peak_value(id, 2); + get_output_peak_value(id, 0); + get_output_peak_value(id, 1); + get_output_peak_value(id, 2); + + qDebug("------------------- TEST @%i: set extra data --------------------", id); + set_custom_data(id, CarlaBackend::CUSTOM_DATA_STRING, "", ""); + set_chunk_data(id, nullptr); + set_gui_container(id, (uintptr_t)1); + + qDebug("------------------- TEST @%i: gui stuff --------------------", id); + show_gui(id, false); + show_gui(id, true); + show_gui(id, true); + + idle_guis(); + idle_guis(); + idle_guis(); + + qDebug("------------------- TEST @%i: other --------------------", id); + send_midi_note(id, 15, 127, 127); + send_midi_note(id, 0, 0, 0); + + prepare_for_save(id); + prepare_for_save(id); + prepare_for_save(id); + } +} + +int main(int argc, char* argv[]) +{ + using namespace CarlaBackend; + + // Qt app + QApplication app(argc, argv); + + // Qt gui (for vst) + vstGui = new QDialog(nullptr); + + // set callback and options + set_callback_function(main_callback); + set_option(OPTION_PREFER_UI_BRIDGES, 0, nullptr); + //set_option(OPTION_PROCESS_MODE, PROCESS_MODE_CONTINUOUS_RACK, nullptr); + + // start engine + if (! engine_init("JACK", "carla_demo")) + { + qCritical("failed to start backend engine, reason:\n%s", get_last_error()); + delete vstGui; + return 1; + } + + short id_ladspa = add_plugin(BINARY_NATIVE, PLUGIN_LADSPA, "/usr/lib/ladspa/LEET_eqbw2x2.so", "LADSPA plug name, test long name - " + "------- name ------------ name2 ----------- name3 ------------ name4 ------------ name5 ---------- name6", "leet_equalizer_bw2x2", nullptr); + + short id_dssi = add_plugin(BINARY_NATIVE, PLUGIN_DSSI, "/usr/lib/dssi/fluidsynth-dssi.so", "DSSI pname, short-utf8 _ \xAE", "FluidSynth-DSSI", (void*)"/usr/lib/dssi/fluidsynth-dssi/FluidSynth-DSSI_gtk"); + short id_native = add_plugin(BINARY_NATIVE, PLUGIN_INTERNAL, "", "ZynHere", "zynaddsubfx", nullptr); + + //short id_lv2 = add_plugin(BINARY_NATIVE, PLUGIN_LV2, "FILENAME", "HAHA name!!!", "http://studionumbersix.com/foo/lv2/yc20", nullptr); + + //short id_vst = add_plugin(BINARY_NATIVE, PLUGIN_LV2, "FILENAME", "HAHA name!!!", "http://studionumbersix.com/foo/lv2/yc20", nullptr); + + if (id_ladspa < 0 || id_dssi < 0 || id_native < 0) + { + qCritical("failed to start load plugins, reason:\n%s", get_last_error()); + delete vstGui; + return 1; + } + + //const GuiInfo* const guiInfo = get_gui_info(id); + //if (guiInfo->type == CarlaBackend::GUI_INTERNAL_QT4 || guiInfo->type == CarlaBackend::GUI_INTERNAL_X11) + //{ + // set_gui_data(id, 0, (uintptr_t)gui); + //gui->show(); + //} + + // activate + set_active(id_ladspa, true); + set_active(id_dssi, true); + set_active(id_native, true); + + // start guis + show_gui(id_dssi, true); + carla_sleep(1); + + // do tests + run_tests_standalone(id_dssi+1); + + // lock + app.exec(); + + delete vstGui; + vstGui = nullptr; + + remove_plugin(id_ladspa); + remove_plugin(id_dssi); + remove_plugin(id_native); + engine_close(); + + return 0; +} + +#endif diff --git a/source/utils/carla_utils.hpp b/source/utils/carla_utils.hpp index c669c547e..f14b4cea7 100644 --- a/source/utils/carla_utils.hpp +++ b/source/utils/carla_utils.hpp @@ -494,7 +494,7 @@ public: for (size_t i=0; i < bufferLen; i++) { if (buffer[i] >= 'A' && buffer[i] <= 'Z') - buffer[i] += charDiff; + buffer[i] = char(buffer[i] + charDiff); } } @@ -505,7 +505,7 @@ public: for (size_t i=0; i < bufferLen; i++) { if (buffer[i] >= 'a' && buffer[i] <= 'z') - buffer[i] -= charDiff; + buffer[i] = char(buffer[i] + charDiff); } }