@@ -165,7 +165,7 @@ carla_backend: carla_lilv | |||
$(MAKE) -C src/carla-backend | |||
carla_bridge: carla_lilv | |||
# $(MAKE) -C src/carla-bridge | |||
$(MAKE) -C src/carla-bridge | |||
carla_discovery: | |||
$(MAKE) -C src/carla-discovery unix$(_arch_n) NATIVE=1 | |||
@@ -21,7 +21,7 @@ CARLA_C_FLAGS = $(BASE_FLAGS) $(CFLAGS) | |||
CARLA_CXX_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS) | |||
CARLA_CXX_FLAGS += $(shell pkg-config --cflags liblo QtCore QtGui) | |||
CARLA_CXX_FLAGS += -DNDEBUG -DQT_NO_DEBUG -DQT_NO_DEBUG_STREAM -DQT_NO_DEBUG_OUTPUT | |||
CARLA_CXX_FLAGS += -DVESTIGE_HEADER -I../carla-includes/vestige # Comment this line to not use vestige header | |||
CARLA_CXX_FLAGS += -DVESTIGE_HEADER # Comment this line to not use vestige header | |||
CARLA_LD_FLAGS = -shared -ldl -lm -fPIC $(LDFLAGS) | |||
CARLA_LD_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui) | |||
@@ -21,7 +21,7 @@ CARLA_C_FLAGS = $(BASE_FLAGS) $(CFLAGS) | |||
CARLA_CXX_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS) | |||
CARLA_CXX_FLAGS += $(shell pkg-config --cflags liblo QtCore QtGui) | |||
CARLA_CXX_FLAGS += -DDEBUG | |||
CARLA_CXX_FLAGS += -DVESTIGE_HEADER -I../carla-includes/vestige # Comment this line to not use vestige header | |||
CARLA_CXX_FLAGS += -DVESTIGE_HEADER # Comment this line to not use vestige header | |||
CARLA_LD_FLAGS = -shared -ldl -lm -fPIC $(LDFLAGS) | |||
CARLA_LD_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui) | |||
@@ -543,34 +543,3 @@ int CarlaOsc::handle_bridge_aouts_peak(CARLA_OSC_HANDLE_ARGS2) | |||
return 0; | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
void osc_send_lv2_atom_transfer(const CarlaOscData* const oscData /* TODO */) | |||
{ | |||
qDebug("osc_send_lv2_atom_transfer(%s)", oscData->path); | |||
if (oscData->target) | |||
{ | |||
char targetPath[strlen(oscData->path)+19]; | |||
strcpy(targetPath, oscData->path); | |||
strcat(targetPath, "/lv2_atom_transfer"); | |||
lo_send(oscData->target, targetPath, ""); | |||
} | |||
} | |||
void osc_send_lv2_event_transfer(const CarlaOscData* const oscData, const char* const type, const char* const key, const char* const value) | |||
{ | |||
qDebug("osc_send_lv2_event_transfer(%s, %s, %s, %s)", oscData->path, type, key, value); | |||
assert(type); | |||
assert(key); | |||
assert(value); | |||
if (oscData->target) | |||
{ | |||
char targetPath[strlen(oscData->path)+20]; | |||
strcpy(targetPath, oscData->path); | |||
strcat(targetPath, "/lv2_event_transfer"); | |||
lo_send(oscData->target, targetPath, "sss", type, key, value); | |||
} | |||
} |
@@ -74,12 +74,12 @@ public: | |||
} | |||
private: | |||
CarlaBackend::CarlaEngine* const engine; | |||
const char* m_serverPath; | |||
lo_server_thread m_serverThread; | |||
CarlaOscData m_controllerData; | |||
CarlaBackend::CarlaEngine* const engine; | |||
const char* m_name; | |||
size_t m_name_len; | |||
@@ -126,9 +126,4 @@ private: | |||
int handle_bridge_aouts_peak(CARLA_OSC_HANDLE_ARGS2); | |||
}; | |||
// ----------------------------------------------------------------------- | |||
void osc_send_lv2_atom_transfer(const CarlaOscData* const oscData /* TODO */); | |||
void osc_send_lv2_event_transfer(const CarlaOscData* const oscData, const char* const type, const char* const key, const char* const value); | |||
#endif // CARLA_OSC_H |
@@ -1468,10 +1468,10 @@ public: | |||
for (size_t i=0; i < custom.size(); i++) | |||
{ | |||
//if (m_type == PLUGIN_LV2) | |||
// osc_send_lv2_event_transfer(&osc.data, customdatatype2str(custom[i].type), custom[i].key, custom[i].value); | |||
//else if (custom[i].type == CUSTOM_DATA_STRING) | |||
osc_send_configure(&osc.data, custom[i].key, custom[i].value); | |||
if (m_type == PLUGIN_LV2) | |||
osc_send_lv2_event_transfer(&osc.data, getCustomDataTypeString(custom[i].type), custom[i].key, custom[i].value); | |||
else if (custom[i].type == CUSTOM_DATA_STRING) | |||
osc_send_configure(&osc.data, custom[i].key, custom[i].value); | |||
// FIXME | |||
} | |||
@@ -891,9 +891,9 @@ public: | |||
} | |||
else | |||
{ | |||
//osc_send_hide(&osc.data); | |||
//osc_send_quit(&osc.data); | |||
//osc_clear_data(&osc.data); | |||
osc_send_hide(&osc.data); | |||
osc_send_quit(&osc.data); | |||
osc_clear_data(&osc.data); | |||
} | |||
break; | |||
#endif | |||
@@ -2481,19 +2481,19 @@ public: | |||
// do basic checks | |||
if (! uriKey) | |||
{ | |||
qWarning("Lv2Plugin::carla_lv2_state_store(%p, %i, %p, " P_SIZE ", %i, %i) - Invalid key", handle, key, value, size, type, flags); | |||
qWarning("Lv2Plugin::handleStateStore(%i, %p, " P_SIZE ", %i, %i) - Invalid key", key, value, size, type, flags); | |||
return LV2_STATE_ERR_NO_PROPERTY; | |||
} | |||
if (! flags & LV2_STATE_IS_POD) | |||
{ | |||
qWarning("Lv2Plugin::carla_lv2_state_store(%p, %i, %p, " P_SIZE ", %i, %i) - Invalid flags", handle, key, value, size, type, flags); | |||
qWarning("Lv2Plugin::handleStateStore(%i, %p, " P_SIZE ", %i, %i) - Invalid flags", key, value, size, type, flags); | |||
return LV2_STATE_ERR_BAD_FLAGS; | |||
} | |||
if (dtype == CUSTOM_DATA_INVALID) | |||
{ | |||
qCritical("Lv2Plugin::carla_lv2_state_store(%p, %i, %p, " P_SIZE ", %i, %i) - Invalid type '%s'", handle, key, value, size, type, flags, CustomDataType2str(dtype)); | |||
qCritical("Lv2Plugin::handleStateStore(%i, %p, " P_SIZE ", %i, %i) - Invalid type '%s'", key, value, size, type, flags, CustomDataType2str(dtype)); | |||
return LV2_STATE_ERR_BAD_TYPE; | |||
} | |||
@@ -2536,7 +2536,7 @@ public: | |||
if (! uriKey) | |||
{ | |||
qCritical("Lv2Plugin::carla_lv2_state_retrieve(%p, %i, %p, %p, %p) - Failed to find key", handle, key, size, type, flags); | |||
qCritical("Lv2Plugin::handleStateRetrieve(%i, %p, %p, %p) - Failed to find key", key, size, type, flags); | |||
return nullptr; | |||
} | |||
@@ -2555,7 +2555,7 @@ public: | |||
if (! stringData) | |||
{ | |||
qCritical("Lv2Plugin::carla_lv2_state_retrieve(%p, %i, %p, %p, %p) - Invalid key '%s'", handle, key, size, type, flags, uriKey); | |||
qCritical("Lv2Plugin::handleStateRetrieve(%i, %p, %p, %p) - Invalid key '%s'", key, size, type, flags, uriKey); | |||
return nullptr; | |||
} | |||
@@ -2587,7 +2587,7 @@ public: | |||
return chunk.constData(); | |||
} | |||
qCritical("Lv2Plugin::carla_lv2_state_retrieve(%p, %i, %p, %p, %p) - Invalid key type '%s'", handle, key, size, type, flags, CustomDataType2str(dtype)); | |||
qCritical("Lv2Plugin::handleStateRetrieve(%i, %p, %p, %p) - Invalid key type '%s'", key, size, type, flags, CustomDataType2str(dtype)); | |||
return nullptr; | |||
} | |||
@@ -3518,7 +3518,7 @@ public: | |||
// ------------------------------------------------------- | |||
// initialize ui bridge | |||
const char* const oscBinary = "/home/falktx/Personal/FOSS/GIT/Cadence/src/carla-bridge/carla-bridge-lv2-gtk2"; //lv2bridge2str(UiType); | |||
const char* const oscBinary = lv2bridge2str(UiType); | |||
qDebug("Has UI - is bridge, uitype = %i : %s", UiType, oscBinary); | |||
if (oscBinary) | |||
@@ -9,10 +9,12 @@ CXX ?= g++ | |||
WINECC ?= winegcc | |||
WINECXX ?= wineg++ | |||
BUILD_CFLAGS = -O2 -ffast-math -fomit-frame-pointer -mtune=generic -msse -std=c99 -Wall -I. -I../carla-backend -I../carla-includes $(CFLAGS) | |||
BASE_FLAGS = -O2 -ffast-math -fomit-frame-pointer -fPIC -mtune=generic -msse -Wall | |||
BUILD_FLAGS = -O2 -ffast-math -fomit-frame-pointer -mtune=generic -msse -std=c++0x -Wall $(CXXFLAGS) | |||
BUILD_FLAGS += -I. -I../carla-backend -I../carla-includes $(shell pkg-config --cflags liblo QtCore) | |||
BUILD_CFLAGS = $(BASE_FLAGS) -std=c99 $(CFLAGS) | |||
BUILD_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS) | |||
BUILD_FLAGS += -I. -I../carla-includes $(shell pkg-config --cflags liblo QtCore) | |||
BUILD_FLAGS += -DBUILD_BRIDGE -DNDEBUG -DQT_NO_DEBUG -DQT_NO_DEBUG_STREAM -DQT_NO_DEBUG_OUTPUT | |||
BUILD_FLAGS += -DVESTIGE_HEADER -I../carla-includes/vestige # Comment this line to not use vestige header | |||
@@ -77,7 +79,7 @@ wine64: carla-bridge-win64.exe.so | |||
# -------------------------------------------------------------- | |||
# ui_lv2-gtk2 | |||
OBJS_UI_LV2_GTK2 = carla_bridge_ui-lv2__lv2-gtk2.o carla_bridge_ui-gtk2__lv2-gtk2.o carla_bridge_osc__lv2-gtk2.o ../carla-lilv/carla_lilv.a | |||
OBJS_UI_LV2_GTK2 = carla_bridge_ui-lv2__lv2-gtk2.o carla_bridge_toolkit-gtk2__lv2-gtk2.o carla_bridge_osc__lv2-gtk2.o ../carla-lilv/carla_lilv.a | |||
carla-bridge-lv2-gtk2: $(OBJS_UI_LV2_GTK2) | |||
$(CXX) $^ $(LINK_UI_LV2_GTK2_FLAGS) -o $@ && strip $@ | |||
@@ -85,7 +87,7 @@ carla-bridge-lv2-gtk2: $(OBJS_UI_LV2_GTK2) | |||
carla_bridge_ui-lv2__lv2-gtk2.o: carla_bridge_ui-lv2.cpp | |||
$(CXX) $< $(BUILD_UI_LV2_GTK2_FLAGS) -c -o $@ | |||
carla_bridge_ui-gtk2__lv2-gtk2.o: carla_bridge_ui-gtk2.cpp | |||
carla_bridge_toolkit-gtk2__lv2-gtk2.o: carla_bridge_toolkit-gtk2.cpp | |||
$(CXX) $< $(BUILD_UI_LV2_GTK2_FLAGS) -c -o $@ | |||
carla_bridge_osc__lv2-gtk2.o: carla_bridge_osc.cpp | |||
@@ -94,7 +96,7 @@ carla_bridge_osc__lv2-gtk2.o: carla_bridge_osc.cpp | |||
# -------------------------------------------------------------- | |||
# ui_lv2-qt4 | |||
OBJS_UI_LV2_QT4 = carla_bridge_ui-lv2__lv2-qt4.o carla_bridge_ui-qt4__lv2-qt4.o carla_bridge_osc__lv2-qt4.o ../carla-lilv/carla_lilv.a | |||
OBJS_UI_LV2_QT4 = carla_bridge_ui-lv2__lv2-qt4.o carla_bridge_toolkit-qt4__lv2-qt4.o carla_bridge_osc__lv2-qt4.o ../carla-lilv/carla_lilv.a | |||
carla-bridge-lv2-qt4: $(OBJS_UI_LV2_QT4) | |||
$(CXX) $^ $(LINK_UI_LV2_QT4_FLAGS) -o $@ && strip $@ | |||
@@ -102,7 +104,7 @@ carla-bridge-lv2-qt4: $(OBJS_UI_LV2_QT4) | |||
carla_bridge_ui-lv2__lv2-qt4.o: carla_bridge_ui-lv2.cpp | |||
$(CXX) $< $(BUILD_UI_LV2_QT4_FLAGS) -c -o $@ | |||
carla_bridge_ui-qt4__lv2-qt4.o: carla_bridge_ui-qt4.cpp | |||
carla_bridge_toolkit-qt4__lv2-qt4.o: carla_bridge_toolkit-qt4.cpp | |||
$(CXX) $< $(BUILD_UI_LV2_QT4_FLAGS) -c -o $@ | |||
carla_bridge_osc__lv2-qt4.o: carla_bridge_osc.cpp | |||
@@ -111,7 +113,7 @@ carla_bridge_osc__lv2-qt4.o: carla_bridge_osc.cpp | |||
# -------------------------------------------------------------- | |||
# ui_lv2-x11 | |||
OBJS_UI_LV2_X11 = carla_bridge_ui-lv2__lv2-x11.o carla_bridge_ui-qt4__lv2-x11.o carla_bridge_osc__lv2-x11.o ../carla-lilv/carla_lilv.a | |||
OBJS_UI_LV2_X11 = carla_bridge_ui-lv2__lv2-x11.o carla_bridge_toolkit-qt4__lv2-x11.o carla_bridge_osc__lv2-x11.o ../carla-lilv/carla_lilv.a | |||
carla-bridge-lv2-x11: $(OBJS_UI_LV2_X11) | |||
$(CXX) $^ $(LINK_UI_LV2_X11_FLAGS) -o $@ && strip $@ | |||
@@ -119,7 +121,7 @@ carla-bridge-lv2-x11: $(OBJS_UI_LV2_X11) | |||
carla_bridge_ui-lv2__lv2-x11.o: carla_bridge_ui-lv2.cpp | |||
$(CXX) $< $(BUILD_UI_LV2_X11_FLAGS) -c -o $@ | |||
carla_bridge_ui-qt4__lv2-x11.o: carla_bridge_ui-qt4.cpp | |||
carla_bridge_toolkit-qt4__lv2-x11.o: carla_bridge_toolkit-qt4.cpp | |||
$(CXX) $< $(BUILD_UI_LV2_X11_FLAGS) -c -o $@ | |||
carla_bridge_osc__lv2-x11.o: carla_bridge_osc.cpp | |||
@@ -128,7 +130,7 @@ carla_bridge_osc__lv2-x11.o: carla_bridge_osc.cpp | |||
# -------------------------------------------------------------- | |||
# ui_vst-x11 | |||
OBJS_UI_VST_X11 = carla_bridge_ui-vst__vst-x11.o carla_bridge_ui-qt4__vst-x11.o carla_bridge_osc__vst-x11.o | |||
OBJS_UI_VST_X11 = carla_bridge_ui-vst__vst-x11.o carla_bridge_toolkit-qt4__vst-x11.o carla_bridge_osc__vst-x11.o | |||
carla-bridge-vst-x11: $(OBJS_UI_VST_X11) | |||
$(CXX) $^ $(LINK_UI_VST_X11_FLAGS) -o $@ && strip $@ | |||
@@ -136,7 +138,7 @@ carla-bridge-vst-x11: $(OBJS_UI_VST_X11) | |||
carla_bridge_ui-vst__vst-x11.o: carla_bridge_ui-vst.cpp | |||
$(CXX) $< $(BUILD_UI_VST_X11_FLAGS) -c -o $@ | |||
carla_bridge_ui-qt4__vst-x11.o: carla_bridge_ui-qt4.cpp | |||
carla_bridge_toolkit-qt4__vst-x11.o: carla_bridge_toolkit-qt4.cpp | |||
$(CXX) $< $(BUILD_UI_VST_X11_FLAGS) -c -o $@ | |||
carla_bridge_osc__vst-x11.o: carla_bridge_osc.cpp | |||
@@ -20,231 +20,51 @@ | |||
#include "carla_includes.h" | |||
#ifdef BUILD_BRIDGE_UI | |||
#include "carla_lib_includes.h" | |||
#endif | |||
#define CARLA_BRIDGE_START_NAMESPACE namespace CarlaBridge { | |||
#define CARLA_BRIDGE_END_NAMESPACE } | |||
#include <cstdio> | |||
#include <cstdint> | |||
#include <cstdlib> | |||
#include <cstring> | |||
#include <QtCore/QMutex> | |||
CARLA_BRIDGE_START_NAMESPACE | |||
void toolkit_init(); | |||
void toolkit_loop(); | |||
void toolkit_quit(); | |||
void toolkit_window_show(); | |||
void toolkit_window_hide(); | |||
void toolkit_window_resize(int width, int height); | |||
// ------------------------------------------------------------------------- | |||
#define MAX_BRIDGE_MESSAGES 256 | |||
/*! | |||
* @defgroup CarlaBridgeAPI Carla Bridge API | |||
* | |||
* The Carla Bridge API | |||
* @{ | |||
*/ | |||
enum BridgeMessageType { | |||
BRIDGE_MESSAGE_NULL = 0, | |||
BRIDGE_MESSAGE_PARAMETER = 1, // index, 0, value | |||
BRIDGE_MESSAGE_PROGRAM = 2, // index, 0, 0 | |||
BRIDGE_MESSAGE_MIDI_PROGRAM = 3, // bank, program, 0 | |||
BRIDGE_MESSAGE_NOTE_ON = 4, // note, velocity, 0 | |||
BRIDGE_MESSAGE_NOTE_OFF = 5, // note, 0, 0 | |||
BRIDGE_MESSAGE_SHOW_GUI = 6, // show, 0, 0 | |||
BRIDGE_MESSAGE_RESIZE_GUI = 7, // width, height, 0 | |||
BRIDGE_MESSAGE_SAVE_NOW = 8, | |||
BRIDGE_MESSAGE_QUIT = 9 | |||
#define MAX_BRIDGE_MESSAGES 256 //!< Maximum number of messages per client | |||
enum MessageType { | |||
MESSAGE_NULL = 0, | |||
MESSAGE_PARAMETER = 1, // index, 0, value | |||
MESSAGE_PROGRAM = 2, // index, 0, 0 | |||
MESSAGE_MIDI_PROGRAM = 3, // bank, program, 0 | |||
MESSAGE_NOTE_ON = 4, // note, velocity, 0 | |||
MESSAGE_NOTE_OFF = 5, // note, 0, 0 | |||
MESSAGE_SHOW_GUI = 6, // show, 0, 0 | |||
MESSAGE_RESIZE_GUI = 7, // width, height, 0 | |||
MESSAGE_SAVE_NOW = 8, | |||
MESSAGE_QUIT = 9 | |||
}; | |||
struct QuequeBridgeMessage { | |||
BridgeMessageType type; | |||
struct Message { | |||
MessageType type; | |||
int value1; | |||
int value2; | |||
double value3; | |||
}; | |||
// ------------------------------------------------------------------------- | |||
class ClientData | |||
{ | |||
public: | |||
ClientData(const char* ui_title) | |||
{ | |||
m_title = strdup(ui_title); | |||
for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | |||
{ | |||
QuequeBridgeMessages[i].type = BRIDGE_MESSAGE_NULL; | |||
QuequeBridgeMessages[i].value1 = 0; | |||
QuequeBridgeMessages[i].value2 = 0; | |||
QuequeBridgeMessages[i].value3 = 0.0; | |||
} | |||
#ifdef BUILD_BRIDGE_UI | |||
m_filename = nullptr; | |||
m_lib = nullptr; | |||
#endif | |||
} | |||
virtual ~ClientData() | |||
{ | |||
free(m_title); | |||
#ifdef BUILD_BRIDGE_UI | |||
if (m_filename) | |||
free(m_filename); | |||
#endif | |||
} | |||
void queque_message(BridgeMessageType type, int value1, int value2, double value3) | |||
{ | |||
m_lock.lock(); | |||
for (unsigned int i=0; i<MAX_BRIDGE_MESSAGES; i++) | |||
{ | |||
if (QuequeBridgeMessages[i].type == BRIDGE_MESSAGE_NULL) | |||
{ | |||
QuequeBridgeMessages[i].type = type; | |||
QuequeBridgeMessages[i].value1 = value1; | |||
QuequeBridgeMessages[i].value2 = value2; | |||
QuequeBridgeMessages[i].value3 = value3; | |||
break; | |||
} | |||
} | |||
m_lock.unlock(); | |||
} | |||
bool run_messages() | |||
{ | |||
m_lock.lock(); | |||
for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | |||
{ | |||
if (QuequeBridgeMessages[i].type != BRIDGE_MESSAGE_NULL) | |||
{ | |||
const QuequeBridgeMessage* const m = &QuequeBridgeMessages[i]; | |||
switch (m->type) | |||
{ | |||
case BRIDGE_MESSAGE_PARAMETER: | |||
set_parameter(m->value1, m->value3); | |||
break; | |||
case BRIDGE_MESSAGE_PROGRAM: | |||
set_program(m->value1); | |||
break; | |||
case BRIDGE_MESSAGE_MIDI_PROGRAM: | |||
set_midi_program(m->value1, m->value2); | |||
break; | |||
case BRIDGE_MESSAGE_NOTE_ON: | |||
note_on(m->value1, m->value2); | |||
break; | |||
case BRIDGE_MESSAGE_NOTE_OFF: | |||
note_off(m->value1); | |||
break; | |||
case BRIDGE_MESSAGE_SHOW_GUI: | |||
if (m->value1) | |||
toolkit_window_show(); | |||
else | |||
toolkit_window_hide(); | |||
break; | |||
case BRIDGE_MESSAGE_RESIZE_GUI: | |||
toolkit_window_resize(m->value1, m->value2); | |||
break; | |||
case BRIDGE_MESSAGE_SAVE_NOW: | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
save_now(); | |||
#endif | |||
break; | |||
case BRIDGE_MESSAGE_QUIT: | |||
toolkit_quit(); | |||
m_lock.unlock(); | |||
return false; | |||
default: | |||
break; | |||
} | |||
QuequeBridgeMessages[i].type = BRIDGE_MESSAGE_NULL; | |||
} | |||
else | |||
break; | |||
} | |||
m_lock.unlock(); | |||
return true; | |||
} | |||
const char* get_title() const | |||
{ | |||
return m_title; | |||
} | |||
// --------------------------------------------------------------------- | |||
#ifdef BUILD_BRIDGE_UI | |||
// initialization | |||
virtual bool init(const char*, const char*) = 0; | |||
virtual void close() = 0; | |||
#endif | |||
// processing | |||
virtual void set_parameter(int32_t rindex, double value) = 0; | |||
virtual void set_program(uint32_t index) = 0; | |||
virtual void set_midi_program(uint32_t bank, uint32_t program) = 0; | |||
virtual void note_on(uint8_t note, uint8_t velocity) = 0; | |||
virtual void note_off(uint8_t note) = 0; | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
// plugin | |||
virtual void save_now() = 0; | |||
virtual void set_custom_data(const char* const type, const char* const key, const char* const value) = 0; | |||
virtual void set_chunk_data(const char* const filePath) = 0; | |||
#else | |||
// gui | |||
virtual void* get_widget() const = 0; | |||
virtual bool is_resizable() const = 0; | |||
virtual bool needs_reparent() const = 0; | |||
#endif | |||
// --------------------------------------------------------------------- | |||
#ifdef BUILD_BRIDGE_UI | |||
bool lib_open(const char* filename) | |||
{ | |||
m_lib = ::lib_open(filename); | |||
m_filename = strdup(filename); | |||
return bool(m_lib); | |||
} | |||
bool lib_close() | |||
{ | |||
if (m_lib) | |||
return ::lib_close(m_lib); | |||
return false; | |||
} | |||
void* lib_symbol(const char* symbol) | |||
{ | |||
if (m_lib) | |||
return ::lib_symbol(m_lib, symbol); | |||
return nullptr; | |||
} | |||
const char* lib_error() | |||
{ | |||
return ::lib_error(m_filename ? m_filename : ""); | |||
} | |||
#endif | |||
// --------------------------------------------------------------------- | |||
private: | |||
char* m_title; | |||
QMutex m_lock; | |||
QuequeBridgeMessage QuequeBridgeMessages[MAX_BRIDGE_MESSAGES]; | |||
#ifdef BUILD_BRIDGE_UI | |||
char* m_filename; | |||
void* m_lib; | |||
#endif | |||
Message() | |||
: type(MESSAGE_NULL), | |||
value1(0), | |||
value2(0), | |||
value3(0.0) {} | |||
}; | |||
// ------------------------------------------------------------------------- | |||
/**@}*/ | |||
class CarlaBridgeClient; | |||
class CarlaBridgeToolkit; | |||
extern ClientData* client; | |||
CARLA_BRIDGE_END_NAMESPACE | |||
#endif // CARLA_BRIDGE_H |
@@ -0,0 +1,243 @@ | |||
/* | |||
* Carla bridge code | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
* | |||
* 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 COPYING file | |||
*/ | |||
#ifndef CARLA_BRIDGE_CLIENT_H | |||
#define CARLA_BRIDGE_CLIENT_H | |||
#include "carla_bridge.h" | |||
#include "carla_bridge_osc.h" | |||
#include "carla_bridge_toolkit.h" | |||
#ifdef BUILD_BRIDGE_UI | |||
#include "carla_lib_includes.h" | |||
#endif | |||
#include <cstdio> | |||
#include <cstdint> | |||
#include <cstdlib> | |||
#include <QtCore/QMutex> | |||
//CARLA_BRIDGE_START_NAMESPACE; | |||
namespace CarlaBridge { | |||
class CarlaBridgeClient | |||
{ | |||
public: | |||
CarlaBridgeClient(CarlaBridgeToolkit* const toolkit) : | |||
m_toolkit(toolkit), | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
m_osc(this, "lv2-plugin-bridge") | |||
#else | |||
m_osc(this, "lv2-ui-bridge") | |||
#endif | |||
{ | |||
#ifdef BUILD_BRIDGE_UI | |||
m_filename = nullptr; | |||
m_lib = nullptr; | |||
#endif | |||
} | |||
virtual ~CarlaBridgeClient() | |||
{ | |||
#ifdef BUILD_BRIDGE_UI | |||
if (m_filename) | |||
free(m_filename); | |||
#endif | |||
} | |||
// --------------------------------------------------------------------- | |||
void oscInit(const char* const url) | |||
{ | |||
m_osc.init(url); | |||
} | |||
void oscClose() | |||
{ | |||
m_osc.close(); | |||
} | |||
void oscSendUpdate() | |||
{ | |||
m_osc.sendOscUpdate(); | |||
} | |||
const CarlaOscData* getOscServerData() | |||
{ | |||
return m_osc.getServerData(); | |||
} | |||
// --------------------------------------------------------------------- | |||
void quequeMessage(MessageType type, int value1, int value2, double value3) | |||
{ | |||
const QMutexLocker locker(&m_messages.lock); | |||
for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | |||
{ | |||
Message* const m = &m_messages.data[i]; | |||
if (m->type == MESSAGE_NULL) | |||
{ | |||
m->type = type; | |||
m->value1 = value1; | |||
m->value2 = value2; | |||
m->value3 = value3; | |||
break; | |||
} | |||
} | |||
} | |||
bool runMessages() | |||
{ | |||
const QMutexLocker locker(&m_messages.lock); | |||
for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | |||
{ | |||
Message* const m = &m_messages.data[i]; | |||
switch (m->type) | |||
{ | |||
case MESSAGE_NULL: | |||
return true; | |||
case MESSAGE_PARAMETER: | |||
setParameter(m->value1, m->value3); | |||
break; | |||
case MESSAGE_PROGRAM: | |||
setProgram(m->value1); | |||
break; | |||
case MESSAGE_MIDI_PROGRAM: | |||
setMidiProgram(m->value1, m->value2); | |||
break; | |||
case MESSAGE_NOTE_ON: | |||
noteOn(m->value1, m->value2); | |||
break; | |||
case MESSAGE_NOTE_OFF: | |||
noteOff(m->value1); | |||
break; | |||
case MESSAGE_SHOW_GUI: | |||
if (m->value1) | |||
m_toolkit->show(); | |||
else | |||
m_toolkit->hide(); | |||
break; | |||
case MESSAGE_RESIZE_GUI: | |||
m_toolkit->resize(m->value1, m->value2); | |||
break; | |||
case MESSAGE_SAVE_NOW: | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
saveNow(); | |||
#endif | |||
break; | |||
case MESSAGE_QUIT: | |||
m_toolkit->quit(); | |||
return false; | |||
} | |||
m->type = MESSAGE_NULL; | |||
} | |||
return true; | |||
} | |||
// --------------------------------------------------------------------- | |||
#ifdef BUILD_BRIDGE_UI | |||
// ui initialization | |||
virtual bool init(const char* const, const char* const) = 0; | |||
virtual void close() = 0; | |||
#endif | |||
// processing | |||
virtual void setParameter(const int32_t rindex, const double value) = 0; | |||
virtual void setProgram(const uint32_t index) = 0; | |||
virtual void setMidiProgram(const uint32_t bank, const uint32_t program) = 0; | |||
virtual void noteOn(const uint8_t note, const uint8_t velocity) = 0; | |||
virtual void noteOff(const uint8_t note) = 0; | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
// plugin | |||
virtual void saveNow() = 0; | |||
virtual void setCustomData(const char* const type, const char* const key, const char* const value) = 0; | |||
virtual void setChunkData(const char* const filePath) = 0; | |||
#else | |||
// gui | |||
virtual void* getWidget() const = 0; | |||
virtual bool isResizable() const = 0; | |||
virtual bool needsReparent() const = 0; | |||
#endif | |||
// --------------------------------------------------------------------- | |||
#ifdef BUILD_BRIDGE_UI | |||
protected: | |||
bool libOpen(const char* const filename) | |||
{ | |||
m_lib = ::lib_open(filename); | |||
m_filename = strdup(filename); | |||
return bool(m_lib); | |||
} | |||
bool libClose() | |||
{ | |||
if (m_lib) | |||
return ::lib_close(m_lib); | |||
return false; | |||
} | |||
void* libSymbol(const char* const symbol) | |||
{ | |||
if (m_lib) | |||
return ::lib_symbol(m_lib, symbol); | |||
return nullptr; | |||
} | |||
const char* libError() | |||
{ | |||
return ::lib_error(m_filename ? m_filename : ""); | |||
} | |||
#endif | |||
// --------------------------------------------------------------------- | |||
private: | |||
CarlaBridgeToolkit* const m_toolkit; | |||
CarlaBridgeOsc m_osc; | |||
struct { | |||
Message data[MAX_BRIDGE_MESSAGES]; | |||
QMutex lock; | |||
} m_messages; | |||
#ifdef BUILD_BRIDGE_UI | |||
char* m_filename; | |||
void* m_lib; | |||
#endif | |||
}; | |||
CARLA_BRIDGE_END_NAMESPACE | |||
#endif // CARLA_BRIDGE_CLIENT_H |
@@ -15,131 +15,124 @@ | |||
* For a full copy of the GNU General Public License see the COPYING file | |||
*/ | |||
#include "carla_bridge.h" | |||
#include "carla_bridge_osc.h" | |||
#include "carla_bridge_client.h" | |||
#include "carla_midi.h" | |||
#include <QtCore/QString> | |||
#include <QtCore/QStringList> | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
static const size_t client_name_len = 13; | |||
static const char* const client_name = "plugin-bridge"; | |||
#include "carla_plugin.h" | |||
#else | |||
static const size_t client_name_len = 13; | |||
static const char* const client_name = "lv2-ui-bridge"; | |||
#endif | |||
//CARLA_BRIDGE_START_NAMESPACE | |||
namespace CarlaBridge { | |||
CarlaBridgeOsc::CarlaBridgeOsc(CarlaBridgeClient* const client_, const char* const name) : | |||
client(client_) | |||
{ | |||
qDebug("CarlaBridgeOsc::CarlaBridgeOsc(%p, %s)", client_, name); | |||
assert(client_); | |||
assert(name); | |||
const char* global_osc_server_path = nullptr; | |||
lo_server_thread global_osc_server_thread = nullptr; | |||
OscData global_osc_data = { nullptr, nullptr, nullptr }; | |||
m_serverPath = nullptr; | |||
m_serverThread = nullptr; | |||
m_serverData.path = nullptr; | |||
m_serverData.source = nullptr; | |||
m_serverData.target = nullptr; | |||
// ------------------------------------------------------------------------- | |||
m_name = strdup(name); | |||
m_name_len = strlen(name); | |||
} | |||
void osc_init(const char* osc_url) | |||
CarlaBridgeOsc::~CarlaBridgeOsc() | |||
{ | |||
qDebug("osc_init(%s)", osc_url); | |||
qDebug("CarlaBridgeOsc::~CarlaBridgeOsc()"); | |||
const char* host = lo_url_get_hostname(osc_url); | |||
const char* port = lo_url_get_port(osc_url); | |||
free((void*)m_name); | |||
} | |||
global_osc_data.path = lo_url_get_path(osc_url); | |||
global_osc_data.target = lo_address_new(host, port); | |||
void CarlaBridgeOsc::init(const char* const url) | |||
{ | |||
qDebug("CarlaBridgeOsc::init(%s)", url); | |||
assert(url); | |||
const char* host = lo_url_get_hostname(url); | |||
const char* port = lo_url_get_port(url); | |||
m_serverData.path = lo_url_get_path(url); | |||
m_serverData.target = lo_address_new(host, port); | |||
free((void*)host); | |||
free((void*)port); | |||
// create new OSC thread | |||
global_osc_server_thread = lo_server_thread_new(nullptr, osc_error_handler); | |||
m_serverThread = lo_server_thread_new(nullptr, osc_error_handler); | |||
// get our full OSC server path | |||
char* osc_thread_path = lo_server_thread_get_url(global_osc_server_thread); | |||
global_osc_server_path = strdup(QString("%1%2").arg(osc_thread_path).arg(client_name).toUtf8().constData()); | |||
free(osc_thread_path); | |||
char* const threadPath = lo_server_thread_get_url(m_serverThread); | |||
m_serverPath = strdup(QString("%1%2").arg(threadPath).arg(m_name).toUtf8().constData()); | |||
free(threadPath); | |||
// register message handler and start OSC thread | |||
lo_server_thread_add_method(global_osc_server_thread, nullptr, nullptr, osc_message_handler, nullptr); | |||
lo_server_thread_start(global_osc_server_thread); | |||
lo_server_thread_add_method(m_serverThread, nullptr, nullptr, osc_message_handler, this); | |||
lo_server_thread_start(m_serverThread); | |||
} | |||
void osc_close() | |||
void CarlaBridgeOsc::close() | |||
{ | |||
qDebug("osc_close()"); | |||
qDebug("CarlaBridgeOsc::close()"); | |||
assert(client); | |||
osc_clear_data(&global_osc_data); | |||
osc_clear_data(&m_serverData); | |||
lo_server_thread_stop(global_osc_server_thread); | |||
lo_server_thread_del_method(global_osc_server_thread, nullptr, nullptr); | |||
lo_server_thread_free(global_osc_server_thread); | |||
lo_server_thread_stop(m_serverThread); | |||
lo_server_thread_del_method(m_serverThread, nullptr, nullptr); | |||
lo_server_thread_free(m_serverThread); | |||
free((void*)global_osc_server_path); | |||
global_osc_server_path = nullptr; | |||
free((void*)m_serverPath); | |||
m_serverPath = nullptr; | |||
} | |||
void osc_clear_data(OscData* osc_data) | |||
int CarlaBridgeOsc::handleMessage(const char* const path, const int argc, const lo_arg* const* const argv, const char* const types, const lo_message msg) | |||
{ | |||
qDebug("osc_clear_data(%p)", osc_data); | |||
if (osc_data->path) | |||
free((void*)osc_data->path); | |||
if (osc_data->source) | |||
lo_address_free(osc_data->source); | |||
if (osc_data->target) | |||
lo_address_free(osc_data->target); | |||
osc_data->path = nullptr; | |||
osc_data->source = nullptr; | |||
osc_data->target = nullptr; | |||
} | |||
// ------------------------------------------------------------------------- | |||
void osc_error_handler(int num, const char* msg, const char* path) | |||
{ | |||
qCritical("osc_error_handler(%i, %s, %s)", num, msg, path); | |||
} | |||
int osc_message_handler(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) | |||
{ | |||
#if DEBUG | |||
qDebug("osc_message_handler(%s, %s, %p, %i, %p, %p)", path, types, argv, argc, data, user_data); | |||
#endif | |||
qDebug("CarlaBridgeOsc::handleMessage(%s, %i, %p, %s, %p)", path, argc, argv, types, msg); | |||
assert(m_serverThread); | |||
assert(path); | |||
// Check if message is for this client | |||
if (strlen(path) <= client_name_len || strncmp(path+1, client_name, client_name_len) != 0) | |||
if (strlen(path) <= m_name_len || strncmp(path+1, m_name, m_name_len) != 0) | |||
{ | |||
qWarning("osc_message_handler() - message not for this client -> '%s' != '/%s/'", path, client_name); | |||
qWarning("CarlaBridgeOsc::handleMessage() - message not for this client -> '%s' != '/%s/'", path, m_name); | |||
return 1; | |||
} | |||
char method[32] = { 0 }; | |||
memcpy(method, path + client_name_len + 1, 32); | |||
memcpy(method, path + (m_name_len + 1), 32); | |||
// Common OSC methods | |||
if (strcmp(method, "/configure") == 0) | |||
return osc_handle_configure(argv); | |||
else if (strcmp(method, "/control") == 0) | |||
return osc_handle_control(argv); | |||
else if (strcmp(method, "/program") == 0) | |||
return osc_handle_program(argv); | |||
else if (strcmp(method, "/midi_program") == 0) | |||
return osc_handle_midi_program(argv); | |||
else if (strcmp(method, "/midi") == 0) | |||
return osc_handle_midi(argv); | |||
else if (strcmp(method, "/show") == 0) | |||
return osc_handle_show(); | |||
else if (strcmp(method, "/hide") == 0) | |||
return osc_handle_hide(); | |||
else if (strcmp(method, "/quit") == 0) | |||
return osc_handle_quit(); | |||
#if BRIDGE_LV2_GTK2 || BRIDGE_LV2_QT4 || BRIDGE_LV2_X11 | |||
//else if (strcmp(method, "/lv2_atom_transfer") == 0) | |||
// return osc_handle_lv2_atom_transfer(argv); | |||
else if (strcmp(method, "/lv2_event_transfer") == 0) | |||
return osc_handle_lv2_event_transfer(argv); | |||
return handle_configure(argc, argv, types); | |||
if (strcmp(method, "/control") == 0) | |||
return handle_control(argc, argv, types); | |||
if (strcmp(method, "/program") == 0) | |||
return handle_program(argc, argv, types); | |||
if (strcmp(method, "/midi_program") == 0) | |||
return handle_midi_program(argc, argv, types); | |||
if (strcmp(method, "/midi") == 0) | |||
return handle_midi(argc, argv, types); | |||
if (strcmp(method, "/show") == 0) | |||
return handle_show(); | |||
if (strcmp(method, "/hide") == 0) | |||
return handle_hide(); | |||
if (strcmp(method, "/quit") == 0) | |||
return handle_quit(); | |||
// client specific methods | |||
#if LV2_UI_GTK2 || LV2_UI_QT4 || LV2_UI_X11 | |||
if (strcmp(method, "/lv2_atom_transfer") == 0) | |||
return handle_lv2_atom_transfer(argc, argv, types); | |||
if (strcmp(method, "/lv2_event_transfer") == 0) | |||
return handle_lv2_event_transfer(argc, argv, types); | |||
#endif | |||
#if 0 | |||
else if (strcmp(method, "set_parameter_midi_channel") == 0) | |||
return osc_set_parameter_midi_channel_handler(argv); | |||
@@ -150,48 +143,41 @@ int osc_message_handler(const char* path, const char* types, lo_arg** argv, int | |||
qWarning("Got unsupported OSC method '%s' on '%s'", method, path); | |||
return 1; | |||
Q_UNUSED(types); | |||
Q_UNUSED(argc); | |||
Q_UNUSED(data); | |||
Q_UNUSED(user_data); | |||
} | |||
// ------------------------------------------------------------------------- | |||
int osc_handle_configure(lo_arg** argv) | |||
int CarlaBridgeOsc::handle_configure(CARLA_BRIDGE_OSC_HANDLE_ARGS) | |||
{ | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
using namespace CarlaBackend; | |||
qDebug("CarlaOsc::handle_configure()"); | |||
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "ss"); | |||
const char* key = (const char*)&argv[0]->s; | |||
const char* value = (const char*)&argv[1]->s; | |||
if (! client) | |||
return 1; | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
const char* const key = (const char*)&argv[0]->s; | |||
const char* const value = (const char*)&argv[1]->s; | |||
if (client) | |||
if (strcmp(key, CARLA_BRIDGE_MSG_SAVE_NOW) == 0) | |||
{ | |||
if (strcmp(key, CARLA_BRIDGE_MSG_SAVE_NOW) == 0) | |||
{ | |||
client->queque_message(BRIDGE_MESSAGE_SAVE_NOW, 0, 0, 0.0); | |||
} | |||
else if (strcmp(key, CARLA_BRIDGE_MSG_SET_CHUNK) == 0) | |||
{ | |||
client->set_chunk_data(value); | |||
} | |||
else if (strcmp(key, CARLA_BRIDGE_MSG_SET_CUSTOM) == 0) | |||
{ | |||
QStringList vList = QString(value).split("·", QString::KeepEmptyParts); | |||
client->quequeMessage(BRIDGE_MESSAGE_SAVE_NOW, 0, 0, 0.0); | |||
} | |||
else if (strcmp(key, CARLA_BRIDGE_MSG_SET_CHUNK) == 0) | |||
{ | |||
client->setChunkData(value); | |||
} | |||
else if (strcmp(key, CARLA_BRIDGE_MSG_SET_CUSTOM) == 0) | |||
{ | |||
QStringList vList = QString(value).split("·", QString::KeepEmptyParts); | |||
if (vList.size() == 3) | |||
{ | |||
const char* const cType = vList.at(0).toUtf8().constData(); | |||
const char* const cKey = vList.at(1).toUtf8().constData(); | |||
const char* const cValue = vList.at(2).toUtf8().constData(); | |||
if (vList.size() == 3) | |||
{ | |||
const char* const cType = vList.at(0).toUtf8().constData(); | |||
const char* const cKey = vList.at(1).toUtf8().constData(); | |||
const char* const cValue = vList.at(2).toUtf8().constData(); | |||
client->set_custom_data(cType, cKey, cValue); | |||
} | |||
client->set_custom_data(cType, cKey, cValue); | |||
} | |||
} | |||
#else | |||
Q_UNUSED(argv); | |||
#endif | |||
@@ -199,41 +185,59 @@ int osc_handle_configure(lo_arg** argv) | |||
return 0; | |||
} | |||
int osc_handle_control(lo_arg** argv) | |||
int CarlaBridgeOsc::handle_control(CARLA_BRIDGE_OSC_HANDLE_ARGS) | |||
{ | |||
int rindex = argv[0]->i; | |||
float value = argv[1]->f; | |||
//qDebug("CarlaOsc::handle_control()"); | |||
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "if"); | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_PARAMETER, rindex, 0, value); | |||
if (! client) | |||
return 1; | |||
const int rindex = argv[0]->i; | |||
const float value = argv[1]->f; | |||
client->quequeMessage(MESSAGE_PARAMETER, rindex, 0, value); | |||
return 0; | |||
} | |||
int osc_handle_program(lo_arg** argv) | |||
int CarlaBridgeOsc::handle_program(CARLA_BRIDGE_OSC_HANDLE_ARGS) | |||
{ | |||
int index = argv[0]->i; | |||
qDebug("CarlaOsc::handle_program()"); | |||
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(1, "i"); | |||
if (! client) | |||
return 1; | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_PROGRAM, index, 0, 0.0); | |||
const int index = argv[0]->i; | |||
client->quequeMessage(MESSAGE_PROGRAM, index, 0, 0.0); | |||
return 0; | |||
} | |||
int osc_handle_midi_program(lo_arg** argv) | |||
int CarlaBridgeOsc::handle_midi_program(CARLA_BRIDGE_OSC_HANDLE_ARGS) | |||
{ | |||
int bank = argv[0]->i; | |||
int program = argv[1]->i; | |||
qDebug("CarlaOsc::handle_program()"); | |||
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "ii"); | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_MIDI_PROGRAM, bank, program, 0.0); | |||
if (! client) | |||
return 1; | |||
const int bank = argv[0]->i; | |||
const int program = argv[1]->i; | |||
client->quequeMessage(MESSAGE_MIDI_PROGRAM, bank, program, 0.0); | |||
return 0; | |||
} | |||
int osc_handle_midi(lo_arg** argv) | |||
int CarlaBridgeOsc::handle_midi(CARLA_BRIDGE_OSC_HANDLE_ARGS) | |||
{ | |||
uint8_t* data = argv[0]->m; | |||
qDebug("CarlaOsc::handle_midi()"); | |||
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(1, "m"); | |||
if (! client) | |||
return 1; | |||
const uint8_t* const data = argv[0]->m; | |||
uint8_t status = data[1]; | |||
// Fix bad note-off | |||
@@ -243,125 +247,46 @@ int osc_handle_midi(lo_arg** argv) | |||
if (MIDI_IS_STATUS_NOTE_OFF(status)) | |||
{ | |||
uint8_t note = data[2]; | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_NOTE_OFF, note, 0, 0.0); | |||
client->quequeMessage(MESSAGE_NOTE_OFF, note, 0, 0.0); | |||
} | |||
else if (MIDI_IS_STATUS_NOTE_ON(status)) | |||
{ | |||
uint8_t note = data[2]; | |||
uint8_t velo = data[3]; | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_NOTE_ON, note, velo, 0.0); | |||
client->quequeMessage(MESSAGE_NOTE_ON, note, velo, 0.0); | |||
} | |||
return 0; | |||
} | |||
int osc_handle_show() | |||
int CarlaBridgeOsc::handle_show() | |||
{ | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_SHOW_GUI, 1, 0, 0.0); | |||
return 0; | |||
} | |||
int osc_handle_hide() | |||
{ | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_SHOW_GUI, 0, 0, 0.0); | |||
return 0; | |||
} | |||
if (! client) | |||
return 1; | |||
int osc_handle_quit() | |||
{ | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_QUIT, 0, 0, 0.0); | |||
client->quequeMessage(MESSAGE_SHOW_GUI, 1, 0, 0.0); | |||
return 0; | |||
} | |||
// ------------------------------------------------------------------------- | |||
void osc_send_configure(const char* const key, const char* const value) | |||
int CarlaBridgeOsc::handle_hide() | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+11]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/configure"); | |||
lo_send(global_osc_data.target, target_path, "ss", key, value); | |||
} | |||
} | |||
void osc_send_control(int param, double value) | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+9]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/control"); | |||
lo_send(global_osc_data.target, target_path, "if", param, value); | |||
} | |||
} | |||
if (! client) | |||
return 1; | |||
void osc_send_program(int program) | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+9]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/program"); | |||
lo_send(global_osc_data.target, target_path, "i", program); | |||
} | |||
} | |||
client->quequeMessage(MESSAGE_SHOW_GUI, 0, 0, 0.0); | |||
void osc_send_midi_program(int bank, int program, bool) | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+14]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/midi_program"); | |||
lo_send(global_osc_data.target, target_path, "ii", bank, program); | |||
} | |||
return 0; | |||
} | |||
void osc_send_midi(uint8_t buf[4]) | |||
int CarlaBridgeOsc::handle_quit() | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+6]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/midi"); | |||
lo_send(global_osc_data.target, target_path, "m", buf); | |||
} | |||
} | |||
if (! client) | |||
return 1; | |||
// ------------------------------------------------------------------------- | |||
client->quequeMessage(MESSAGE_QUIT, 0, 0, 0.0); | |||
void osc_send_update() | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+8]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/update"); | |||
lo_send(global_osc_data.target, target_path, "s", global_osc_server_path); | |||
} | |||
} | |||
void osc_send_exiting() | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+9]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/exiting"); | |||
lo_send(global_osc_data.target, target_path, ""); | |||
} | |||
return 0; | |||
} | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
@@ -541,15 +466,6 @@ void osc_send_bridge_update() | |||
lo_send(global_osc_data.target, target_path, ""); | |||
} | |||
} | |||
#else | |||
void osc_send_lv2_event_transfer(const char* type, const char* key, const char* value) | |||
{ | |||
if (global_osc_data.target) | |||
{ | |||
char target_path[strlen(global_osc_data.path)+20]; | |||
strcpy(target_path, global_osc_data.path); | |||
strcat(target_path, "/lv2_event_transfer"); | |||
lo_send(global_osc_data.target, target_path, "sss", type, key, value); | |||
} | |||
} | |||
#endif | |||
CARLA_BRIDGE_END_NAMESPACE |
@@ -19,12 +19,98 @@ | |||
#define CARLA_BRIDGE_OSC_H | |||
#include "carla_osc_includes.h" | |||
#include "carla_bridge.h" | |||
void osc_send_update(); | |||
void osc_send_exiting(); | |||
#define CARLA_BRIDGE_OSC_HANDLE_ARGS const int argc, const lo_arg* const* const argv, const char* const types | |||
#define CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \ | |||
/* check argument count */ \ | |||
if (argc != argcToCompare) \ | |||
{ \ | |||
qCritical("CarlaBridgeOsc::%s() - argument count mismatch: %i != %i", __FUNCTION__, argc, argcToCompare); \ | |||
return 1; \ | |||
} \ | |||
if (argc > 0) \ | |||
{ \ | |||
/* check for nullness */ \ | |||
if (! (types && typesToCompare)) \ | |||
{ \ | |||
qCritical("CarlaBridgeOsc::%s() - argument types are null", __FUNCTION__); \ | |||
return 1; \ | |||
} \ | |||
/* check argument types */ \ | |||
if (strcmp(types, typesToCompare) != 0) \ | |||
{ \ | |||
qCritical("CarlaBridgeOsc::%s() - argument types mismatch: '%s' != '%s'", __FUNCTION__, types, typesToCompare); \ | |||
return 1; \ | |||
} \ | |||
} | |||
//CARLA_BRIDGE_START_NAMESPACE | |||
namespace CarlaBridge { | |||
class CarlaBridgeOsc | |||
{ | |||
public: | |||
CarlaBridgeOsc(CarlaBridgeClient* const client, const char* const name); | |||
~CarlaBridgeOsc(); | |||
void init(const char* const url); | |||
void close(); | |||
const CarlaOscData* getServerData() const | |||
{ | |||
return &m_serverData; | |||
} | |||
void sendOscUpdate() | |||
{ | |||
osc_send_update(&m_serverData, m_serverPath); | |||
} | |||
private: | |||
CarlaBridgeClient* const client; | |||
const char* m_serverPath; | |||
lo_server_thread m_serverThread; | |||
CarlaOscData m_serverData; | |||
const char* m_name; | |||
size_t m_name_len; | |||
// ------------------------------------------------------------------- | |||
static void osc_error_handler(const int num, const char* const msg, const char* const path) | |||
{ | |||
qCritical("osc_error_handler(%i, %s, %s)", num, msg, path); | |||
} | |||
static int osc_message_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg, void* const user_data) | |||
{ | |||
CarlaBridgeOsc* const _this_ = (CarlaBridgeOsc*)user_data; | |||
if (! _this_->client) | |||
return 1; | |||
return _this_->handleMessage(path, argc, argv, types, msg); | |||
} | |||
int handleMessage(const char* const path, const int argc, const lo_arg* const* const argv, const char* const types, const lo_message msg); | |||
int handle_configure(CARLA_BRIDGE_OSC_HANDLE_ARGS); | |||
int handle_control(CARLA_BRIDGE_OSC_HANDLE_ARGS); | |||
int handle_program(CARLA_BRIDGE_OSC_HANDLE_ARGS); | |||
int handle_midi_program(CARLA_BRIDGE_OSC_HANDLE_ARGS); | |||
int handle_midi(CARLA_BRIDGE_OSC_HANDLE_ARGS); | |||
int handle_show(); | |||
int handle_hide(); | |||
int handle_quit(); | |||
int handle_lv2_atom_transfer(CARLA_BRIDGE_OSC_HANDLE_ARGS); | |||
int handle_lv2_event_transfer(CARLA_BRIDGE_OSC_HANDLE_ARGS); | |||
}; | |||
#ifdef BUILD_BRIDGE_PLUGIN | |||
// plugin-bridge only | |||
void osc_send_bridge_ains_peak(int index, double value); | |||
void osc_send_bridge_aouts_peak(int index, double value); | |||
void osc_send_bridge_audio_count(int ins, int outs, int total); | |||
@@ -41,12 +127,8 @@ void osc_send_bridge_midi_program_info(int index, int bank, int program, const c | |||
void osc_send_bridge_custom_data(const char* stype, const char* key, const char* value); | |||
void osc_send_bridge_chunk_data(const char* string_data); | |||
void osc_send_bridge_update(); | |||
#else | |||
// ui-bridge only | |||
//int osc_handle_lv2_atom_transfer(lo_arg** argv); | |||
int osc_handle_lv2_event_transfer(lo_arg** argv); | |||
//void osc_send_lv2_atom_transfer(); | |||
void osc_send_lv2_event_transfer(const char* type, const char* key, const char* value); | |||
#endif | |||
CARLA_BRIDGE_END_NAMESPACE | |||
#endif // CARLA_BRIDGE_OSC_H |
@@ -0,0 +1,193 @@ | |||
/* | |||
* Carla UI bridge code | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
* | |||
* 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 COPYING file | |||
*/ | |||
#include "carla_bridge_client.h" | |||
#ifdef BRIDGE_LV2_X11 | |||
#error X11 UI uses Qt4 | |||
#endif | |||
#include <gtk/gtk.h> | |||
#include <QtCore/QSettings> | |||
CARLA_BRIDGE_START_NAMESPACE | |||
// ------------------------------------------------------------------------- | |||
class CarlaBridgeToolkitGtk2: public CarlaBridgeToolkit | |||
{ | |||
public: | |||
CarlaBridgeToolkitGtk2(const char* const title) : | |||
CarlaBridgeToolkit(title), | |||
settings("Cadence", "Carla-Gtk2UIs") | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::CarlaBridgeToolkitGtk2(%s)", title); | |||
window = nullptr; | |||
last_x = last_y = 0; | |||
last_width = last_height = 0; | |||
} | |||
~CarlaBridgeToolkitGtk2() | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::~CarlaBridgeToolkitGtk2()"); | |||
} | |||
void init() | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::init()"); | |||
static int argc = 0; | |||
static char** argv = { nullptr }; | |||
gtk_init(&argc, &argv); | |||
} | |||
void exec(CarlaBridgeClient* const client) | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::exec(%p)", client); | |||
assert(client); | |||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |||
gtk_container_add(GTK_CONTAINER(window), (GtkWidget*)client->getWidget()); | |||
gtk_window_set_resizable(GTK_WINDOW(window), client->isResizable()); | |||
gtk_window_set_title(GTK_WINDOW(window), m_title); | |||
gtk_window_get_position(GTK_WINDOW(window), &last_x, &last_y); | |||
gtk_window_get_size(GTK_WINDOW(window), &last_width, &last_height); | |||
if (settings.contains(QString("%1/pos_x").arg(m_title))) | |||
{ | |||
last_x = settings.value(QString("%1/pos_x").arg(m_title), last_x).toInt(); | |||
last_y = settings.value(QString("%1/pos_y").arg(m_title), last_y).toInt(); | |||
gtk_window_move(GTK_WINDOW(window), last_x, last_y); | |||
if (client->isResizable()) | |||
{ | |||
last_width = settings.value(QString("%1/width").arg(m_title), last_width).toInt(); | |||
last_height = settings.value(QString("%1/height").arg(m_title), last_height).toInt(); | |||
gtk_window_resize(GTK_WINDOW(window), last_width, last_height); | |||
} | |||
} | |||
g_timeout_add(50, gtk_ui_timeout, this); | |||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_ui_destroy), this); | |||
m_client = client; | |||
client->oscSendUpdate(); | |||
// Main loop | |||
gtk_main(); | |||
} | |||
void quit() | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::quit()"); | |||
if (window) | |||
{ | |||
gtk_widget_destroy(window); | |||
gtk_main_quit(); | |||
window = nullptr; | |||
} | |||
m_client = nullptr; | |||
} | |||
void show() | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::show()"); | |||
assert(window); | |||
if (window) | |||
gtk_widget_show_all(window); | |||
} | |||
void hide() | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::hide()"); | |||
assert(window); | |||
if (window) | |||
gtk_widget_hide_all(window); | |||
} | |||
void resize(int width, int height) | |||
{ | |||
qDebug("CarlaBridgeToolkitGtk2::resize(%i, %i)", width, height); | |||
assert(window); | |||
if (window) | |||
gtk_window_resize(GTK_WINDOW(window), width, height); | |||
} | |||
private: | |||
GtkWidget* window; | |||
QSettings settings; | |||
gint last_x, last_y, last_width, last_height; | |||
static void gtk_ui_destroy(GtkWidget*, gpointer data) | |||
{ | |||
CarlaBridgeToolkitGtk2* const _this_ = (CarlaBridgeToolkitGtk2*)data; | |||
_this_->handleDestroy(); | |||
gtk_main_quit(); | |||
} | |||
static gboolean gtk_ui_timeout(gpointer data) | |||
{ | |||
CarlaBridgeToolkitGtk2* const _this_ = (CarlaBridgeToolkitGtk2*)data; | |||
return _this_->handleTimeout(); | |||
} | |||
// --------------------------------------------------------------------- | |||
void handleDestroy() | |||
{ | |||
window = nullptr; | |||
m_client = nullptr; | |||
settings.setValue(QString("%1/pos_x").arg(m_title), last_x); | |||
settings.setValue(QString("%1/pos_y").arg(m_title), last_y); | |||
settings.setValue(QString("%1/width").arg(m_title), last_width); | |||
settings.setValue(QString("%1/height").arg(m_title), last_height); | |||
settings.sync(); | |||
} | |||
gboolean handleTimeout() | |||
{ | |||
if (window) | |||
{ | |||
gtk_window_get_position(GTK_WINDOW(window), &last_x, &last_y); | |||
gtk_window_get_size(GTK_WINDOW(window), &last_width, &last_height); | |||
} | |||
return m_client ? m_client->runMessages() : false; | |||
} | |||
}; | |||
// ------------------------------------------------------------------------- | |||
CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(const char* const title) | |||
{ | |||
return new CarlaBridgeToolkitGtk2(title); | |||
} | |||
CARLA_BRIDGE_END_NAMESPACE |
@@ -0,0 +1,213 @@ | |||
/* | |||
* Carla UI bridge code | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
* | |||
* 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 COPYING file | |||
*/ | |||
#include "carla_bridge_client.h" | |||
#include <QtCore/QSettings> | |||
#include <QtCore/QTimer> | |||
#include <QtGui/QApplication> | |||
#include <QtGui/QDialog> | |||
#include <QtGui/QVBoxLayout> | |||
//CARLA_BRIDGE_START_NAMESPACE | |||
namespace CarlaBridge { | |||
// ------------------------------------------------------------------------- | |||
class MessageChecker : public QTimer | |||
{ | |||
public: | |||
MessageChecker(CarlaBridgeClient* const client_) : | |||
client(client_) | |||
{ | |||
assert(client); | |||
} | |||
void timerEvent(QTimerEvent*) | |||
{ | |||
if (! client->runMessages()) | |||
stop(); | |||
} | |||
private: | |||
CarlaBridgeClient* const client; | |||
}; | |||
class CarlaBridgeToolkitQt4: public CarlaBridgeToolkit | |||
{ | |||
public: | |||
CarlaBridgeToolkitQt4(const char* const title) : | |||
CarlaBridgeToolkit(title), | |||
#ifdef BRIDGE_LV2_X11 | |||
settings("Cadence", "Carla-X11UIs") | |||
#else | |||
settings("Cadence", "Carla-Qt4UIs") | |||
#endif | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::CarlaBridgeToolkitQt4(%s)", title); | |||
app = nullptr; | |||
window = nullptr; | |||
} | |||
~CarlaBridgeToolkitQt4() | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::~CarlaBridgeToolkitQt4()"); | |||
} | |||
void init() | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::init()"); | |||
assert(! app); | |||
static int argc = 0; | |||
static char* argv[] = { nullptr }; | |||
app = new QApplication(argc, argv, true); | |||
} | |||
void exec(CarlaBridgeClient* const client) | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::exec(%p)", client); | |||
assert(app); | |||
assert(client); | |||
if (client->needsReparent()) | |||
{ | |||
window = (QDialog*)client->getWidget(); | |||
window->resize(10, 10); | |||
} | |||
else | |||
{ | |||
// TODO - window->setCentralWidget(widget); or other simpler method | |||
window = new QDialog(); | |||
window->resize(10, 10); | |||
window->setLayout(new QVBoxLayout(window)); | |||
QWidget* const widget = (QWidget*)client->getWidget(); | |||
window->layout()->addWidget(widget); | |||
window->layout()->setContentsMargins(0, 0, 0, 0); | |||
window->adjustSize(); | |||
widget->setParent(window); | |||
widget->show(); | |||
} | |||
if (! client->isResizable()) | |||
window->setFixedSize(window->width(), window->height()); | |||
window->setWindowTitle(m_title); | |||
if (settings.contains(QString("%1/pos_x").arg(m_title))) | |||
{ | |||
int posX = settings.value(QString("%1/pos_x").arg(m_title), window->x()).toInt(); | |||
int posY = settings.value(QString("%1/pos_y").arg(m_title), window->y()).toInt(); | |||
window->move(posX, posY); | |||
if (client->isResizable()) | |||
{ | |||
int width = settings.value(QString("%1/width").arg(m_title), window->width()).toInt(); | |||
int height = settings.value(QString("%1/height").arg(m_title), window->height()).toInt(); | |||
window->resize(width, height); | |||
} | |||
} | |||
MessageChecker messageChecker(client); | |||
messageChecker.start(50); | |||
QObject::connect(window, SIGNAL(finished(int)), app, SLOT(quit())); | |||
m_client = client; | |||
client->oscSendUpdate(); | |||
// Main loop | |||
app->exec(); | |||
} | |||
void quit() | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::quit()"); | |||
assert(app); | |||
if (window) | |||
{ | |||
if (m_client) | |||
{ | |||
settings.setValue(QString("%1/pos_x").arg(m_title), window->x()); | |||
settings.setValue(QString("%1/pos_y").arg(m_title), window->y()); | |||
settings.setValue(QString("%1/width").arg(m_title), window->width()); | |||
settings.setValue(QString("%1/height").arg(m_title), window->height()); | |||
settings.sync(); | |||
} | |||
window->close(); | |||
delete window; | |||
window = nullptr; | |||
} | |||
m_client = nullptr; | |||
if (app) | |||
{ | |||
if (! app->closingDown()) | |||
app->quit(); | |||
delete app; | |||
} | |||
} | |||
void show() | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::show()"); | |||
assert(window); | |||
if (window) | |||
window->show(); | |||
} | |||
void hide() | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::hide()"); | |||
assert(window); | |||
if (window) | |||
window->hide(); | |||
} | |||
void resize(int width, int height) | |||
{ | |||
qDebug("CarlaBridgeToolkitQt4::resize(%i, %i)", width, height); | |||
assert(window); | |||
if (window) | |||
window->setFixedSize(width, height); | |||
} | |||
private: | |||
QApplication* app; | |||
QDialog* window; | |||
QSettings settings; | |||
}; | |||
// ------------------------------------------------------------------------- | |||
CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(const char* const title) | |||
{ | |||
return new CarlaBridgeToolkitQt4(title); | |||
} | |||
CARLA_BRIDGE_END_NAMESPACE |
@@ -0,0 +1,62 @@ | |||
/* | |||
* Carla bridge code | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
* | |||
* 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 COPYING file | |||
*/ | |||
#ifndef CARLA_BRIDGE_TOOLKIT_H | |||
#define CARLA_BRIDGE_TOOLKIT_H | |||
#include "carla_bridge.h" | |||
#include <cassert> | |||
#include <cstring> | |||
//CARLA_BRIDGE_START_NAMESPACE | |||
namespace CarlaBridge { | |||
class CarlaBridgeToolkit | |||
{ | |||
public: | |||
CarlaBridgeToolkit(const char* const title) | |||
{ | |||
assert(title); | |||
m_title = strdup(title); | |||
m_client = nullptr; | |||
} | |||
virtual ~CarlaBridgeToolkit() | |||
{ | |||
free((void*)m_title); | |||
} | |||
virtual void init() = 0; | |||
virtual void exec(CarlaBridgeClient* const client) = 0; | |||
virtual void quit() = 0; | |||
virtual void show() = 0; | |||
virtual void hide() = 0; | |||
virtual void resize(int width, int height) = 0; | |||
static CarlaBridgeToolkit* createNew(const char* const title); | |||
protected: | |||
const char* m_title; | |||
CarlaBridgeClient* m_client; | |||
}; | |||
CARLA_BRIDGE_END_NAMESPACE | |||
#endif // CARLA_BRIDGE_TOOLKIT_H |
@@ -1,137 +0,0 @@ | |||
/* | |||
* Carla UI bridge code | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
* | |||
* 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 COPYING file | |||
*/ | |||
#include "carla_bridge.h" | |||
#include "carla_bridge_osc.h" | |||
#ifdef BRIDGE_LV2_X11 | |||
#error X11 UI uses Qt4 | |||
#endif | |||
#include <gtk/gtk.h> | |||
#include <QtCore/QSettings> | |||
static GtkWidget* window = nullptr; | |||
static QSettings settings("Cadence", "Carla-Gtk2UIs"); | |||
// ------------------------------------------------------------------------- | |||
gint last_x, last_y, last_width, last_height; | |||
void save_window_settings() | |||
{ | |||
if (client) | |||
{ | |||
settings.setValue(QString("%1/pos_x").arg(client->get_title()), last_x); | |||
settings.setValue(QString("%1/pos_y").arg(client->get_title()), last_y); | |||
settings.setValue(QString("%1/width").arg(client->get_title()), last_width); | |||
settings.setValue(QString("%1/height").arg(client->get_title()), last_height); | |||
settings.sync(); | |||
} | |||
} | |||
// ------------------------------------------------------------------------- | |||
gboolean gtk_ui_recheck(void*) | |||
{ | |||
if (window) | |||
{ | |||
gtk_window_get_position(GTK_WINDOW(window), &last_x, &last_y); | |||
gtk_window_get_size(GTK_WINDOW(window), &last_width, &last_height); | |||
} | |||
return client ? client->run_messages() : false; | |||
} | |||
void gtk_ui_destroy(GtkWidget*, void*) | |||
{ | |||
toolkit_quit(); | |||
} | |||
// ------------------------------------------------------------------------- | |||
void toolkit_init() | |||
{ | |||
static int argc = 0; | |||
static char** argv = { nullptr }; | |||
gtk_init(&argc, &argv); | |||
} | |||
void toolkit_loop() | |||
{ | |||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |||
gtk_container_add(GTK_CONTAINER(window), (GtkWidget*)client->get_widget()); | |||
g_timeout_add(50, gtk_ui_recheck, nullptr); | |||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_ui_destroy), nullptr); | |||
gtk_window_set_resizable(GTK_WINDOW(window), client->is_resizable()); | |||
gtk_window_set_title(GTK_WINDOW(window), client->get_title()); | |||
gtk_window_get_position(GTK_WINDOW(window), &last_x, &last_y); | |||
gtk_window_get_size(GTK_WINDOW(window), &last_width, &last_height); | |||
if (settings.contains(QString("%1/pos_x").arg(client->get_title()))) | |||
{ | |||
last_x = settings.value(QString("%1/pos_x").arg(client->get_title()), last_x).toInt(); | |||
last_y = settings.value(QString("%1/pos_y").arg(client->get_title()), last_y).toInt(); | |||
gtk_window_move(GTK_WINDOW(window), last_x, last_y); | |||
if (client->is_resizable()) | |||
{ | |||
last_width = settings.value(QString("%1/width").arg(client->get_title()), last_width).toInt(); | |||
last_height = settings.value(QString("%1/height").arg(client->get_title()), last_height).toInt(); | |||
gtk_window_resize(GTK_WINDOW(window), last_width, last_height); | |||
} | |||
} | |||
osc_send_update(); | |||
// Main loop | |||
gtk_main(); | |||
} | |||
void toolkit_quit() | |||
{ | |||
save_window_settings(); | |||
if (window) | |||
{ | |||
gtk_widget_destroy(window); | |||
gtk_main_quit(); | |||
} | |||
window = nullptr; | |||
} | |||
void toolkit_window_show() | |||
{ | |||
if (window) | |||
gtk_widget_show_all(window); | |||
} | |||
void toolkit_window_hide() | |||
{ | |||
if (window) | |||
gtk_widget_hide_all(window); | |||
} | |||
void toolkit_window_resize(int width, int height) | |||
{ | |||
if (window) | |||
gtk_window_resize(GTK_WINDOW(window), width, height); | |||
} |
@@ -15,13 +15,10 @@ | |||
* For a full copy of the GNU General Public License see the COPYING file | |||
*/ | |||
#include "carla_bridge.h" | |||
#include "carla_bridge_osc.h" | |||
#include "carla_bridge_client.h" | |||
#include "carla_lv2.h" | |||
#include "carla_midi.h" | |||
#include "lv2_rdf.h" | |||
#include "sratom/sratom.h" | |||
#include <vector> | |||
#include <QtCore/QDir> | |||
@@ -29,7 +26,8 @@ | |||
#include <QtGui/QDialog> | |||
#endif | |||
ClientData* client = nullptr; | |||
//CARLA_BRIDGE_START_NAMESPACE; | |||
namespace CarlaBridge { | |||
// ------------------------------------------------------------------------- | |||
@@ -65,10 +63,10 @@ const uint32_t CARLA_URI_MAP_ID_COUNT = 12; | |||
// ------------------------------------------------------------------------- | |||
class Lv2UiData : public ClientData | |||
class CarlaBridgeLv2Client : public CarlaBridgeClient | |||
{ | |||
public: | |||
Lv2UiData(const char* ui_title) : ClientData(ui_title) | |||
CarlaBridgeLv2Client(CarlaBridgeToolkit* const toolkit) : CarlaBridgeClient(toolkit) | |||
{ | |||
handle = nullptr; | |||
widget = nullptr; | |||
@@ -191,7 +189,7 @@ public: | |||
features[lv2_feature_id_ui_resize]->data = UI_Resize_Feature; | |||
} | |||
~Lv2UiData() | |||
~CarlaBridgeLv2Client() | |||
{ | |||
if (rdf_descriptor) | |||
lv2_rdf_free(rdf_descriptor); | |||
@@ -254,13 +252,13 @@ public: | |||
// ----------------------------------------------------------------- | |||
// open DLL | |||
if (! lib_open(rdf_ui_descriptor->Binary)) | |||
if (! libOpen(rdf_ui_descriptor->Binary)) | |||
return false; | |||
// ----------------------------------------------------------------- | |||
// get DLL main entry | |||
LV2UI_DescriptorFunction ui_descfn = (LV2UI_DescriptorFunction)lib_symbol("lv2ui_descriptor"); | |||
LV2UI_DescriptorFunction const ui_descfn = (LV2UI_DescriptorFunction)libSymbol("lv2ui_descriptor"); | |||
if (! ui_descfn) | |||
return false; | |||
@@ -301,17 +299,14 @@ public: | |||
#endif | |||
// ----------------------------------------------------------- | |||
// check for programs extension | |||
// check for known extensions | |||
if (descriptor->extension_data) | |||
for (uint32_t i=0; descriptor->extension_data && i < rdf_ui_descriptor->ExtensionCount; i++) | |||
{ | |||
for (uint32_t i=0; i < rdf_ui_descriptor->ExtensionCount; i++) | |||
if (strcmp(rdf_ui_descriptor->Extensions[i], LV2_PROGRAMS__UIInterface) == 0) | |||
{ | |||
if (strcmp(rdf_ui_descriptor->Extensions[i], LV2_PROGRAMS__UIInterface) == 0) | |||
{ | |||
programs = (LV2_Programs_UI_Interface*)descriptor->extension_data(LV2_PROGRAMS__UIInterface); | |||
break; | |||
} | |||
programs = (LV2_Programs_UI_Interface*)descriptor->extension_data(LV2_PROGRAMS__UIInterface); | |||
break; | |||
} | |||
} | |||
@@ -320,44 +315,58 @@ public: | |||
void close() | |||
{ | |||
assert(handle && descriptor); | |||
if (handle && descriptor && descriptor->cleanup) | |||
descriptor->cleanup(handle); | |||
lib_close(); | |||
libClose(); | |||
} | |||
// --------------------------------------------------------------------- | |||
// processing | |||
void set_parameter(int32_t rindex, double value) | |||
void setParameter(int32_t rindex, double value) | |||
{ | |||
if (descriptor && descriptor->port_event) | |||
assert(handle && descriptor); | |||
if (handle && descriptor && descriptor->port_event) | |||
{ | |||
float fvalue = value; | |||
descriptor->port_event(handle, rindex, sizeof(float), 0, &fvalue); | |||
} | |||
} | |||
void set_program(uint32_t) {} | |||
void setProgram(uint32_t) | |||
{ | |||
} | |||
void set_midi_program(uint32_t bank, uint32_t program) | |||
void setMidiProgram(uint32_t bank, uint32_t program) | |||
{ | |||
if (programs) | |||
assert(handle); | |||
if (handle && programs) | |||
programs->select_program(handle, bank, program); | |||
} | |||
void note_on(uint8_t note, uint8_t velo) | |||
void noteOn(uint8_t note, uint8_t velo) | |||
{ | |||
if (descriptor && descriptor->port_event) | |||
assert(handle && descriptor); | |||
// FIXME | |||
if (handle && descriptor && descriptor->port_event) | |||
{ | |||
uint8_t buf[3] = { 0x90, note, velo }; | |||
descriptor->port_event(handle, 0, 3, CARLA_URI_MAP_ID_MIDI_EVENT, buf); | |||
} | |||
} | |||
void note_off(uint8_t note) | |||
void noteOff(uint8_t note) | |||
{ | |||
if (descriptor && descriptor->port_event) | |||
assert(handle && descriptor); | |||
// FIXME | |||
if (handle && descriptor && descriptor->port_event) | |||
{ | |||
uint8_t buf[3] = { 0x80, note, 0 }; | |||
descriptor->port_event(handle, 0, 3, CARLA_URI_MAP_ID_MIDI_EVENT, buf); | |||
@@ -367,7 +376,7 @@ public: | |||
// --------------------------------------------------------------------- | |||
// gui | |||
void* get_widget() const | |||
void* getWidget() const | |||
{ | |||
#ifdef BRIDGE_LV2_X11 | |||
return x11_widget; | |||
@@ -376,12 +385,12 @@ public: | |||
#endif | |||
} | |||
bool is_resizable() const | |||
bool isResizable() const | |||
{ | |||
return m_resizable; | |||
} | |||
bool needs_reparent() const | |||
bool needsReparent() const | |||
{ | |||
#ifdef BRIDGE_LV2_X11 | |||
return true; | |||
@@ -394,7 +403,8 @@ public: | |||
uint32_t getCustomURID(const char* const uri) | |||
{ | |||
qDebug("getCustomURID(%s)", uri); | |||
qDebug("CarlaBridgeLv2Client::getCustomURID(%s)", uri); | |||
assert(uri); | |||
for (size_t i=0; i < customURIDs.size(); i++) | |||
{ | |||
@@ -408,7 +418,8 @@ public: | |||
const char* getCustomURIString(LV2_URID urid) | |||
{ | |||
qDebug("getCustomURIString(%i)", urid); | |||
qDebug("CarlaBridgeLv2Client::getCustomURIString(%i)", urid); | |||
assert(urid != 0); | |||
if (urid < customURIDs.size()) | |||
return customURIDs[urid]; | |||
@@ -423,12 +434,12 @@ public: | |||
void handleEventTransfer(const char* const type, const char* const key, const char* const value) | |||
{ | |||
qDebug("handleEventTransfer(%s, %s, %s)", type, key, value); | |||
qDebug("CarlaBridgeLv2Client::handleEventTransfer(%s, %s, %s)", type, key, value); | |||
assert(type); | |||
assert(key); | |||
assert(value); | |||
if (descriptor && descriptor->port_event) | |||
if (handle && descriptor && descriptor->port_event) | |||
{ | |||
LV2_URID_Map* const URID_Map = (LV2_URID_Map*)features[lv2_feature_id_urid_map]->data; | |||
const LV2_URID uridPatchSet = getCustomURID(LV2_PATCH__Set); | |||
@@ -471,7 +482,7 @@ public: | |||
void handleProgramChanged(int32_t /*index*/) | |||
{ | |||
osc_send_configure("reloadprograms", ""); | |||
osc_send_configure(getOscServerData(), "reloadprograms", ""); | |||
} | |||
uint32_t handleUiPortMap(const char* const symbol) | |||
@@ -493,7 +504,7 @@ public: | |||
assert(width > 0); | |||
assert(height > 0); | |||
queque_message(BRIDGE_MESSAGE_RESIZE_GUI, width, height, 0.0); | |||
quequeMessage(MESSAGE_RESIZE_GUI, width, height, 0.0); | |||
return 0; | |||
} | |||
@@ -508,7 +519,7 @@ public: | |||
if (bufferSize == sizeof(float)) | |||
{ | |||
float value = *(float*)buffer; | |||
osc_send_control(portIndex, value); | |||
osc_send_control(getOscServerData(), portIndex, value); | |||
} | |||
} | |||
else if (format == CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM) | |||
@@ -526,7 +537,7 @@ public: | |||
descriptor->port_event(handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom); | |||
QByteArray chunk((const char*)buffer, bufferSize); | |||
osc_send_lv2_event_transfer(getCustomURIString(atom->type), LV2_ATOM__eventTransfer, chunk.toBase64().constData()); | |||
osc_send_lv2_event_transfer(getOscServerData(), getCustomURIString(atom->type), LV2_ATOM__eventTransfer, chunk.toBase64().constData()); | |||
} | |||
} | |||
@@ -534,7 +545,7 @@ public: | |||
static uint32_t carla_lv2_event_ref(LV2_Event_Callback_Data callback_data, LV2_Event* event) | |||
{ | |||
qDebug("carla_lv2_event_ref(%p, %p)", callback_data, event); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_event_ref(%p, %p)", callback_data, event); | |||
assert(callback_data); | |||
assert(event); | |||
@@ -543,7 +554,7 @@ public: | |||
static uint32_t carla_lv2_event_unref(LV2_Event_Callback_Data callback_data, LV2_Event* event) | |||
{ | |||
qDebug("carla_lv2_event_unref(%p, %p)", callback_data, event); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_event_unref(%p, %p)", callback_data, event); | |||
assert(callback_data); | |||
assert(event); | |||
@@ -554,7 +565,7 @@ public: | |||
static int carla_lv2_log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...) | |||
{ | |||
qDebug("carla_lv2_log_printf(%p, %i, %s, ...)", handle, type, fmt); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_log_printf(%p, %i, %s, ...)", handle, type, fmt); | |||
assert(handle); | |||
assert(type > 0); | |||
@@ -573,7 +584,7 @@ public: | |||
static int carla_lv2_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list ap) | |||
{ | |||
qDebug("carla_lv2_log_vprintf(%p, %i, %s, ...)", handle, type, fmt); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_log_vprintf(%p, %i, %s, ...)", handle, type, fmt); | |||
assert(handle); | |||
assert(type > 0); | |||
@@ -613,18 +624,18 @@ public: | |||
static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index) | |||
{ | |||
qDebug("carla_lv2_program_changed(%p, %i)", handle, index); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_program_changed(%p, %i)", handle, index); | |||
assert(handle); | |||
Lv2UiData* lv2ui = (Lv2UiData*)handle; | |||
lv2ui->handleProgramChanged(index); | |||
CarlaBridgeLv2Client* const client = (CarlaBridgeLv2Client*)handle; | |||
client->handleProgramChanged(index); | |||
} | |||
// ----------------- State Feature --------------------------------------------------- | |||
static char* carla_lv2_state_make_path(LV2_State_Make_Path_Handle handle, const char* path) | |||
{ | |||
qDebug("carla_lv2_state_make_path(%p, %p)", handle, path); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_state_make_path(%p, %p)", handle, path); | |||
assert(handle); | |||
assert(path); | |||
@@ -635,7 +646,7 @@ public: | |||
static char* carla_lv2_state_map_abstract_path(LV2_State_Map_Path_Handle handle, const char* absolute_path) | |||
{ | |||
qDebug("carla_lv2_state_map_abstract_path(%p, %p)", handle, absolute_path); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_state_map_abstract_path(%p, %p)", handle, absolute_path); | |||
assert(handle); | |||
assert(absolute_path); | |||
@@ -645,7 +656,7 @@ public: | |||
static char* carla_lv2_state_map_absolute_path(LV2_State_Map_Path_Handle handle, const char* abstract_path) | |||
{ | |||
qDebug("carla_lv2_state_map_absolute_path(%p, %p)", handle, abstract_path); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_state_map_absolute_path(%p, %p)", handle, abstract_path); | |||
assert(handle); | |||
assert(abstract_path); | |||
@@ -657,7 +668,7 @@ public: | |||
static uint32_t carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char* map, const char* uri) | |||
{ | |||
qDebug("carla_lv2_uri_to_id(%p, %s, %s)", data, map, uri); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_uri_to_id(%p, %s, %s)", data, map, uri); | |||
return carla_lv2_urid_map(data, uri); | |||
} | |||
@@ -665,7 +676,7 @@ public: | |||
static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri) | |||
{ | |||
qDebug("carla_lv2_urid_map(%p, %s)", handle, uri); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_urid_map(%p, %s)", handle, uri); | |||
assert(handle); | |||
assert(uri); | |||
@@ -698,13 +709,13 @@ public: | |||
return CARLA_URI_MAP_ID_MIDI_EVENT; | |||
// Custom types | |||
Lv2UiData* lv2ui = (Lv2UiData*)handle; | |||
return lv2ui->getCustomURID(uri); | |||
CarlaBridgeLv2Client* const client = (CarlaBridgeLv2Client*)handle; | |||
return client->getCustomURID(uri); | |||
} | |||
static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) | |||
{ | |||
qDebug("carla_lv2_urid_unmap(%p, %i)", handle, urid); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_urid_unmap(%p, %i)", handle, urid); | |||
assert(handle); | |||
assert(urid > 0); | |||
@@ -737,19 +748,19 @@ public: | |||
return LV2_MIDI__MidiEvent; | |||
// Custom types | |||
Lv2UiData* lv2ui = (Lv2UiData*)handle; | |||
return lv2ui->getCustomURIString(urid); | |||
CarlaBridgeLv2Client* const client = (CarlaBridgeLv2Client*)handle; | |||
return client->getCustomURIString(urid); | |||
} | |||
// ----------------- UI Port-Map Feature --------------------------------------------- | |||
static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol) | |||
{ | |||
qDebug("carla_lv2_ui_port_map(%p, %s)", handle, symbol); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_ui_port_map(%p, %s)", handle, symbol); | |||
assert(handle); | |||
Lv2UiData* lv2ui = (Lv2UiData*)handle; | |||
return lv2ui->handleUiPortMap(symbol); | |||
CarlaBridgeLv2Client* const client = (CarlaBridgeLv2Client*)handle; | |||
return client->handleUiPortMap(symbol); | |||
} | |||
@@ -757,22 +768,22 @@ public: | |||
static int carla_lv2_ui_resize(LV2UI_Feature_Handle handle, int width, int height) | |||
{ | |||
qDebug("carla_lv2_ui_resize(%p, %i, %i)", handle, width, height); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_ui_resize(%p, %i, %i)", handle, width, height); | |||
assert(handle); | |||
Lv2UiData* lv2ui = (Lv2UiData*)handle; | |||
return lv2ui->handleUiResize(width, height); | |||
CarlaBridgeLv2Client* const client = (CarlaBridgeLv2Client*)handle; | |||
return client->handleUiResize(width, height); | |||
} | |||
// ----------------- UI Extension ------------------------------------------ | |||
static void carla_lv2_ui_write_function(LV2UI_Controller controller, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer) | |||
{ | |||
qDebug("carla_lv2_ui_write_function(%p, %i, %i, %i, %p)", controller, port_index, buffer_size, format, buffer); | |||
qDebug("CarlaBridgeLv2Client::carla_lv2_ui_write_function(%p, %i, %i, %i, %p)", controller, port_index, buffer_size, format, buffer); | |||
assert(controller); | |||
Lv2UiData* lv2ui = (Lv2UiData*)controller; | |||
lv2ui->handleUiWrite(port_index, buffer_size, format, buffer); | |||
CarlaBridgeLv2Client* const client = (CarlaBridgeLv2Client*)controller; | |||
client->handleUiWrite(port_index, buffer_size, format, buffer); | |||
} | |||
private: | |||
@@ -794,15 +805,44 @@ private: | |||
std::vector<const char*> customURIDs; | |||
}; | |||
int osc_handle_lv2_event_transfer(lo_arg** argv) | |||
int CarlaBridgeOsc::handle_lv2_atom_transfer(CARLA_BRIDGE_OSC_HANDLE_ARGS) | |||
{ | |||
qDebug("CarlaBridgeOsc::handle_lv2_atom_transfer()"); | |||
//CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "ii"); | |||
if (! client) | |||
return 1; | |||
Q_UNUSED(argc); | |||
Q_UNUSED(argv); | |||
Q_UNUSED(types); | |||
CarlaBridgeLv2Client* const lv2client = (CarlaBridgeLv2Client*)client; | |||
lv2client->handleAtomTransfer(); | |||
return 0; | |||
} | |||
int CarlaBridgeOsc::handle_lv2_event_transfer(CARLA_BRIDGE_OSC_HANDLE_ARGS) | |||
{ | |||
qDebug("CarlaBridgeOsc::handle_lv2_event_transfer()"); | |||
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(3, "sss"); | |||
if (! client) | |||
return 1; | |||
const char* type = (const char*)&argv[0]->s; | |||
const char* key = (const char*)&argv[1]->s; | |||
const char* value = (const char*)&argv[2]->s; | |||
((Lv2UiData*)client)->handleEventTransfer(type, key, value); | |||
CarlaBridgeLv2Client* lv2client = (CarlaBridgeLv2Client*)client; | |||
lv2client->handleEventTransfer(type, key, value); | |||
return 0; | |||
} | |||
CARLA_BRIDGE_END_NAMESPACE | |||
int main(int argc, char* argv[]) | |||
{ | |||
if (argc != 5) | |||
@@ -816,21 +856,24 @@ int main(int argc, char* argv[]) | |||
const char* ui_uri = argv[3]; | |||
const char* ui_title = argv[4]; | |||
using namespace CarlaBridge; | |||
// Init toolkit | |||
toolkit_init(); | |||
CarlaBridgeToolkit* const toolkit = CarlaBridgeToolkit::createNew(ui_title); | |||
toolkit->init(); | |||
// Init LV2-UI | |||
client = new Lv2UiData(ui_title); | |||
CarlaBridgeLv2Client client(toolkit); | |||
// Init OSC | |||
osc_init(osc_url); | |||
client.oscInit(osc_url); | |||
// Load UI | |||
int ret; | |||
if (client->init(plugin_uri, ui_uri)) | |||
if (client.init(plugin_uri, ui_uri)) | |||
{ | |||
toolkit_loop(); | |||
toolkit->exec(&client); | |||
ret = 0; | |||
} | |||
else | |||
@@ -840,18 +883,15 @@ int main(int argc, char* argv[]) | |||
} | |||
// Close OSC | |||
osc_send_exiting(); | |||
osc_close(); | |||
osc_send_exiting(client.getOscServerData()); | |||
client.oscClose(); | |||
// Close LV2-UI | |||
client->close(); | |||
client.close(); | |||
// Close toolkit | |||
if (! ret) | |||
toolkit_quit(); | |||
delete client; | |||
client = nullptr; | |||
toolkit->quit(); | |||
delete toolkit; | |||
return ret; | |||
} |
@@ -1,162 +0,0 @@ | |||
/* | |||
* Carla UI bridge code | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
* | |||
* 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 COPYING file | |||
*/ | |||
#include "carla_bridge.h" | |||
#include "carla_bridge_osc.h" | |||
#include <QtCore/QSettings> | |||
#include <QtCore/QTimer> | |||
#include <QtGui/QApplication> | |||
#include <QtGui/QDialog> | |||
#include <QtGui/QVBoxLayout> | |||
static QDialog* window = nullptr; | |||
#ifdef BRIDGE_LV2_X11 | |||
static QSettings settings("Cadence", "Carla-X11UIs"); | |||
#else | |||
static QSettings settings("Cadence", "Carla-Qt4UIs"); | |||
#endif | |||
// ------------------------------------------------------------------------- | |||
// Static QApplication | |||
static QApplication* app = nullptr; | |||
class MessageChecker : public QTimer | |||
{ | |||
public: | |||
MessageChecker() {} | |||
void timerEvent(QTimerEvent*) | |||
{ | |||
if (client) | |||
client->run_messages(); | |||
} | |||
}; | |||
// ------------------------------------------------------------------------- | |||
void toolkit_init() | |||
{ | |||
static int argc = 0; | |||
static char* argv[] = { nullptr }; | |||
app = new QApplication(argc, argv, true); | |||
} | |||
void toolkit_loop() | |||
{ | |||
if (client->needs_reparent()) | |||
{ | |||
window = (QDialog*)client->get_widget(); | |||
window->resize(10, 10); | |||
} | |||
else | |||
{ | |||
// TODO - window->setCentralWidget(widget); or other simpler method | |||
window = new QDialog(); | |||
window->resize(10, 10); | |||
window->setLayout(new QVBoxLayout(window)); | |||
QWidget* widget = (QWidget*)client->get_widget(); | |||
window->layout()->addWidget(widget); | |||
window->layout()->setContentsMargins(0, 0, 0, 0); | |||
window->adjustSize(); | |||
widget->setParent(window); | |||
widget->show(); | |||
} | |||
MessageChecker checker; | |||
checker.start(50); | |||
QObject::connect(window, SIGNAL(finished(int)), app, SLOT(quit())); | |||
if (! client->is_resizable()) | |||
window->setFixedSize(window->width(), window->height()); | |||
window->setWindowTitle(client->get_title()); | |||
if (settings.contains(QString("%1/pos_x").arg(client->get_title()))) | |||
{ | |||
int pos_x = settings.value(QString("%1/pos_x").arg(client->get_title()), window->x()).toInt(); | |||
int pos_y = settings.value(QString("%1/pos_y").arg(client->get_title()), window->y()).toInt(); | |||
window->move(pos_x, pos_y); | |||
if (client->is_resizable()) | |||
{ | |||
int width = settings.value(QString("%1/width").arg(client->get_title()), window->width()).toInt(); | |||
int height = settings.value(QString("%1/height").arg(client->get_title()), window->height()).toInt(); | |||
window->resize(width, height); | |||
} | |||
} | |||
osc_send_update(); | |||
// Main loop | |||
app->exec(); | |||
} | |||
void toolkit_quit() | |||
{ | |||
if (window) | |||
{ | |||
if (client) | |||
{ | |||
settings.setValue(QString("%1/pos_x").arg(client->get_title()), window->x()); | |||
settings.setValue(QString("%1/pos_y").arg(client->get_title()), window->y()); | |||
settings.setValue(QString("%1/width").arg(client->get_title()), window->width()); | |||
settings.setValue(QString("%1/height").arg(client->get_title()), window->height()); | |||
settings.sync(); | |||
} | |||
window->close(); | |||
delete window; | |||
window = nullptr; | |||
} | |||
if (app) | |||
{ | |||
if (! app->closingDown()) | |||
app->quit(); | |||
delete app; | |||
app = nullptr; | |||
} | |||
} | |||
void toolkit_window_show() | |||
{ | |||
if (window) | |||
window->show(); | |||
} | |||
void toolkit_window_hide() | |||
{ | |||
if (window) | |||
window->hide(); | |||
} | |||
void toolkit_window_resize(int width, int height) | |||
{ | |||
if (client && window) | |||
{ | |||
if (client->is_resizable()) | |||
window->resize(width, height); | |||
else | |||
window->setFixedSize(width, height); | |||
} | |||
} |
@@ -15,31 +15,30 @@ | |||
* For a full copy of the GNU General Public License see the COPYING file | |||
*/ | |||
#include "carla_bridge.h" | |||
#include "carla_bridge_osc.h" | |||
#include "carla_bridge_client.h" | |||
#include "carla_vst.h" | |||
#include "carla_midi.h" | |||
#include "carla_vst_includes.h" | |||
#include <QtGui/QDialog> | |||
ClientData* client = nullptr; | |||
//CARLA_BRIDGE_START_NAMESPACE; | |||
namespace CarlaBridge { | |||
// ------------------------------------------------------------------------- | |||
#define FAKE_SAMPLE_RATE 44100.0 | |||
#define FAKE_BUFFER_SIZE 512 | |||
class VstUiData : public ClientData | |||
class CarlaBridgeVstClient : public CarlaBridgeClient | |||
{ | |||
public: | |||
VstUiData(const char* ui_title) : ClientData(ui_title) | |||
CarlaBridgeVstClient(CarlaBridgeToolkit* const toolkit) : CarlaBridgeClient(toolkit) | |||
{ | |||
effect = nullptr; | |||
widget = new QDialog; | |||
} | |||
~VstUiData() | |||
~CarlaBridgeVstClient() | |||
{ | |||
} | |||
@@ -57,22 +56,20 @@ public: | |||
// ----------------------------------------------------------------- | |||
// get DLL main entry | |||
VST_Function vstfn = (VST_Function)lib_symbol("VSTPluginMain"); | |||
VST_Function vstfn = (VST_Function)libSymbol("VSTPluginMain"); | |||
if (! vstfn) | |||
{ | |||
vstfn = (VST_Function)lib_symbol("main"); | |||
vstfn = (VST_Function)libSymbol("main"); | |||
if (! vstfn) | |||
return false; | |||
} | |||
if (! vstfn) | |||
return false; | |||
// ----------------------------------------------------------------- | |||
// initialize plugin | |||
effect = vstfn(VstHostCallback); | |||
if (! effect || effect->magic != kEffectMagic) | |||
if ((! effect) || effect->magic != kEffectMagic) | |||
return false; | |||
// ----------------------------------------------------------------- | |||
@@ -120,46 +117,56 @@ public: | |||
// --------------------------------------------------------------------- | |||
// processing | |||
void set_parameter(int32_t rindex, double value) | |||
void setParameter(const int32_t rindex, const double value) | |||
{ | |||
if (effect) | |||
effect->setParameter(effect, rindex, value); | |||
} | |||
void set_program(uint32_t index) | |||
void setProgram(const uint32_t index) | |||
{ | |||
if (effect) | |||
effect->dispatcher(effect, effSetProgram, 0, index, nullptr, 0.0f); | |||
} | |||
void set_midi_program(uint32_t, uint32_t) {} | |||
void note_on(uint8_t, uint8_t) {} | |||
void note_off(uint8_t) {} | |||
void setMidiProgram(uint32_t, uint32_t) | |||
{ | |||
} | |||
void noteOn(uint8_t, uint8_t) | |||
{ | |||
} | |||
void noteOff(uint8_t) | |||
{ | |||
} | |||
// --------------------------------------------------------------------- | |||
// gui | |||
void* get_widget() const | |||
void* getWidget() const | |||
{ | |||
return widget; | |||
} | |||
bool is_resizable() const | |||
bool isResizable() const | |||
{ | |||
return false; | |||
} | |||
bool needs_reparent() const | |||
bool needsReparent() const | |||
{ | |||
return true; | |||
} | |||
// --------------------------------------------------------------------- | |||
static intptr_t VstHostCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | |||
{ | |||
switch (opcode) | |||
{ | |||
case audioMasterAutomate: | |||
osc_send_control(index, opt); | |||
//osc_send_control(index, opt); | |||
break; | |||
case audioMasterVersion: | |||
@@ -180,6 +187,7 @@ public: | |||
return (intptr_t)&timeInfo; | |||
case audioMasterProcessEvents: | |||
#if 0 | |||
if (client && ptr) | |||
{ | |||
const VstEvents* const events = (VstEvents*)ptr; | |||
@@ -200,7 +208,7 @@ public: | |||
} | |||
else | |||
qDebug("VstHostCallback:audioMasterProcessEvents - Some MIDI Out events were ignored"); | |||
#endif | |||
break; | |||
#if ! VST_FORCE_DEPRECATED | |||
@@ -210,8 +218,8 @@ public: | |||
#endif | |||
case audioMasterSizeWindow: | |||
if (client) | |||
client->queque_message(BRIDGE_MESSAGE_RESIZE_GUI, index, value, 0.0f); | |||
//if (client) | |||
// client->queque_message(BRIDGE_MESSAGE_RESIZE_GUI, index, value, 0.0f); | |||
return 1; | |||
case audioMasterGetSampleRate: | |||
@@ -300,6 +308,8 @@ private: | |||
QDialog* widget; | |||
}; | |||
CARLA_BRIDGE_END_NAMESPACE | |||
int main(int argc, char* argv[]) | |||
{ | |||
if (argc != 4) | |||
@@ -312,21 +322,24 @@ int main(int argc, char* argv[]) | |||
const char* binary = argv[2]; | |||
const char* ui_title = argv[3]; | |||
using namespace CarlaBridge; | |||
// Init toolkit | |||
toolkit_init(); | |||
CarlaBridgeToolkit* const toolkit = CarlaBridgeToolkit::createNew(ui_title); | |||
toolkit->init(); | |||
// Init VST-UI | |||
client = new VstUiData(ui_title); | |||
CarlaBridgeVstClient client(toolkit); | |||
// Init OSC | |||
osc_init(osc_url); | |||
client.oscInit(osc_url); | |||
// Load UI | |||
int ret; | |||
if (client->init(binary, nullptr)) | |||
if (client.init(binary, nullptr)) | |||
{ | |||
toolkit_loop(); | |||
toolkit->exec(&client); | |||
ret = 0; | |||
} | |||
else | |||
@@ -336,18 +349,15 @@ int main(int argc, char* argv[]) | |||
} | |||
// Close OSC | |||
osc_send_exiting(); | |||
osc_close(); | |||
osc_send_exiting(client.getOscServerData()); | |||
client.oscClose(); | |||
// Close VST-UI | |||
client->close(); | |||
client.close(); | |||
// Close toolkit | |||
if (! ret) | |||
toolkit_quit(); | |||
delete client; | |||
client = nullptr; | |||
toolkit->quit(); | |||
delete toolkit; | |||
return ret; | |||
} |
@@ -12,25 +12,26 @@ VERSION = 0.5.0 | |||
SOURCES = \ | |||
../carla_bridge_osc.cpp \ | |||
../carla_bridge_ui-lv2.cpp \ | |||
../carla_bridge_ui-gtk2.cpp | |||
../carla_bridge_toolkit-gtk2.cpp | |||
HEADERS = \ | |||
../carla_bridge.h \ | |||
../carla_bridge_client.h \ | |||
../carla_bridge_osc.h \ | |||
../carla_bridge_toolkit.h \ | |||
../../carla-includes/carla_includes.h \ | |||
../../carla-includes/carla_lib_includes.h \ | |||
../../carla-includes/carla_osc_includes.h \ | |||
../../carla-includes/carla_lv2_includes.h \ | |||
../../carla-includes/carla_lv2.h \ | |||
../../carla-includes/carla_midi.h \ | |||
../../carla-includes/lv2_rdf.h | |||
INCLUDEPATH = .. \ | |||
../../carla-backend \ | |||
../../carla-includes | |||
LIBS = \ | |||
../../carla-lilv/carla_lilv.a | |||
DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_GTK2 | |||
DEFINES = DEBUG BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_GTK2 | |||
QMAKE_CXXFLAGS *= -std=c++0x |
@@ -12,23 +12,26 @@ VERSION = 0.5.0 | |||
SOURCES = \ | |||
../carla_bridge_osc.cpp \ | |||
../carla_bridge_ui-lv2.cpp \ | |||
../carla_bridge_ui-qt4.cpp | |||
../carla_bridge_toolkit-qt4.cpp | |||
HEADERS = \ | |||
../carla_bridge.h \ | |||
../carla_bridge_client.h \ | |||
../carla_bridge_osc.h \ | |||
../../carla-backend/carla_midi.h \ | |||
../carla_bridge_toolkit.h \ | |||
../../carla-includes/carla_includes.h \ | |||
../../carla-includes/carla_lib_includes.h \ | |||
../../carla-includes/carla_osc_includes.h \ | |||
../../carla-includes/carla_lv2.h \ | |||
../../carla-includes/carla_midi.h \ | |||
../../carla-includes/lv2_rdf.h | |||
INCLUDEPATH = .. \ | |||
../../carla-backend \ | |||
../../carla-includes | |||
DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_QT4 | |||
LIBS = \ | |||
../../carla-lilv/carla_lilv.a | |||
LIBS = ../../carla-lilv/carla_lilv.a -ldl | |||
DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_QT4 | |||
QMAKE_CXXFLAGS *= -std=c++0x |
@@ -12,23 +12,26 @@ VERSION = 0.5.0 | |||
SOURCES = \ | |||
../carla_bridge_osc.cpp \ | |||
../carla_bridge_ui-lv2.cpp \ | |||
../carla_bridge_ui-qt4.cpp | |||
../carla_bridge_toolkit-qt4.cpp | |||
HEADERS = \ | |||
../carla_bridge.h \ | |||
../carla_bridge_client.h \ | |||
../carla_bridge_osc.h \ | |||
../../carla-backend/carla_midi.h \ | |||
../carla_bridge_toolkit.h \ | |||
../../carla-includes/carla_includes.h \ | |||
../../carla-includes/carla_lib_includes.h \ | |||
../../carla-includes/carla_osc_includes.h \ | |||
../../carla-includes/carla_lv2.h \ | |||
../../carla-includes/carla_midi.h \ | |||
../../carla-includes/lv2_rdf.h | |||
INCLUDEPATH = .. \ | |||
../../carla-backend \ | |||
../../carla-includes | |||
DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_X11 | |||
LIBS = \ | |||
../../carla-lilv/carla_lilv.a | |||
LIBS = ../../carla-lilv/carla_lilv.a -ldl | |||
DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_X11 | |||
QMAKE_CXXFLAGS *= -std=c++0x |
@@ -12,24 +12,22 @@ VERSION = 0.5.0 | |||
SOURCES = \ | |||
../carla_bridge_osc.cpp \ | |||
../carla_bridge_ui-vst.cpp \ | |||
../carla_bridge_ui-qt4.cpp | |||
../carla_bridge_toolkit-qt4.cpp | |||
HEADERS = \ | |||
../carla_bridge.h \ | |||
../carla_bridge_client.h \ | |||
../carla_bridge_osc.h \ | |||
../../carla-backend/carla_midi.h \ | |||
../carla_bridge_toolkit.h \ | |||
../../carla-includes/carla_includes.h \ | |||
../../carla-includes/carla_lib_includes.h \ | |||
../../carla-includes/carla_osc_includes.h \ | |||
../../carla-includes/carla_vst_includes.h | |||
../../carla-includes/carla_vst.h \ | |||
../../carla-includes/carla_midi.h | |||
INCLUDEPATH = .. \ | |||
../../carla-backend \ | |||
../../carla-includes \ | |||
../../carla-includes/vst | |||
../../carla-includes | |||
DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_VST_X11 | |||
LIBS = ../../carla-lilv/carla_lilv.a -ldl | |||
QMAKE_CXXFLAGS *= -std=c++0x |
@@ -8,7 +8,7 @@ CXX ?= g++ | |||
WINECXX ?= wineg++ | |||
STRIP ?= strip | |||
BASE_FLAGS = -O2 -ffast-math -fomit-frame-pointer -fPIC -mtune=generic -msse -Wall -I../carla-includes | |||
BASE_FLAGS = -O2 -ffast-math -fomit-frame-pointer -fPIC -mtune=generic -msse -Wall | |||
BUILD_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS) | |||
BUILD_FLAGS += -I../carla-backend -I../carla-includes $(shell pkg-config --cflags QtCore) | |||
@@ -25,7 +25,7 @@ | |||
#include <lo/lo.h> | |||
struct CarlaOscData { | |||
char* path; | |||
const char* path; | |||
lo_address source; | |||
lo_address target; | |||
}; | |||
@@ -141,7 +141,36 @@ void osc_send_midi(const CarlaOscData* const oscData, const uint8_t buf[4]) | |||
} | |||
} | |||
#ifndef BUILD_BRIDGE | |||
#ifdef BUILD_BRIDGE | |||
static inline | |||
void osc_send_update(const CarlaOscData* const oscData, const char* const url) | |||
{ | |||
qDebug("osc_send_update(%s, %s)", oscData->path, url); | |||
if (oscData->target) | |||
{ | |||
char targetPath[strlen(oscData->path)+8]; | |||
strcpy(targetPath, oscData->path); | |||
strcat(targetPath, "/update"); | |||
lo_send(oscData->target, targetPath, "s", url); | |||
} | |||
} | |||
static inline | |||
void osc_send_exiting(const CarlaOscData* const oscData) | |||
{ | |||
qDebug("osc_send_exiting(%s)", oscData->path); | |||
if (oscData->target) | |||
{ | |||
char targetPath[strlen(oscData->path)+9]; | |||
strcpy(targetPath, oscData->path); | |||
strcat(targetPath, "/exiting"); | |||
lo_send(oscData->target, targetPath, ""); | |||
} | |||
} | |||
#else | |||
static inline | |||
void osc_send_show(const CarlaOscData* const oscData) | |||
{ | |||
@@ -185,4 +214,35 @@ void osc_send_quit(const CarlaOscData* const oscData) | |||
} | |||
#endif | |||
static inline | |||
void osc_send_lv2_atom_transfer(const CarlaOscData* const oscData /* TODO */) | |||
{ | |||
qDebug("osc_send_lv2_atom_transfer(%s)", oscData->path); | |||
if (oscData->target) | |||
{ | |||
char targetPath[strlen(oscData->path)+19]; | |||
strcpy(targetPath, oscData->path); | |||
strcat(targetPath, "/lv2_atom_transfer"); | |||
lo_send(oscData->target, targetPath, ""); | |||
} | |||
} | |||
static inline | |||
void osc_send_lv2_event_transfer(const CarlaOscData* const oscData, const char* const type, const char* const key, const char* const value) | |||
{ | |||
qDebug("osc_send_lv2_event_transfer(%s, %s, %s, %s)", oscData->path, type, key, value); | |||
assert(type); | |||
assert(key); | |||
assert(value); | |||
if (oscData->target) | |||
{ | |||
char targetPath[strlen(oscData->path)+20]; | |||
strcpy(targetPath, oscData->path); | |||
strcat(targetPath, "/lv2_event_transfer"); | |||
lo_send(oscData->target, targetPath, "sss", type, key, value); | |||
} | |||
} | |||
#endif // CARLA_OSC_INCLUDES_H |
@@ -3522,8 +3522,8 @@ if __name__ == '__main__': | |||
dname = cString(CarlaHost.get_engine_driver_name(i)) | |||
print("%i - %s" % (i, dname)) | |||
#if not CarlaHost.engine_init("JACK", "Carla"): | |||
if not CarlaHost.engine_init("PulseAudio", "Carla"): | |||
if not CarlaHost.engine_init("JACK", "Carla"): | |||
#if not CarlaHost.engine_init("PulseAudio", "Carla"): | |||
CustomMessageBox(None, QMessageBox.Critical, "Error", "Could not connect to Audio backend, possible reasons:", | |||
cString(CarlaHost.get_last_error()), QMessageBox.Ok, QMessageBox.Ok) | |||
sys.exit(1) | |||