@@ -15,55 +15,80 @@ | |||||
* For a full copy of the GNU General Public License see the COPYING file | * For a full copy of the GNU General Public License see the COPYING file | ||||
*/ | */ | ||||
#include "carla_bridge_osc.h" | |||||
#include "carla_bridge_ui.h" | #include "carla_bridge_ui.h" | ||||
#include "../carla-bridge/carla_osc.h" | |||||
#ifdef BRIDGE_LV2_X11 | |||||
#error X11 UI uses Qt4 | |||||
#endif | |||||
#include <gtk/gtk.h> | #include <gtk/gtk.h> | ||||
#include <QtCore/QSettings> | #include <QtCore/QSettings> | ||||
static GtkWidget* window; | |||||
static GtkWidget* window = nullptr; | |||||
static QSettings settings("Cadence", "Carla-UIs"); | |||||
// ------------------------------------------------------------------------- | |||||
gint last_x, last_y, last_width, last_height; | |||||
void save_window_settings() | |||||
{ | |||||
settings.setValue(QString("%1/pos_x").arg(ui->get_title()), last_x); | |||||
settings.setValue(QString("%1/pos_y").arg(ui->get_title()), last_y); | |||||
settings.setValue(QString("%1/width").arg(ui->get_title()), last_width); | |||||
settings.setValue(QString("%1/height").arg(ui->get_title()), last_height); | |||||
} | |||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
gboolean gtk_ui_recheck(void*) | gboolean gtk_ui_recheck(void*) | ||||
{ | { | ||||
gtk_window_get_position(GTK_WINDOW(window), &last_x, &last_y); | |||||
gtk_window_get_size(GTK_WINDOW(window), &last_width, &last_height); | |||||
return ui->run_messages(); | return ui->run_messages(); | ||||
} | } | ||||
void gtk_ui_destroy(GtkWidget*, void*) | void gtk_ui_destroy(GtkWidget*, void*) | ||||
{ | { | ||||
window = nullptr; | |||||
gtk_main_quit(); | |||||
toolkit_quit(); | |||||
} | } | ||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
void toolkit_init() | void toolkit_init() | ||||
{ | { | ||||
int argc = 0; | |||||
char** argv = nullptr; | |||||
static int argc = 0; | |||||
static char** argv = { nullptr }; | |||||
gtk_init(&argc, &argv); | gtk_init(&argc, &argv); | ||||
} | } | ||||
void toolkit_loop(const char* ui_title, bool reparent) | |||||
void toolkit_loop() | |||||
{ | { | ||||
if (reparent) | |||||
{ | |||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |||||
gtk_container_add(GTK_CONTAINER(window), (GtkWidget*)ui->get_widget()); | |||||
} | |||||
else | |||||
{ | |||||
window = (GtkWidget*)ui->get_widget(); | |||||
} | |||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |||||
gtk_container_add(GTK_CONTAINER(window), (GtkWidget*)ui->get_widget()); | |||||
g_timeout_add(50, gtk_ui_recheck, nullptr); | g_timeout_add(50, gtk_ui_recheck, nullptr); | ||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_ui_destroy), nullptr); | g_signal_connect(window, "destroy", G_CALLBACK(gtk_ui_destroy), nullptr); | ||||
gtk_window_get_position(GTK_WINDOW(window), &last_x, &last_y); | |||||
gtk_window_get_size(GTK_WINDOW(window), &last_width, &last_height); | |||||
gtk_window_set_resizable(GTK_WINDOW(window), ui->is_resizable()); | gtk_window_set_resizable(GTK_WINDOW(window), ui->is_resizable()); | ||||
gtk_window_set_title(GTK_WINDOW(window), ui_title); | |||||
gtk_window_set_title(GTK_WINDOW(window), ui->get_title()); | |||||
if (settings.contains(QString("%1/pos_x").arg(ui->get_title()))) | |||||
{ | |||||
last_x = settings.value(QString("%1/pos_x").arg(ui->get_title()), last_x).toInt(); | |||||
last_y = settings.value(QString("%1/pos_y").arg(ui->get_title()), last_y).toInt(); | |||||
last_width = settings.value(QString("%1/width").arg(ui->get_title()), last_width).toInt(); | |||||
last_height = settings.value(QString("%1/height").arg(ui->get_title()), last_height).toInt(); | |||||
gtk_window_move(GTK_WINDOW(window), last_x, last_y); | |||||
gtk_window_resize(GTK_WINDOW(window), last_width, last_height); | |||||
} | |||||
osc_send_update(); | |||||
osc_send_update(nullptr); | |||||
// Main loop | // Main loop | ||||
gtk_main(); | gtk_main(); | ||||
@@ -73,22 +98,28 @@ void toolkit_quit() | |||||
{ | { | ||||
if (window) | if (window) | ||||
{ | { | ||||
save_window_settings(); | |||||
gtk_widget_destroy(window); | gtk_widget_destroy(window); | ||||
gtk_main_quit(); | gtk_main_quit(); | ||||
} | } | ||||
window = nullptr; | |||||
} | } | ||||
void toolkit_window_show() | void toolkit_window_show() | ||||
{ | { | ||||
gtk_widget_show_all(window); | |||||
if (window) | |||||
gtk_widget_show_all(window); | |||||
} | } | ||||
void toolkit_window_hide() | void toolkit_window_hide() | ||||
{ | { | ||||
gtk_widget_hide_all(window); | |||||
if (window) | |||||
gtk_widget_hide_all(window); | |||||
} | } | ||||
void toolkit_window_resize(int width, int height) | void toolkit_window_resize(int width, int height) | ||||
{ | { | ||||
gtk_window_resize(GTK_WINDOW(window), width, height); | |||||
if (window) | |||||
gtk_window_resize(GTK_WINDOW(window), width, height); | |||||
} | } |
@@ -15,19 +15,14 @@ | |||||
* For a full copy of the GNU General Public License see the COPYING file | * For a full copy of the GNU General Public License see the COPYING file | ||||
*/ | */ | ||||
#include "carla_bridge_osc.h" | |||||
#include "carla_bridge_ui.h" | #include "carla_bridge_ui.h" | ||||
#include "carla_osc.h" | |||||
#include "carla_midi.h" | |||||
#include "lv2/lv2.h" | |||||
#include "lv2/atom.h" | |||||
#include "lv2/event.h" | |||||
#include "lv2/uri-map.h" | |||||
#include "lv2/urid.h" | |||||
#include "lv2/ui.h" | |||||
#include <cstring> | |||||
#include "lv2_rdf.h" | |||||
#ifdef BRIDGE_LV2_X11 | #ifdef BRIDGE_LV2_X11 | ||||
// FIXME, use x11 something | |||||
#include <QtGui/QDialog> | #include <QtGui/QDialog> | ||||
#endif | #endif | ||||
@@ -36,119 +31,76 @@ UiData* ui = nullptr; | |||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
// feature ids | // feature ids | ||||
const uint32_t lv2_feature_id_uri_map = 0; | |||||
const uint32_t lv2_feature_id_urid_map = 1; | |||||
const uint32_t lv2_feature_id_urid_unmap = 2; | |||||
const uint32_t lv2_feature_id_event = 3; | |||||
const uint32_t lv2_feature_id_ui_resize = 4; | |||||
const uint32_t lv2_feature_id_ui_parent = 5; | |||||
const uint32_t lv2_feature_count = 6; | |||||
const uint32_t lv2_feature_id_event = 0; | |||||
const uint32_t lv2_feature_id_logs = 1; | |||||
const uint32_t lv2_feature_id_programs = 2; | |||||
const uint32_t lv2_feature_id_state_make_path = 3; | |||||
const uint32_t lv2_feature_id_state_map_path = 4; | |||||
const uint32_t lv2_feature_id_uri_map = 5; | |||||
const uint32_t lv2_feature_id_urid_map = 6; | |||||
const uint32_t lv2_feature_id_urid_unmap = 7; | |||||
const uint32_t lv2_feature_id_ui_parent = 8; | |||||
const uint32_t lv2_feature_id_ui_port_map = 9; | |||||
const uint32_t lv2_feature_id_ui_resize = 10; | |||||
const uint32_t lv2_feature_count = 11; | |||||
// pre-set uri[d] map ids | // pre-set uri[d] map ids | ||||
const uint32_t CARLA_URI_MAP_ID_NULL = 0; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_STRING = 1; | |||||
const uint32_t CARLA_URI_MAP_ID_EVENT_MIDI = 2; | |||||
const uint32_t CARLA_URI_MAP_ID_EVENT_TIME = 3; | |||||
const uint32_t CARLA_URI_MAP_ID_COUNT = 4; | |||||
// ----------------- URI-Map Feature --------------------------------------- | |||||
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); | |||||
if (map && strcmp(map, LV2_EVENT_URI) == 0) | |||||
{ | |||||
// Event types | |||||
if (strcmp(uri, "http://lv2plug.in/ns/ext/midi#MidiEvent") == 0) | |||||
return CARLA_URI_MAP_ID_EVENT_MIDI; | |||||
else if (strcmp(uri, "http://lv2plug.in/ns/ext/time#Position") == 0) | |||||
return CARLA_URI_MAP_ID_EVENT_TIME; | |||||
} | |||||
else if (strcmp(uri, LV2_ATOM__String) == 0) | |||||
{ | |||||
return CARLA_URI_MAP_ID_ATOM_STRING; | |||||
} | |||||
return CARLA_URI_MAP_ID_NULL; | |||||
} | |||||
// ----------------- URID Feature ------------------------------------------ | |||||
static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri) | |||||
{ | |||||
qDebug("carla_lv2_urid_map(%p, %s)", handle, uri); | |||||
if (strcmp(uri, "http://lv2plug.in/ns/ext/midi#MidiEvent") == 0) | |||||
return CARLA_URI_MAP_ID_EVENT_MIDI; | |||||
else if (strcmp(uri, "http://lv2plug.in/ns/ext/time#Position") == 0) | |||||
return CARLA_URI_MAP_ID_EVENT_TIME; | |||||
else if (strcmp(uri, LV2_ATOM__String) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_STRING; | |||||
return CARLA_URI_MAP_ID_NULL; | |||||
} | |||||
static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) | |||||
{ | |||||
qDebug("carla_lv2_urid_unmap(%p, %i)", handle, urid); | |||||
if (urid == CARLA_URI_MAP_ID_EVENT_MIDI) | |||||
return "http://lv2plug.in/ns/ext/midi#MidiEvent"; | |||||
else if (urid == CARLA_URI_MAP_ID_EVENT_TIME) | |||||
return "http://lv2plug.in/ns/ext/time#Position"; | |||||
else if (urid == CARLA_URI_MAP_ID_ATOM_STRING) | |||||
return LV2_ATOM__String; | |||||
return nullptr; | |||||
} | |||||
// ----------------- UI Resize Feature ------------------------------------- | |||||
static int carla_lv2_ui_resize(LV2UI_Feature_Handle data, int width, int height) | |||||
{ | |||||
qDebug("carla_lv2_ui_resized(%p, %i, %i)", data, width, height); | |||||
if (data) | |||||
{ | |||||
UiData* ui = (UiData*)data; | |||||
ui->queque_message(BRIDGE_MESSAGE_RESIZE_GUI, width, height, 0.0); | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
// ----------------- 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); | |||||
if (controller) | |||||
{ | |||||
//UiData* ui = (UiData*)controller; | |||||
if (format == 0 && buffer_size == sizeof(float)) | |||||
{ | |||||
float value = *(float*)buffer; | |||||
osc_send_control(nullptr, port_index, value); | |||||
} | |||||
} | |||||
} | |||||
const uint32_t CARLA_URI_MAP_ID_NULL = 0; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_CHUNK = 1; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_PATH = 2; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_SEQUENCE = 3; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_STRING = 4; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_ERROR = 5; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_NOTE = 6; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_TRACE = 7; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_WARNING = 8; | |||||
const uint32_t CARLA_URI_MAP_ID_MIDI_EVENT = 9; | |||||
const uint32_t CARLA_URI_MAP_ID_COUNT = 10; | |||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
class Lv2UiData : public UiData | class Lv2UiData : public UiData | ||||
{ | { | ||||
public: | public: | ||||
Lv2UiData() : UiData() | |||||
Lv2UiData(const char* ui_title) : UiData(ui_title) | |||||
{ | { | ||||
handle = nullptr; | handle = nullptr; | ||||
widget = nullptr; | widget = nullptr; | ||||
descriptor = nullptr; | descriptor = nullptr; | ||||
rdf_descriptor = nullptr; | |||||
rdf_ui_descriptor = nullptr; | |||||
programs = nullptr; | |||||
#ifdef BRIDGE_LV2_X11 | #ifdef BRIDGE_LV2_X11 | ||||
x11_widget = new QDialog(nullptr); | |||||
x11_widget = new QDialog; | |||||
#endif | #endif | ||||
// Initialize features | // Initialize features | ||||
LV2_Event_Feature* Event_Feature = new LV2_Event_Feature; | |||||
Event_Feature->callback_data = this; | |||||
Event_Feature->lv2_event_ref = carla_lv2_event_ref; | |||||
Event_Feature->lv2_event_unref = carla_lv2_event_unref; | |||||
LV2_Log_Log* Log_Feature = new LV2_Log_Log; | |||||
Log_Feature->handle = this; | |||||
Log_Feature->printf = carla_lv2_log_printf; | |||||
Log_Feature->vprintf = carla_lv2_log_vprintf; | |||||
LV2_Programs_Host* Programs_Feature = new LV2_Programs_Host; | |||||
Programs_Feature->handle = this; | |||||
Programs_Feature->program_changed = carla_lv2_program_changed; | |||||
LV2_State_Make_Path* State_MakePath_Feature = new LV2_State_Make_Path; | |||||
State_MakePath_Feature->handle = this; | |||||
State_MakePath_Feature->path = carla_lv2_state_make_path; | |||||
LV2_State_Map_Path* State_MapPath_Feature = new LV2_State_Map_Path; | |||||
State_MapPath_Feature->handle = this; | |||||
State_MapPath_Feature->abstract_path = carla_lv2_state_map_abstract_path; | |||||
State_MapPath_Feature->absolute_path = carla_lv2_state_map_absolute_path; | |||||
LV2_URI_Map_Feature* URI_Map_Feature = new LV2_URI_Map_Feature; | LV2_URI_Map_Feature* URI_Map_Feature = new LV2_URI_Map_Feature; | ||||
URI_Map_Feature->callback_data = this; | URI_Map_Feature->callback_data = this; | ||||
URI_Map_Feature->uri_to_id = carla_lv2_uri_to_id; | URI_Map_Feature->uri_to_id = carla_lv2_uri_to_id; | ||||
@@ -161,54 +113,74 @@ public: | |||||
URID_Unmap_Feature->handle = this; | URID_Unmap_Feature->handle = this; | ||||
URID_Unmap_Feature->unmap = carla_lv2_urid_unmap; | URID_Unmap_Feature->unmap = carla_lv2_urid_unmap; | ||||
LV2_Event_Feature* Event_Feature = new LV2_Event_Feature; | |||||
Event_Feature->callback_data = this; | |||||
Event_Feature->lv2_event_ref = nullptr; | |||||
Event_Feature->lv2_event_unref = nullptr; | |||||
LV2UI_Port_Map* UI_PortMap_Feature = new LV2UI_Port_Map; | |||||
UI_PortMap_Feature->handle = this; | |||||
UI_PortMap_Feature->port_index = carla_lv2_ui_port_map; | |||||
LV2UI_Resize* UI_Resize_Feature = new LV2UI_Resize; | LV2UI_Resize* UI_Resize_Feature = new LV2UI_Resize; | ||||
UI_Resize_Feature->handle = this; | UI_Resize_Feature->handle = this; | ||||
UI_Resize_Feature->ui_resize = carla_lv2_ui_resize; | UI_Resize_Feature->ui_resize = carla_lv2_ui_resize; | ||||
features[lv2_feature_id_uri_map] = new LV2_Feature; | |||||
features[lv2_feature_id_uri_map]->URI = LV2_URI_MAP_URI; | |||||
features[lv2_feature_id_uri_map]->data = URI_Map_Feature; | |||||
features[lv2_feature_id_event] = new LV2_Feature; | |||||
features[lv2_feature_id_event]->URI = LV2_EVENT_URI; | |||||
features[lv2_feature_id_event]->data = Event_Feature; | |||||
features[lv2_feature_id_urid_map] = new LV2_Feature; | |||||
features[lv2_feature_id_urid_map]->URI = LV2_URID_MAP_URI; | |||||
features[lv2_feature_id_urid_map]->data = URID_Map_Feature; | |||||
features[lv2_feature_id_logs] = new LV2_Feature; | |||||
features[lv2_feature_id_logs]->URI = LV2_LOG__log; | |||||
features[lv2_feature_id_logs]->data = Log_Feature; | |||||
features[lv2_feature_id_urid_unmap] = new LV2_Feature; | |||||
features[lv2_feature_id_urid_unmap]->URI = LV2_URID_UNMAP_URI; | |||||
features[lv2_feature_id_urid_unmap]->data = URID_Unmap_Feature; | |||||
features[lv2_feature_id_programs] = new LV2_Feature; | |||||
features[lv2_feature_id_programs]->URI = LV2_PROGRAMS__Host; | |||||
features[lv2_feature_id_programs]->data = Programs_Feature; | |||||
features[lv2_feature_id_event] = new LV2_Feature; | |||||
features[lv2_feature_id_event]->URI = LV2_EVENT_URI; | |||||
features[lv2_feature_id_event]->data = Event_Feature; | |||||
features[lv2_feature_id_state_make_path] = new LV2_Feature; | |||||
features[lv2_feature_id_state_make_path]->URI = LV2_STATE__makePath; | |||||
features[lv2_feature_id_state_make_path]->data = State_MakePath_Feature; | |||||
features[lv2_feature_id_ui_resize] = new LV2_Feature; | |||||
features[lv2_feature_id_ui_resize]->URI = LV2_UI__resize; | |||||
features[lv2_feature_id_ui_resize]->data = UI_Resize_Feature; | |||||
features[lv2_feature_id_state_map_path] = new LV2_Feature; | |||||
features[lv2_feature_id_state_map_path]->URI = LV2_STATE__mapPath; | |||||
features[lv2_feature_id_state_map_path]->data = State_MapPath_Feature; | |||||
features[lv2_feature_id_uri_map] = new LV2_Feature; | |||||
features[lv2_feature_id_uri_map]->URI = LV2_URI_MAP_URI; | |||||
features[lv2_feature_id_uri_map]->data = URI_Map_Feature; | |||||
features[lv2_feature_id_urid_map] = new LV2_Feature; | |||||
features[lv2_feature_id_urid_map]->URI = LV2_URID__map; | |||||
features[lv2_feature_id_urid_map]->data = URID_Map_Feature; | |||||
features[lv2_feature_id_urid_unmap] = new LV2_Feature; | |||||
features[lv2_feature_id_urid_unmap]->URI = LV2_URID__unmap; | |||||
features[lv2_feature_id_urid_unmap]->data = URID_Unmap_Feature; | |||||
features[lv2_feature_id_ui_parent] = new LV2_Feature; | |||||
features[lv2_feature_id_ui_parent]->URI = LV2_UI__parent; | |||||
#ifdef BRIDGE_LV2_X11 | #ifdef BRIDGE_LV2_X11 | ||||
features[lv2_feature_id_ui_parent] = new LV2_Feature; | |||||
features[lv2_feature_id_ui_parent]->URI = LV2_UI__parent; | |||||
features[lv2_feature_id_ui_parent]->data = (void*)x11_widget->winId(); | |||||
features[lv2_feature_id_ui_parent]->data = (void*)x11_widget->winId(); | |||||
#else | #else | ||||
features[lv2_feature_id_ui_parent] = nullptr; | |||||
features[lv2_feature_id_ui_parent]->data = nullptr; | |||||
#endif | #endif | ||||
features[lv2_feature_count] = nullptr; | |||||
features[lv2_feature_id_ui_port_map] = new LV2_Feature; | |||||
features[lv2_feature_id_ui_port_map]->URI = LV2_UI__portMap; | |||||
features[lv2_feature_id_ui_port_map]->data = UI_PortMap_Feature; | |||||
resizable = true; | |||||
features[lv2_feature_id_ui_resize] = new LV2_Feature; | |||||
features[lv2_feature_id_ui_resize]->URI = LV2_UI__resize; | |||||
features[lv2_feature_id_ui_resize]->data = UI_Resize_Feature; | |||||
} | } | ||||
~Lv2UiData() | ~Lv2UiData() | ||||
{ | { | ||||
delete (LV2_Event_Feature*)features[lv2_feature_id_event]->data; | |||||
delete (LV2_Log_Log*)features[lv2_feature_id_logs]->data; | |||||
delete (LV2_Programs_Host*)features[lv2_feature_id_programs]->data; | |||||
delete (LV2_State_Make_Path*)features[lv2_feature_id_state_make_path]->data; | |||||
delete (LV2_State_Map_Path*)features[lv2_feature_id_state_map_path]->data; | |||||
delete (LV2_URI_Map_Feature*)features[lv2_feature_id_uri_map]->data; | delete (LV2_URI_Map_Feature*)features[lv2_feature_id_uri_map]->data; | ||||
delete (LV2_URID_Map*)features[lv2_feature_id_urid_map]->data; | delete (LV2_URID_Map*)features[lv2_feature_id_urid_map]->data; | ||||
delete (LV2_URID_Unmap*)features[lv2_feature_id_urid_unmap]->data; | delete (LV2_URID_Unmap*)features[lv2_feature_id_urid_unmap]->data; | ||||
delete (LV2_Event_Feature*)features[lv2_feature_id_event]->data; | |||||
delete (LV2UI_Port_Map*)features[lv2_feature_id_ui_port_map]->data; | |||||
delete (LV2UI_Resize*)features[lv2_feature_id_ui_resize]->data; | delete (LV2UI_Resize*)features[lv2_feature_id_ui_resize]->data; | ||||
for (uint32_t i=0; i < lv2_feature_count; i++) | for (uint32_t i=0; i < lv2_feature_count; i++) | ||||
@@ -216,50 +188,90 @@ public: | |||||
if (features[i]) | if (features[i]) | ||||
delete features[i]; | delete features[i]; | ||||
} | } | ||||
if (rdf_descriptor) | |||||
lv2_rdf_free(rdf_descriptor); | |||||
#ifdef WANT_X11 | #ifdef WANT_X11 | ||||
//delete x11_widget; | //delete x11_widget; | ||||
#endif | #endif | ||||
} | } | ||||
virtual bool init(const char* plugin_uri, const char* ui_uri, const char* ui_bundle, bool resizable_) | |||||
// --------------------------------------------------------------------- | |||||
// initialization | |||||
bool init(const char* plugin_uri, const char* ui_uri) | |||||
{ | { | ||||
LV2UI_DescriptorFunction ui_descfn = (LV2UI_DescriptorFunction)lib_symbol("lv2ui_descriptor"); | |||||
Lv2World.init(); | |||||
rdf_descriptor = lv2_rdf_new(plugin_uri); | |||||
if (ui_descfn) | |||||
if (rdf_descriptor) | |||||
{ | { | ||||
uint32_t i = 0; | |||||
while ((descriptor = ui_descfn(i++))) | |||||
for (uint32_t i=0; i < rdf_descriptor->UICount; i++) | |||||
{ | { | ||||
if (strcmp(descriptor->URI, ui_uri) == 0) | |||||
if (strcmp(rdf_descriptor->UIs[i].URI, ui_uri) == 0) | |||||
{ | |||||
rdf_ui_descriptor = &rdf_descriptor->UIs[i]; | |||||
break; | break; | ||||
} | |||||
} | } | ||||
if (descriptor) | |||||
if (rdf_ui_descriptor && lib_open(rdf_ui_descriptor->Binary)) | |||||
{ | { | ||||
handle = descriptor->instantiate(descriptor, | |||||
plugin_uri, | |||||
ui_bundle, | |||||
carla_lv2_ui_write_function, | |||||
this, | |||||
&widget, | |||||
features); | |||||
resizable = resizable_; | |||||
return bool(handle); | |||||
LV2UI_DescriptorFunction ui_descfn = (LV2UI_DescriptorFunction)lib_symbol("lv2ui_descriptor"); | |||||
if (ui_descfn) | |||||
{ | |||||
uint32_t i = 0; | |||||
while ((descriptor = ui_descfn(i++))) | |||||
{ | |||||
if (strcmp(descriptor->URI, ui_uri) == 0) | |||||
break; | |||||
} | |||||
if (descriptor) | |||||
{ | |||||
handle = descriptor->instantiate(descriptor, | |||||
plugin_uri, | |||||
rdf_ui_descriptor->Bundle, | |||||
carla_lv2_ui_write_function, | |||||
this, | |||||
&widget, | |||||
features); | |||||
if (handle && descriptor->extension_data) | |||||
{ | |||||
for (uint32_t j=0; j < rdf_ui_descriptor->ExtensionCount; j++) | |||||
{ | |||||
if (strcmp(rdf_ui_descriptor->Extensions[j], LV2_PROGRAMS__UIInterface) == 0) | |||||
{ | |||||
programs = (LV2_Programs_UI_Interface*)descriptor->extension_data(LV2_PROGRAMS__UIInterface); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return bool(handle); | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
virtual void close() | |||||
void close() | |||||
{ | { | ||||
if (handle && descriptor && descriptor->cleanup) | if (handle && descriptor && descriptor->cleanup) | ||||
descriptor->cleanup(handle); | descriptor->cleanup(handle); | ||||
lib_close(); | |||||
} | } | ||||
virtual void update_parameter(int index, double value) | |||||
// --------------------------------------------------------------------- | |||||
// processing | |||||
void set_parameter(int index, double value) | |||||
{ | { | ||||
if (descriptor && descriptor->port_event) | if (descriptor && descriptor->port_event) | ||||
{ | { | ||||
@@ -268,12 +280,44 @@ public: | |||||
} | } | ||||
} | } | ||||
virtual void update_program(int) {} | |||||
virtual void update_midi_program(int, int) {} | |||||
virtual void send_note_on(int, int) {} | |||||
virtual void send_note_off(int) {} | |||||
void set_program(int) {} | |||||
virtual void* get_widget() | |||||
void set_midi_program(int bank, int program) | |||||
{ | |||||
if (programs) | |||||
programs->select_program(handle, bank, program); | |||||
} | |||||
void send_note_on(int, int) {} | |||||
void send_note_off(int) {} | |||||
// --------------------------------------------------------------------- | |||||
// gui | |||||
bool has_parent() const | |||||
{ | |||||
#ifdef BRIDGE_LV2_X11 | |||||
return false; | |||||
#else | |||||
return true; | |||||
#endif | |||||
} | |||||
bool is_resizable() const | |||||
{ | |||||
if (rdf_ui_descriptor) | |||||
{ | |||||
for (uint32_t i=0; i < rdf_ui_descriptor->FeatureCount; i++) | |||||
{ | |||||
if (strcmp(rdf_ui_descriptor->Features[i].URI, LV2_UI__fixedSize) == 0 || strcmp(rdf_ui_descriptor->Features[i].URI, LV2_UI__noUserResize) == 0) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
void* get_widget() const | |||||
{ | { | ||||
#ifdef BRIDGE_LV2_X11 | #ifdef BRIDGE_LV2_X11 | ||||
return x11_widget; | return x11_widget; | ||||
@@ -282,9 +326,248 @@ public: | |||||
#endif | #endif | ||||
} | } | ||||
virtual bool is_resizable() | |||||
// ----------------- Event Feature --------------------------------------------------- | |||||
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); | |||||
return 0; | |||||
} | |||||
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); | |||||
return 0; | |||||
} | |||||
// ----------------- Logs Feature ---------------------------------------------------- | |||||
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); | |||||
char buf[8196]; | |||||
vsprintf(buf, fmt, ap); | |||||
if (buf[0] == 0) | |||||
return 0; | |||||
switch (type) | |||||
{ | |||||
case CARLA_URI_MAP_ID_LOG_ERROR: | |||||
qCritical("%s", buf); | |||||
break; | |||||
case CARLA_URI_MAP_ID_LOG_NOTE: | |||||
printf("%s\n", buf); | |||||
break; | |||||
case CARLA_URI_MAP_ID_LOG_TRACE: | |||||
qDebug("%s", buf); | |||||
break; | |||||
case CARLA_URI_MAP_ID_LOG_WARNING: | |||||
qWarning("%s", buf); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
return strlen(buf); | |||||
} | |||||
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); | |||||
va_list args; | |||||
va_start(args, fmt); | |||||
const int ret = carla_lv2_log_vprintf(handle, type, fmt, args); | |||||
va_end(args); | |||||
return ret; | |||||
} | |||||
// ----------------- Programs Feature ------------------------------------------------ | |||||
static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index) | |||||
{ | |||||
qDebug("Lv2Plugin::carla_lv2_program_changed(%p, %i)", handle, index); | |||||
osc_send_configure(nullptr, "reloadprograms", ""); | |||||
// QString::number(index).toUtf8().constData() | |||||
} | |||||
// ----------------- 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); | |||||
return strdup(path); | |||||
} | |||||
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); | |||||
return strdup(absolute_path); | |||||
} | |||||
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); | |||||
return strdup(abstract_path); | |||||
} | |||||
// ----------------- URI-Map Feature --------------------------------------- | |||||
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); | |||||
// Atom types | |||||
if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_CHUNK; | |||||
else if (strcmp(uri, LV2_ATOM__Path) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_PATH; | |||||
else if (strcmp(uri, LV2_ATOM__Sequence) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_SEQUENCE; | |||||
else if (strcmp(uri, LV2_ATOM__String) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_STRING; | |||||
// Log types | |||||
else if (strcmp(uri, LV2_LOG__Error) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_ERROR; | |||||
else if (strcmp(uri, LV2_LOG__Note) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_NOTE; | |||||
else if (strcmp(uri, LV2_LOG__Trace) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_TRACE; | |||||
else if (strcmp(uri, LV2_LOG__Warning) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_WARNING; | |||||
// Others | |||||
else if (strcmp(uri, LV2_MIDI__MidiEvent) == 0) | |||||
return CARLA_URI_MAP_ID_MIDI_EVENT; | |||||
return CARLA_URI_MAP_ID_NULL; | |||||
} | |||||
// ----------------- URID Feature ------------------------------------------ | |||||
static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri) | |||||
{ | |||||
qDebug("carla_lv2_urid_map(%p, %s)", handle, uri); | |||||
// Atom types | |||||
if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_CHUNK; | |||||
else if (strcmp(uri, LV2_ATOM__Path) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_PATH; | |||||
else if (strcmp(uri, LV2_ATOM__Sequence) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_SEQUENCE; | |||||
else if (strcmp(uri, LV2_ATOM__String) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_STRING; | |||||
// Log types | |||||
else if (strcmp(uri, LV2_LOG__Error) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_ERROR; | |||||
else if (strcmp(uri, LV2_LOG__Note) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_NOTE; | |||||
else if (strcmp(uri, LV2_LOG__Trace) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_TRACE; | |||||
else if (strcmp(uri, LV2_LOG__Warning) == 0) | |||||
return CARLA_URI_MAP_ID_LOG_WARNING; | |||||
// Others | |||||
else if (strcmp(uri, LV2_MIDI__MidiEvent) == 0) | |||||
return CARLA_URI_MAP_ID_MIDI_EVENT; | |||||
return CARLA_URI_MAP_ID_NULL; | |||||
} | |||||
static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) | |||||
{ | |||||
qDebug("carla_lv2_urid_unmap(%p, %i)", handle, urid); | |||||
// Atom types | |||||
if (urid == CARLA_URI_MAP_ID_ATOM_CHUNK) | |||||
return LV2_ATOM__Chunk; | |||||
else if (urid == CARLA_URI_MAP_ID_ATOM_PATH) | |||||
return LV2_ATOM__Path; | |||||
else if (urid == CARLA_URI_MAP_ID_ATOM_SEQUENCE) | |||||
return LV2_ATOM__Sequence; | |||||
else if (urid == CARLA_URI_MAP_ID_ATOM_STRING) | |||||
return LV2_ATOM__String; | |||||
// Log types | |||||
else if (urid == CARLA_URI_MAP_ID_LOG_ERROR) | |||||
return LV2_LOG__Error; | |||||
else if (urid == CARLA_URI_MAP_ID_LOG_NOTE) | |||||
return LV2_LOG__Note; | |||||
else if (urid == CARLA_URI_MAP_ID_LOG_TRACE) | |||||
return LV2_LOG__Trace; | |||||
else if (urid == CARLA_URI_MAP_ID_LOG_WARNING) | |||||
return LV2_LOG__Warning; | |||||
// Others | |||||
else if (urid == CARLA_URI_MAP_ID_MIDI_EVENT) | |||||
return LV2_MIDI__MidiEvent; | |||||
return nullptr; | |||||
} | |||||
// ----------------- UI Port-Map Feature --------------------------------------------- | |||||
static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol) | |||||
{ | { | ||||
return resizable; | |||||
qDebug("Lv2Plugin::carla_lv2_ui_port_map(%p, %s)", handle, symbol); | |||||
if (handle) | |||||
{ | |||||
Lv2UiData* lv2ui = (Lv2UiData*)handle; | |||||
for (uint32_t i=0; i < lv2ui->rdf_descriptor->PortCount; i++) | |||||
{ | |||||
if (strcmp(lv2ui->rdf_descriptor->Ports[i].Symbol, symbol) == 0) | |||||
return i; | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
// ----------------- UI Resize Feature ------------------------------------- | |||||
static int carla_lv2_ui_resize(LV2UI_Feature_Handle data, int width, int height) | |||||
{ | |||||
qDebug("carla_lv2_ui_resized(%p, %i, %i)", data, width, height); | |||||
if (data) | |||||
{ | |||||
Lv2UiData* lv2ui = (Lv2UiData*)data; | |||||
lv2ui->queque_message(BRIDGE_MESSAGE_RESIZE_GUI, width, height, 0.0); | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
// ----------------- 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); | |||||
if (controller) | |||||
{ | |||||
if (format == 0) | |||||
{ | |||||
if (buffer_size == sizeof(float)) | |||||
{ | |||||
float value = *(float*)buffer; | |||||
osc_send_control(nullptr, port_index, value); | |||||
} | |||||
} | |||||
else if (format == CARLA_URI_MAP_ID_MIDI_EVENT) | |||||
{ | |||||
const uint8_t* data = (const uint8_t*)buffer; | |||||
uint8_t status = data[0]; | |||||
// Fix bad note-off | |||||
if (MIDI_IS_STATUS_NOTE_ON(status) && data[2] == 0) | |||||
status -= 0x10; | |||||
uint8_t midi_buf[4] = { 0, status, data[2], data[3] }; | |||||
osc_send_midi(nullptr, midi_buf); | |||||
} | |||||
} | |||||
} | } | ||||
private: | private: | ||||
@@ -292,7 +575,11 @@ private: | |||||
LV2UI_Widget widget; | LV2UI_Widget widget; | ||||
const LV2UI_Descriptor* descriptor; | const LV2UI_Descriptor* descriptor; | ||||
LV2_Feature* features[lv2_feature_count+1]; | LV2_Feature* features[lv2_feature_count+1]; | ||||
bool resizable; | |||||
const LV2_RDF_Descriptor* rdf_descriptor; | |||||
const LV2_RDF_UI* rdf_ui_descriptor; | |||||
const LV2_Programs_UI_Interface* programs; | |||||
#ifdef BRIDGE_LV2_X11 | #ifdef BRIDGE_LV2_X11 | ||||
QDialog* x11_widget; | QDialog* x11_widget; | ||||
@@ -301,63 +588,53 @@ private: | |||||
int main(int argc, char* argv[]) | int main(int argc, char* argv[]) | ||||
{ | { | ||||
if (argc != 7) | |||||
if (argc != 5) | |||||
{ | { | ||||
qCritical("%s: bad arguments", argv[0]); | qCritical("%s: bad arguments", argv[0]); | ||||
return 1; | return 1; | ||||
} | } | ||||
const char* osc_url = argv[1]; | |||||
const char* plugin_uri = argv[2]; | |||||
const char* ui_uri = argv[3]; | |||||
const char* ui_binary = argv[4]; | |||||
const char* ui_bundle = argv[5]; | |||||
const char* ui_title = argv[6]; | |||||
const char* osc_url = argv[1]; | |||||
const char* plugin_uri = argv[2]; | |||||
const char* ui_uri = argv[3]; | |||||
const char* ui_title = argv[4]; | |||||
// Init toolkit | // Init toolkit | ||||
toolkit_init(); | toolkit_init(); | ||||
// Init LV2 | |||||
ui = new Lv2UiData; | |||||
// Init LV2-UI | |||||
ui = new Lv2UiData(ui_title); | |||||
// Init OSC | // Init OSC | ||||
osc_init("lv2-ui-bridge", osc_url); | |||||
osc_init(osc_url); | |||||
// Load UI | |||||
int ret; | |||||
if (ui->lib_open(ui_binary)) | |||||
if (ui->init(plugin_uri, ui_uri)) | |||||
{ | { | ||||
if (ui->init(plugin_uri, ui_uri, ui_bundle, false) == false) // (strcmp(resizable, "true") == 0) | |||||
{ | |||||
qCritical("Failed to load LV2 UI"); | |||||
ui->lib_close(); | |||||
osc_close(); | |||||
return 1; | |||||
} | |||||
toolkit_loop(); | |||||
ret = 0; | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
qCritical("Failed to load UI, error was:\n%s", ui->lib_error()); | |||||
osc_close(); | |||||
return 1; | |||||
qCritical("Failed to load LV2 UI"); | |||||
ret = 1; | |||||
} | } | ||||
#ifdef BRIDGE_LV2_X11 | |||||
bool reparent = false; | |||||
#else | |||||
bool reparent = true; | |||||
#endif | |||||
toolkit_loop(ui_title, reparent); | |||||
// Close OSC | |||||
osc_send_exiting(nullptr); | |||||
osc_close(); | |||||
// Close LV2-UI | |||||
ui->close(); | ui->close(); | ||||
ui->lib_close(); | |||||
osc_send_exiting(); | |||||
osc_close(); | |||||
toolkit_quit(); | |||||
// Close toolkit | |||||
if (! ret) | |||||
toolkit_quit(); | |||||
delete ui; | delete ui; | ||||
ui = nullptr; | ui = nullptr; | ||||
return 0; | |||||
return ret; | |||||
} | } |
@@ -20,10 +20,11 @@ | |||||
#include "carla_includes.h" | #include "carla_includes.h" | ||||
#include <pthread.h> | |||||
#include <cstring> | |||||
#include <QtCore/QMutex> | |||||
void toolkit_init(); | void toolkit_init(); | ||||
void toolkit_loop(const char* ui_title, bool reparent); | |||||
void toolkit_loop(); | |||||
void toolkit_quit(); | void toolkit_quit(); | ||||
void toolkit_window_show(); | void toolkit_window_show(); | ||||
void toolkit_window_hide(); | void toolkit_window_hide(); | ||||
@@ -31,7 +32,7 @@ void toolkit_window_resize(int width, int height); | |||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
const unsigned int MAX_BRIDGE_MESSAGES = 256; | |||||
#define MAX_BRIDGE_MESSAGES 256 | |||||
enum BridgeMessageType { | enum BridgeMessageType { | ||||
BRIDGE_MESSAGE_NULL = 0, | BRIDGE_MESSAGE_NULL = 0, | ||||
@@ -46,7 +47,6 @@ enum BridgeMessageType { | |||||
}; | }; | ||||
struct QuequeBridgeMessage { | struct QuequeBridgeMessage { | ||||
bool valid; | |||||
BridgeMessageType type; | BridgeMessageType type; | ||||
int value1; | int value1; | ||||
int value2; | int value2; | ||||
@@ -58,14 +58,13 @@ struct QuequeBridgeMessage { | |||||
class UiData | class UiData | ||||
{ | { | ||||
public: | public: | ||||
UiData() | |||||
UiData(const char* ui_title) | |||||
{ | { | ||||
m_lib = nullptr; | |||||
pthread_mutex_init(&m_lock, nullptr); | |||||
m_lib = nullptr; | |||||
m_title = strdup(ui_title); | |||||
for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | ||||
{ | { | ||||
QuequeBridgeMessages[i].valid = false; | |||||
QuequeBridgeMessages[i].type = BRIDGE_MESSAGE_NULL; | QuequeBridgeMessages[i].type = BRIDGE_MESSAGE_NULL; | ||||
QuequeBridgeMessages[i].value1 = 0; | QuequeBridgeMessages[i].value1 = 0; | ||||
QuequeBridgeMessages[i].value2 = 0; | QuequeBridgeMessages[i].value2 = 0; | ||||
@@ -75,17 +74,16 @@ public: | |||||
~UiData() | ~UiData() | ||||
{ | { | ||||
pthread_mutex_destroy(&m_lock); | |||||
free((void*)m_title); | |||||
} | } | ||||
void queque_message(BridgeMessageType type, int value1, int value2, double value3) | void queque_message(BridgeMessageType type, int value1, int value2, double value3) | ||||
{ | { | ||||
pthread_mutex_lock(&m_lock); | |||||
m_lock.lock(); | |||||
for (unsigned int i=0; i<MAX_BRIDGE_MESSAGES; i++) | for (unsigned int i=0; i<MAX_BRIDGE_MESSAGES; i++) | ||||
{ | { | ||||
if (QuequeBridgeMessages[i].valid == false) | |||||
if (QuequeBridgeMessages[i].type == BRIDGE_MESSAGE_NULL) | |||||
{ | { | ||||
QuequeBridgeMessages[i].valid = true; | |||||
QuequeBridgeMessages[i].type = type; | QuequeBridgeMessages[i].type = type; | ||||
QuequeBridgeMessages[i].value1 = value1; | QuequeBridgeMessages[i].value1 = value1; | ||||
QuequeBridgeMessages[i].value2 = value2; | QuequeBridgeMessages[i].value2 = value2; | ||||
@@ -93,36 +91,34 @@ public: | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
pthread_mutex_unlock(&m_lock); | |||||
m_lock.unlock(); | |||||
} | } | ||||
bool run_messages() | bool run_messages() | ||||
{ | { | ||||
pthread_mutex_lock(&m_lock); | |||||
m_lock.lock(); | |||||
for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | for (unsigned int i=0; i < MAX_BRIDGE_MESSAGES; i++) | ||||
{ | { | ||||
if (QuequeBridgeMessages[i].valid) | |||||
if (QuequeBridgeMessages[i].type != BRIDGE_MESSAGE_NULL) | |||||
{ | { | ||||
QuequeBridgeMessage* m = &QuequeBridgeMessages[i]; | |||||
const QuequeBridgeMessage* const m = &QuequeBridgeMessages[i]; | |||||
switch (m->type) | switch (m->type) | ||||
{ | { | ||||
case BRIDGE_MESSAGE_NULL: | |||||
break; | |||||
case BRIDGE_MESSAGE_PARAMETER: | case BRIDGE_MESSAGE_PARAMETER: | ||||
update_parameter(m->value1, m->value3); | |||||
set_parameter(m->value1, m->value3); | |||||
break; | break; | ||||
case BRIDGE_MESSAGE_PROGRAM: | case BRIDGE_MESSAGE_PROGRAM: | ||||
update_program(m->value1); | |||||
set_program(m->value1); | |||||
break; | break; | ||||
case BRIDGE_MESSAGE_MIDI_PROGRAM: | case BRIDGE_MESSAGE_MIDI_PROGRAM: | ||||
update_midi_program(m->value1, m->value2); | |||||
set_midi_program(m->value1, m->value2); | |||||
break; | break; | ||||
case BRIDGE_MESSAGE_NOTE_ON: | case BRIDGE_MESSAGE_NOTE_ON: | ||||
send_note_on(m->value1, m->value2); | |||||
//send_note_on(m->value1, m->value2); | |||||
break; | break; | ||||
case BRIDGE_MESSAGE_NOTE_OFF: | case BRIDGE_MESSAGE_NOTE_OFF: | ||||
send_note_off(m->value1); | |||||
//send_note_off(m->value1); | |||||
break; | break; | ||||
case BRIDGE_MESSAGE_SHOW_GUI: | case BRIDGE_MESSAGE_SHOW_GUI: | ||||
if (m->value1) | if (m->value1) | ||||
@@ -135,31 +131,45 @@ public: | |||||
break; | break; | ||||
case BRIDGE_MESSAGE_QUIT: | case BRIDGE_MESSAGE_QUIT: | ||||
toolkit_quit(); | toolkit_quit(); | ||||
pthread_mutex_unlock(&m_lock); | |||||
m_lock.unlock(); | |||||
return false; | return false; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
m->valid = false; | |||||
QuequeBridgeMessages[i].type = BRIDGE_MESSAGE_NULL; | |||||
} | } | ||||
else | else | ||||
break; | break; | ||||
} | } | ||||
pthread_mutex_unlock(&m_lock); | |||||
m_lock.unlock(); | |||||
return true; | return true; | ||||
} | } | ||||
virtual bool init(const char*, const char*, const char*, bool) = 0; | |||||
const char* get_title() const | |||||
{ | |||||
return m_title; | |||||
} | |||||
// --------------------------------------------------------------------- | |||||
// initialization | |||||
virtual bool init(const char*, const char*) = 0; | |||||
virtual void close() = 0; | virtual void close() = 0; | ||||
virtual void update_parameter(int index, double value) = 0; | |||||
virtual void update_program(int index) = 0; | |||||
virtual void update_midi_program(int bank, int program) = 0; | |||||
virtual void send_note_on(int note, int velocity) = 0; | |||||
virtual void send_note_off(int note) = 0; | |||||
// processing | |||||
virtual void set_parameter(int index, double value) = 0; | |||||
virtual void set_program(int index) = 0; | |||||
virtual void set_midi_program(int bank, int program) = 0; | |||||
//virtual void send_note_on(int note, int velocity) = 0; | |||||
//virtual void send_note_off(int note) = 0; | |||||
// gui | |||||
virtual bool has_parent() const = 0; | |||||
virtual bool is_resizable() const = 0; | |||||
virtual void* get_widget() const = 0; | |||||
virtual void* get_widget() = 0; | |||||
virtual bool is_resizable() = 0; | |||||
// --------------------------------------------------------------------- | |||||
bool lib_open(const char* filename) | bool lib_open(const char* filename) | ||||
{ | { | ||||
@@ -214,9 +224,14 @@ public: | |||||
#endif | #endif | ||||
} | } | ||||
// --------------------------------------------------------------------- | |||||
protected: | |||||
const char* m_title; | |||||
private: | private: | ||||
void* m_lib; | void* m_lib; | ||||
pthread_mutex_t m_lock; | |||||
QMutex m_lock; | |||||
QuequeBridgeMessage QuequeBridgeMessages[MAX_BRIDGE_MESSAGES]; | QuequeBridgeMessage QuequeBridgeMessages[MAX_BRIDGE_MESSAGES]; | ||||
}; | }; | ||||
@@ -1,20 +1,28 @@ | |||||
# QtCreator project file | # QtCreator project file | ||||
CONFIG = warn_on qt release | |||||
QT = core | |||||
CONFIG += warn_on qt debug link_pkgconfig | |||||
PKGCONFIG = liblo gtk+-2.0 | |||||
TEMPLATE = app | TEMPLATE = app | ||||
VERSION = 0.5.0 | |||||
VERSION = 0.5.0 | |||||
SOURCES = \ | SOURCES = \ | ||||
../carla_bridge_lv2.cpp \ | ../carla_bridge_lv2.cpp \ | ||||
../carla_bridge_gtk2.cpp \ | ../carla_bridge_gtk2.cpp \ | ||||
../../carla-bridge/carla_osc.cpp | |||||
../../carla-bridge/carla_bridge_osc.cpp | |||||
HEADERS = \ | HEADERS = \ | ||||
../carla_bridge_ui.h \ | ../carla_bridge_ui.h \ | ||||
../../carla-bridge/carla_osc.h | |||||
../../carla/carla_midi.h \ | |||||
../../carla/lv2_rdf.h \ | |||||
../../carla-bridge/carla_bridge_osc.h \ | |||||
../../carla-includes/carla_includes.h \ | |||||
../../carla-includes/carla_osc_includes.h | |||||
INCLUDEPATH = .. \ | INCLUDEPATH = .. \ | ||||
../../carla \ | |||||
../../carla-bridge \ | ../../carla-bridge \ | ||||
../../carla-includes | ../../carla-includes | ||||
@@ -22,9 +30,6 @@ TARGET = carla-bridge-lv2-gtk2 | |||||
DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_GTK2 | DEFINES = BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2_GTK2 | ||||
LIBS += -ldl -lpthread -llo | |||||
LIBS = ../../carla-lilv/carla_lilv.a -ldl | |||||
unix { | |||||
CONFIG += link_pkgconfig | |||||
PKGCONFIG += gtk+-2.0 | |||||
} | |||||
QMAKE_CXXFLAGS *= -std=c++0x |
@@ -15,20 +15,23 @@ | |||||
* For a full copy of the GNU General Public License see the COPYING file | * For a full copy of the GNU General Public License see the COPYING file | ||||
*/ | */ | ||||
#include "carla_osc.h" | |||||
#include "carla_bridge_osc.h" | |||||
#include "carla_midi.h" | |||||
#ifdef BUILD_BRIDGE_UI | #ifdef BUILD_BRIDGE_UI | ||||
#include "carla_bridge_ui.h" | #include "carla_bridge_ui.h" | ||||
#else | #else | ||||
// TODO | |||||
#include "carla_plugin.h" | #include "carla_plugin.h" | ||||
extern void plugin_bridge_show_gui(bool yesno); | extern void plugin_bridge_show_gui(bool yesno); | ||||
extern void plugin_bridge_quit(); | extern void plugin_bridge_quit(); | ||||
//CarlaPlugin* plugin = CarlaPlugins[0]; | |||||
#endif | #endif | ||||
#include <cstring> | #include <cstring> | ||||
size_t plugin_name_len = 0; | |||||
const char* plugin_name = nullptr; | |||||
size_t plugin_name_len = 13; | |||||
const char* plugin_name = "lv2-ui-bridge"; | |||||
const char* global_osc_server_path = nullptr; | const char* global_osc_server_path = nullptr; | ||||
lo_server_thread global_osc_server_thread = nullptr; | lo_server_thread global_osc_server_thread = nullptr; | ||||
@@ -36,11 +39,9 @@ OscData global_osc_data = { nullptr, nullptr, nullptr }; | |||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
void osc_init(const char* osc_name, const char* osc_url) | |||||
void osc_init(const char* osc_url) | |||||
{ | { | ||||
qDebug("osc_init(%s, %s)", osc_name, osc_url); | |||||
plugin_name = osc_name; | |||||
plugin_name_len = strlen(plugin_name); | |||||
qDebug("osc_init(%s)", osc_url); | |||||
const char* host = lo_url_get_hostname(osc_url); | const char* host = lo_url_get_hostname(osc_url); | ||||
const char* port = lo_url_get_port(osc_url); | const char* port = lo_url_get_port(osc_url); | ||||
@@ -55,21 +56,18 @@ void osc_init(const char* osc_name, const char* osc_url) | |||||
global_osc_server_thread = lo_server_thread_new(nullptr, osc_error_handler); | global_osc_server_thread = lo_server_thread_new(nullptr, osc_error_handler); | ||||
// get our full OSC server path | // get our full OSC server path | ||||
char* osc_thread_path = lo_server_thread_get_url(global_osc_server_thread); | |||||
char* this_thread_path = lo_server_thread_get_url(global_osc_server_thread); | |||||
char osc_path_tmp[strlen(osc_thread_path) + plugin_name_len + 1]; | |||||
strcpy(osc_path_tmp, osc_thread_path); | |||||
char osc_path_tmp[strlen(this_thread_path) + plugin_name_len + 1]; | |||||
strcpy(osc_path_tmp, this_thread_path); | |||||
strcat(osc_path_tmp, plugin_name); | strcat(osc_path_tmp, plugin_name); | ||||
free(osc_thread_path); | |||||
free(this_thread_path); | |||||
global_osc_server_path = strdup(osc_path_tmp); | global_osc_server_path = strdup(osc_path_tmp); | ||||
// register message handler and start OSC thread | // 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_add_method(global_osc_server_thread, nullptr, nullptr, osc_message_handler, nullptr); | ||||
lo_server_thread_start(global_osc_server_thread); | lo_server_thread_start(global_osc_server_thread); | ||||
// debug our server path just to make sure everything is ok | |||||
qDebug("carla-bridge OSC -> %s\n", global_osc_server_path); | |||||
} | } | ||||
void osc_close() | void osc_close() | ||||
@@ -90,14 +88,16 @@ void osc_clear_data(OscData* osc_data) | |||||
{ | { | ||||
qDebug("osc_clear_data(%p)", osc_data); | qDebug("osc_clear_data(%p)", osc_data); | ||||
if (global_osc_data.path) | |||||
free((void*)global_osc_data.path); | |||||
// TODO - sync | |||||
if (global_osc_data.target) | |||||
lo_address_free(global_osc_data.target); | |||||
if (osc_data->path) | |||||
free((void*)osc_data->path); | |||||
global_osc_data.path = nullptr; | |||||
global_osc_data.target = nullptr; | |||||
if (osc_data->target) | |||||
lo_address_free(osc_data->target); | |||||
osc_data->path = nullptr; | |||||
osc_data->target = nullptr; | |||||
} | } | ||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
@@ -111,24 +111,25 @@ int osc_message_handler(const char* path, const char* types, lo_arg** argv, int | |||||
{ | { | ||||
qDebug("osc_message_handler(%s, %s, %p, %i, %p, %p)", path, types, argv, argc, data, user_data); | qDebug("osc_message_handler(%s, %s, %p, %i, %p, %p)", path, types, argv, argc, data, user_data); | ||||
char method[32]; | |||||
memset(method, 0, sizeof(char)*24); | |||||
unsigned int mindex = strlen(plugin_name)+2; | |||||
if (strlen(path) < plugin_name_len + 3) | |||||
{ | |||||
qWarning("Got invalid OSC path '%s'", path); | |||||
return 1; | |||||
} | |||||
for (unsigned int i=mindex; i < strlen(path) && i-mindex < 24; i++) | |||||
method[i-mindex] = path[i]; | |||||
char method[32] = { 0 }; | |||||
memcpy(method, path + plugin_name_len + 2, 32); | |||||
if (strcmp(method, "control") == 0) | |||||
if (strcmp(method, "configure") == 0) | |||||
return osc_handle_configure(argv); | |||||
else if (strcmp(method, "control") == 0) | |||||
return osc_handle_control(argv); | return osc_handle_control(argv); | ||||
else if (strcmp(method, "program") == 0) | else if (strcmp(method, "program") == 0) | ||||
return osc_handle_program(argv); | return osc_handle_program(argv); | ||||
else if (strcmp(method, "midi_program") == 0) | else if (strcmp(method, "midi_program") == 0) | ||||
return osc_handle_midi_program(argv); | return osc_handle_midi_program(argv); | ||||
// else if (strcmp(method, "note_on") == 0) | |||||
// return osc_note_on_handler(argv); | |||||
// else if (strcmp(method, "note_off") == 0) | |||||
// return osc_note_off_handler(argv); | |||||
else if (strcmp(method, "midi") == 0) | |||||
return osc_handle_midi(argv); | |||||
else if (strcmp(method, "show") == 0) | else if (strcmp(method, "show") == 0) | ||||
return osc_handle_show(); | return osc_handle_show(); | ||||
else if (strcmp(method, "hide") == 0) | else if (strcmp(method, "hide") == 0) | ||||
@@ -149,6 +150,23 @@ int osc_message_handler(const char* path, const char* types, lo_arg** argv, int | |||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
int osc_handle_configure(lo_arg** argv) | |||||
{ | |||||
const char* key = (const char*)&argv[0]->s; | |||||
const char* value = (const char*)&argv[1]->s; | |||||
#ifdef BUILD_BRIDGE_UI | |||||
// TODO | |||||
(void)key; | |||||
(void)value; | |||||
#else | |||||
if (CarlaPlugins[0]) | |||||
CarlaPlugins[0]->set_custom_data(CUSTOM_DATA_STRING, key, value, false); | |||||
#endif | |||||
return 0; | |||||
} | |||||
int osc_handle_control(lo_arg** argv) | int osc_handle_control(lo_arg** argv) | ||||
{ | { | ||||
int index = argv[0]->i; | int index = argv[0]->i; | ||||
@@ -173,7 +191,7 @@ int osc_handle_program(lo_arg** argv) | |||||
if (ui && index >= 0) | if (ui && index >= 0) | ||||
ui->queque_message(BRIDGE_MESSAGE_PROGRAM, index, 0, 0.0); | ui->queque_message(BRIDGE_MESSAGE_PROGRAM, index, 0, 0.0); | ||||
#else | #else | ||||
if (CarlaPlugins[0]) | |||||
if (CarlaPlugins[0] && index >= 0) | |||||
CarlaPlugins[0]->set_program(index, false, true, true, true); | CarlaPlugins[0]->set_program(index, false, true, true, true); | ||||
#endif | #endif | ||||
@@ -186,18 +204,50 @@ int osc_handle_midi_program(lo_arg** argv) | |||||
int program = argv[1]->i; | int program = argv[1]->i; | ||||
#ifdef BUILD_BRIDGE_UI | #ifdef BUILD_BRIDGE_UI | ||||
//if (ui && index >= 0) | |||||
// ui->queque_message(BRIDGE_MESSAGE_MIDI_PROGRAM, index, 0, 0.0); | |||||
(void)bank; | |||||
(void)program; | |||||
if (ui && bank >= 0 && program >= 0) | |||||
ui->queque_message(BRIDGE_MESSAGE_MIDI_PROGRAM, bank, program, 0.0); | |||||
#else | #else | ||||
if (CarlaPlugins[0]) | |||||
if (CarlaPlugins[0] && bank >= 0 && program >= 0) | |||||
CarlaPlugins[0]->set_midi_program_full(bank, program, false, true, true, true); | CarlaPlugins[0]->set_midi_program_full(bank, program, false, true, true, true); | ||||
#endif | #endif | ||||
return 0; | return 0; | ||||
} | } | ||||
int osc_handle_midi(lo_arg** argv) | |||||
{ | |||||
uint8_t* data = argv[0]->m; | |||||
uint8_t status = data[1]; | |||||
// Fix bad note-off | |||||
if (MIDI_IS_STATUS_NOTE_ON(status) && data[3] == 0) | |||||
status -= 0x10; | |||||
if (MIDI_IS_STATUS_NOTE_OFF(status)) | |||||
{ | |||||
uint8_t note = data[2]; | |||||
#ifdef BUILD_BRIDGE_UI | |||||
if (ui) | |||||
ui->queque_message(BRIDGE_MESSAGE_NOTE_OFF, note, 0, 0.0); | |||||
#else | |||||
plugin->send_midi_note(false, note, 0, false, true, true); | |||||
#endif | |||||
} | |||||
else if (MIDI_IS_STATUS_NOTE_ON(status)) | |||||
{ | |||||
uint8_t note = data[2]; | |||||
uint8_t velo = data[3]; | |||||
#ifdef BUILD_BRIDGE_UI | |||||
if (ui) | |||||
ui->queque_message(BRIDGE_MESSAGE_NOTE_ON, note, velo, 0.0); | |||||
#else | |||||
plugin->send_midi_note(true, note, velo, false, true, true); | |||||
#endif | |||||
} | |||||
return 0; | |||||
} | |||||
int osc_handle_show() | int osc_handle_show() | ||||
{ | { | ||||
#ifdef BUILD_BRIDGE_UI | #ifdef BUILD_BRIDGE_UI | ||||
@@ -236,9 +286,8 @@ int osc_handle_quit() | |||||
// ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
void osc_send_update() | |||||
void osc_send_update(OscData*) | |||||
{ | { | ||||
qDebug("osc_send_update()"); | |||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
{ | { | ||||
char target_path[strlen(global_osc_data.path)+8]; | char target_path[strlen(global_osc_data.path)+8]; | ||||
@@ -248,9 +297,63 @@ void osc_send_update() | |||||
} | } | ||||
} | } | ||||
void osc_send_exiting() | |||||
void osc_send_configure(OscData*, const char* key, const char* value) | |||||
{ | |||||
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(OscData*, 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); | |||||
} | |||||
} | |||||
void osc_send_program(OscData*, 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); | |||||
} | |||||
} | |||||
void osc_send_midi_program(OscData*, int bank, int program) | |||||
{ | |||||
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); | |||||
} | |||||
} | |||||
void osc_send_midi(OscData*, uint8_t buf[4]) | |||||
{ | |||||
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); | |||||
} | |||||
} | |||||
void osc_send_exiting(OscData*) | |||||
{ | { | ||||
qDebug("osc_send_exiting()"); | |||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
{ | { | ||||
char target_path[strlen(global_osc_data.path)+9]; | char target_path[strlen(global_osc_data.path)+9]; | ||||
@@ -260,6 +363,9 @@ void osc_send_exiting() | |||||
} | } | ||||
} | } | ||||
// ------------------------------------------------------------------------- | |||||
#ifndef BUILD_BRIDGE_UI | |||||
void osc_send_bridge_ains_peak(int index, double value) | void osc_send_bridge_ains_peak(int index, double value) | ||||
{ | { | ||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
@@ -315,6 +421,28 @@ void osc_send_bridge_param_count(int ins, int outs, int total) | |||||
} | } | ||||
} | } | ||||
void osc_send_bridge_program_count(int count) | |||||
{ | |||||
if (global_osc_data.target) | |||||
{ | |||||
char target_path[strlen(global_osc_data.path)+22]; | |||||
strcpy(target_path, global_osc_data.path); | |||||
strcat(target_path, "/bridge_program_count"); | |||||
lo_send(global_osc_data.target, target_path, "i", count); | |||||
} | |||||
} | |||||
void osc_send_bridge_midi_program_count(int count) | |||||
{ | |||||
if (global_osc_data.target) | |||||
{ | |||||
char target_path[strlen(global_osc_data.path)+27]; | |||||
strcpy(target_path, global_osc_data.path); | |||||
strcat(target_path, "/bridge_midi_program_count"); | |||||
lo_send(global_osc_data.target, target_path, "i", count); | |||||
} | |||||
} | |||||
void osc_send_bridge_plugin_info(int type, int category, int hints, const char* name, const char* label, const char* maker, const char* copyright, long unique_id) | void osc_send_bridge_plugin_info(int type, int category, int hints, const char* name, const char* label, const char* maker, const char* copyright, long unique_id) | ||||
{ | { | ||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
@@ -337,14 +465,14 @@ void osc_send_bridge_param_info(int index, const char* name, const char* unit) | |||||
} | } | ||||
} | } | ||||
void osc_send_bridge_param_data(int type, int index, int rindex, int hints, int midi_channel, int midi_cc) | |||||
void osc_send_bridge_param_data(int index, int type, int rindex, int hints, int midi_channel, int midi_cc) | |||||
{ | { | ||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
{ | { | ||||
char target_path[strlen(global_osc_data.path)+19]; | char target_path[strlen(global_osc_data.path)+19]; | ||||
strcpy(target_path, global_osc_data.path); | strcpy(target_path, global_osc_data.path); | ||||
strcat(target_path, "/bridge_param_data"); | strcat(target_path, "/bridge_param_data"); | ||||
lo_send(global_osc_data.target, target_path, "iiiiii", type, index, rindex, hints, midi_channel, midi_cc); | |||||
lo_send(global_osc_data.target, target_path, "iiiiii", index, type, rindex, hints, midi_channel, midi_cc); | |||||
} | } | ||||
} | } | ||||
@@ -359,51 +487,36 @@ void osc_send_bridge_param_ranges(int index, double def, double min, double max, | |||||
} | } | ||||
} | } | ||||
void osc_send_bridge_update() | |||||
void osc_send_bridge_program_info(int index, const char* name) | |||||
{ | { | ||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
{ | { | ||||
char target_path[strlen(global_osc_data.path)+14]; | |||||
strcpy(target_path, global_osc_data.path); | |||||
strcat(target_path, "/bridge_update"); | |||||
lo_send(global_osc_data.target, target_path, ""); | |||||
} | |||||
} | |||||
// ------------------------------------------------------------------------- | |||||
void osc_send_configure(OscData*, const char* key, const char* value) | |||||
{ | |||||
qDebug("osc_send_configure(%s, %s)", key, value); | |||||
if (global_osc_data.target) | |||||
{ | |||||
char target_path[strlen(global_osc_data.path)+11]; | |||||
char target_path[strlen(global_osc_data.path)+21]; | |||||
strcpy(target_path, global_osc_data.path); | strcpy(target_path, global_osc_data.path); | ||||
strcat(target_path, "/configure"); | |||||
lo_send(global_osc_data.target, target_path, "ss", key, value); | |||||
strcat(target_path, "/bridge_program_info"); | |||||
lo_send(global_osc_data.target, target_path, "is", index, name); | |||||
} | } | ||||
} | } | ||||
void osc_send_control(OscData*, int param, double value) | |||||
void osc_send_bridge_midi_program_info(int index, int bank, int program, const char* label) | |||||
{ | { | ||||
qDebug("osc_send_control(%i, %f)", param, value); | |||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
{ | { | ||||
char target_path[strlen(global_osc_data.path)+9]; | |||||
char target_path[strlen(global_osc_data.path)+26]; | |||||
strcpy(target_path, global_osc_data.path); | strcpy(target_path, global_osc_data.path); | ||||
strcat(target_path, "/control"); | |||||
lo_send(global_osc_data.target, target_path, "if", param, value); | |||||
strcat(target_path, "/bridge_midi_program_info"); | |||||
lo_send(global_osc_data.target, target_path, "iiis", index, bank, program, label); | |||||
} | } | ||||
} | } | ||||
void osc_send_program(OscData*, int program_id) | |||||
void osc_send_bridge_update() | |||||
{ | { | ||||
qDebug("osc_send_program(%i)", program_id); | |||||
if (global_osc_data.target) | if (global_osc_data.target) | ||||
{ | { | ||||
char target_path[strlen(global_osc_data.path)+9]; | |||||
char target_path[strlen(global_osc_data.path)+15]; | |||||
strcpy(target_path, global_osc_data.path); | strcpy(target_path, global_osc_data.path); | ||||
strcat(target_path, "/program"); | |||||
lo_send(global_osc_data.target, target_path, "i", program_id); | |||||
strcat(target_path, "/bridge_update"); | |||||
lo_send(global_osc_data.target, target_path, ""); | |||||
} | } | ||||
} | } | ||||
#endif |
@@ -15,56 +15,37 @@ | |||||
* For a full copy of the GNU General Public License see the COPYING file | * For a full copy of the GNU General Public License see the COPYING file | ||||
*/ | */ | ||||
#ifndef CARLA_OSC_H | |||||
#define CARLA_OSC_H | |||||
#ifndef CARLA_BRIDGE_OSC_H | |||||
#define CARLA_BRIDGE_OSC_H | |||||
#include "carla_includes.h" | |||||
#include "carla_osc_includes.h" | |||||
#include <lo/lo.h> | |||||
struct OscData { | |||||
char* path; | |||||
lo_address source; // unused | |||||
lo_address target; | |||||
}; | |||||
void osc_init(const char* osc_name, const char* osc_url); | |||||
void osc_close(); | |||||
void osc_clear_data(OscData* osc_data); | |||||
void osc_error_handler(int num, const char* msg, const char* path); | |||||
int osc_message_handler(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); | |||||
// common plugin handlers | |||||
// common handlers | |||||
int osc_handle_configure(lo_arg** argv); | |||||
int osc_handle_control(lo_arg** argv); | int osc_handle_control(lo_arg** argv); | ||||
int osc_handle_program(lo_arg** argv); | int osc_handle_program(lo_arg** argv); | ||||
int osc_handle_midi_program(lo_arg** argv); | int osc_handle_midi_program(lo_arg** argv); | ||||
int osc_handle_midi(lo_arg** argv); | |||||
int osc_handle_show(); | int osc_handle_show(); | ||||
int osc_handle_hide(); | int osc_handle_hide(); | ||||
int osc_handle_quit(); | int osc_handle_quit(); | ||||
#ifndef BUILD_BRIDGE_UI | |||||
// bridge only | // bridge only | ||||
void osc_send_update(); | |||||
void osc_send_exiting(); | |||||
void osc_send_bridge_ains_peak(int index, double value); | void osc_send_bridge_ains_peak(int index, double value); | ||||
void osc_send_bridge_aouts_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); | void osc_send_bridge_audio_count(int ins, int outs, int total); | ||||
void osc_send_bridge_midi_count(int ins, int outs, int total); | void osc_send_bridge_midi_count(int ins, int outs, int total); | ||||
void osc_send_bridge_param_count(int ins, int outs, int total); | void osc_send_bridge_param_count(int ins, int outs, int total); | ||||
//void osc_send_bridge_program_count(); | |||||
//void osc_send_bridge_midi_program_count(); | |||||
void osc_send_bridge_program_count(int count); | |||||
void osc_send_bridge_midi_program_count(int count); | |||||
void osc_send_bridge_plugin_info(int type, int category, int hints, const char* name, const char* label, const char* maker, const char* copyright, long unique_id); | void osc_send_bridge_plugin_info(int type, int category, int hints, const char* name, const char* label, const char* maker, const char* copyright, long unique_id); | ||||
void osc_send_bridge_param_info(int index, const char* name, const char* unit); | void osc_send_bridge_param_info(int index, const char* name, const char* unit); | ||||
void osc_send_bridge_param_data(int type, int index, int rindex, int hints, int midi_channel, int midi_cc); | |||||
void osc_send_bridge_param_data(int index, int type, int rindex, int hints, int midi_channel, int midi_cc); | |||||
void osc_send_bridge_param_ranges(int index, double def, double min, double max, double step, double step_small, double step_large); | void osc_send_bridge_param_ranges(int index, double def, double min, double max, double step, double step_small, double step_large); | ||||
//void osc_send_bridge_program_info(); | |||||
//void osc_send_bridge_midi_program_info(); | |||||
void osc_send_bridge_program_info(int index, const char* name); | |||||
void osc_send_bridge_midi_program_info(int index, int bank, int program, const char* label); | |||||
void osc_send_bridge_update(); | void osc_send_bridge_update(); | ||||
#endif | |||||
// common plugin calls | |||||
void osc_send_configure(OscData* osc_data, const char* key, const char* value); | |||||
void osc_send_control(OscData* osc_data, int param_id, double value); | |||||
void osc_send_program(OscData* osc_data, int program_id); | |||||
// TODO - midi | |||||
#endif // CARLA_OSC_H | |||||
#endif // CARLA_BRIDGE_OSC_H |
@@ -0,0 +1,52 @@ | |||||
/* | |||||
* JACK Backend code for Carla | |||||
* Copyright (C) 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_OSC_INCLUDES_H | |||||
#define CARLA_OSC_INCLUDES_H | |||||
#include "carla_includes.h" | |||||
#include <lo/lo.h> | |||||
struct OscData { | |||||
char* path; | |||||
lo_address source; | |||||
lo_address target; | |||||
}; | |||||
void osc_init(const char*); | |||||
void osc_close(); | |||||
void osc_clear_data(OscData*); | |||||
void osc_error_handler(int num, const char* msg, const char* path); | |||||
int osc_message_handler(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); | |||||
void osc_send_update(OscData*); | |||||
void osc_send_configure(OscData*, const char* key, const char* value); | |||||
void osc_send_control(OscData*, int control, double value); | |||||
void osc_send_program(OscData*, int program); | |||||
void osc_send_midi_program(OscData*, int bank, int program); | |||||
void osc_send_midi(OscData*, uint8_t buf[4]); | |||||
#ifndef BUILD_BRIDGE_UI | |||||
void osc_send_show(OscData*); | |||||
void osc_send_hide(OscData*); | |||||
void osc_send_quit(OscData*); | |||||
#else | |||||
void osc_send_exiting(OscData*); | |||||
#endif | |||||
#endif // CARLA_OSC_INCLUDES_H |
@@ -33,7 +33,7 @@ typedef struct { | |||||
} LV2_MIDIState; | } LV2_MIDIState; | ||||
static double lv2midi_get_event(LV2_MIDIState* state, | |||||
inline double lv2midi_get_event(LV2_MIDIState* state, | |||||
double* timestamp, | double* timestamp, | ||||
uint32_t* size, | uint32_t* size, | ||||
unsigned char** data) { | unsigned char** data) { | ||||
@@ -54,7 +54,7 @@ static double lv2midi_get_event(LV2_MIDIState* state, | |||||
} | } | ||||
static double lv2midi_step(LV2_MIDIState* state) { | |||||
inline double lv2midi_step(LV2_MIDIState* state) { | |||||
if (state->position >= state->midi->size) { | if (state->position >= state->midi->size) { | ||||
state->position = state->midi->size; | state->position = state->midi->size; | ||||
@@ -69,7 +69,7 @@ static double lv2midi_step(LV2_MIDIState* state) { | |||||
} | } | ||||
static void lv2midi_put_event(LV2_MIDIState* state, | |||||
inline void lv2midi_put_event(LV2_MIDIState* state, | |||||
double timestamp, | double timestamp, | ||||
uint32_t size, | uint32_t size, | ||||
const unsigned char* data) { | const unsigned char* data) { | ||||
@@ -2392,7 +2392,7 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||||
content += " <CustomData>\n" | content += " <CustomData>\n" | ||||
content += " <type>%s</type>\n" % (custom_data['type']) | content += " <type>%s</type>\n" % (custom_data['type']) | ||||
content += " <key>%s</key>\n" % (custom_data['key']) | content += " <key>%s</key>\n" % (custom_data['key']) | ||||
if (custom_data['type'] in ("string", "binary")): | |||||
if (custom_data['type'] in ("string", "chunk", "binary")): | |||||
content += " <value>\n" | content += " <value>\n" | ||||
content += "%s\n" % (custom_data['value']) | content += "%s\n" % (custom_data['value']) | ||||
content += " </value>\n" | content += " </value>\n" | ||||
@@ -18,25 +18,10 @@ | |||||
#ifndef CARLA_OSC_H | #ifndef CARLA_OSC_H | ||||
#define CARLA_OSC_H | #define CARLA_OSC_H | ||||
#include "carla_includes.h" | |||||
#include <lo/lo.h> | |||||
#include "carla_osc_includes.h" | |||||
class CarlaPlugin; | class CarlaPlugin; | ||||
struct OscData { | |||||
char* path; | |||||
lo_address source; | |||||
lo_address target; | |||||
}; | |||||
void osc_init(); | |||||
void osc_close(); | |||||
void osc_clear_data(OscData* osc_data); | |||||
void osc_error_handler(int num, const char* msg, const char* path); | |||||
int osc_message_handler(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); | |||||
int osc_handle_register(lo_arg** argv, lo_address source); | int osc_handle_register(lo_arg** argv, lo_address source); | ||||
int osc_handle_unregister(); | int osc_handle_unregister(); | ||||
@@ -45,6 +30,7 @@ int osc_handle_configure(CarlaPlugin* plugin, lo_arg** argv); | |||||
int osc_handle_control(CarlaPlugin* plugin, lo_arg** argv); | int osc_handle_control(CarlaPlugin* plugin, lo_arg** argv); | ||||
int osc_handle_program(CarlaPlugin* plugin, lo_arg** argv); | int osc_handle_program(CarlaPlugin* plugin, lo_arg** argv); | ||||
int osc_handle_program_as_midi(CarlaPlugin* plugin, lo_arg** argv); | int osc_handle_program_as_midi(CarlaPlugin* plugin, lo_arg** argv); | ||||
int osc_handle_midi_program(CarlaPlugin* plugin, lo_arg** argv); | |||||
int osc_handle_midi(CarlaPlugin* plugin, lo_arg** argv); | int osc_handle_midi(CarlaPlugin* plugin, lo_arg** argv); | ||||
int osc_handle_exiting(CarlaPlugin* plugin); | int osc_handle_exiting(CarlaPlugin* plugin); | ||||
@@ -60,15 +46,6 @@ int osc_handle_note_off(CarlaPlugin* plugin, lo_arg** argv); | |||||
int osc_handle_bridge_ains_peak(CarlaPlugin* plugin, lo_arg** argv); | int osc_handle_bridge_ains_peak(CarlaPlugin* plugin, lo_arg** argv); | ||||
int osc_handle_bridge_aouts_peak(CarlaPlugin* plugin, lo_arg** argv); | int osc_handle_bridge_aouts_peak(CarlaPlugin* plugin, lo_arg** argv); | ||||
void osc_send_configure(OscData* osc_data, const char* key, const char* value); | |||||
void osc_send_control(OscData* osc_data, int param_id, double value); | |||||
void osc_send_program(OscData* osc_data, int program_id); | |||||
void osc_send_program_as_midi(OscData* osc_data, int bank, int program); | |||||
void osc_send_midi_program(OscData* osc_data, int bank, int program); | |||||
void osc_send_show(OscData* osc_data); | |||||
void osc_send_hide(OscData* osc_data); | |||||
void osc_send_quit(OscData* osc_data); | |||||
bool osc_global_registered(); | bool osc_global_registered(); | ||||
void osc_global_send_add_plugin(int plugin_id, const char* plugin_name); | void osc_global_send_add_plugin(int plugin_id, const char* plugin_name); | ||||
void osc_global_send_remove_plugin(int plugin_id); | void osc_global_send_remove_plugin(int plugin_id); | ||||
@@ -17,33 +17,6 @@ | |||||
#include "carla_plugin.h" | #include "carla_plugin.h" | ||||
#include "lv2/lv2.h" | |||||
#include "lv2/atom.h" | |||||
#include "lv2/atom-util.h" | |||||
#include "lv2/data-access.h" | |||||
#include "lv2/event.h" | |||||
#include "lv2/event-helpers.h" | |||||
#include "lv2/instance-access.h" | |||||
#include "lv2/log.h" | |||||
#include "lv2/midi.h" | |||||
#include "lv2/patch.h" | |||||
#include "lv2/port-props.h" | |||||
#include "lv2/presets.h" | |||||
#include "lv2/state.h" | |||||
#include "lv2/time.h" | |||||
#include "lv2/ui.h" | |||||
#include "lv2/units.h" | |||||
#include "lv2/uri-map.h" | |||||
#include "lv2/urid.h" | |||||
#include "lv2/worker.h" | |||||
#include "lv2/lv2dynparam.h" | |||||
#include "lv2/lv2-miditype.h" | |||||
#include "lv2/lv2-midifunctions.h" | |||||
#include "lv2/lv2_external_ui.h" | |||||
#include "lv2/lv2_programs.h" | |||||
#include "lv2/lv2_rtmempool.h" | |||||
#include "lv2_rdf.h" | #include "lv2_rdf.h" | ||||
extern "C" { | extern "C" { | ||||
@@ -73,45 +46,44 @@ const unsigned int PARAMETER_IS_TRIGGER = 0x1000; | |||||
const unsigned int PARAMETER_IS_STRICT_BOUNDS = 0x2000; | const unsigned int PARAMETER_IS_STRICT_BOUNDS = 0x2000; | ||||
// feature ids | // feature ids | ||||
const uint32_t lv2_feature_id_event = 0; | |||||
const uint32_t lv2_feature_id_logs = 1; | |||||
const uint32_t lv2_feature_id_state_make_path = 2; | |||||
const uint32_t lv2_feature_id_state_map_path = 3; | |||||
const uint32_t lv2_feature_id_uri_map = 4; | |||||
const uint32_t lv2_feature_id_urid_map = 5; | |||||
const uint32_t lv2_feature_id_urid_unmap = 6; | |||||
const uint32_t lv2_feature_id_worker = 7; | |||||
const uint32_t lv2_feature_id_programs = 8; | |||||
const uint32_t lv2_feature_id_rtmempool = 9; | |||||
const uint32_t lv2_feature_id_data_access = 10; | |||||
const uint32_t lv2_feature_id_instance_access = 11; | |||||
const uint32_t lv2_feature_id_ui_parent = 12; | |||||
const uint32_t lv2_feature_id_ui_port_map = 13; | |||||
const uint32_t lv2_feature_id_ui_resize = 14; | |||||
const uint32_t lv2_feature_id_external_ui = 15; | |||||
const uint32_t lv2_feature_id_external_ui_old = 16; | |||||
const uint32_t lv2_feature_count = 17; | |||||
const uint32_t lv2_feature_id_event = 0; | |||||
const uint32_t lv2_feature_id_logs = 1; | |||||
const uint32_t lv2_feature_id_programs = 2; | |||||
const uint32_t lv2_feature_id_rtmempool = 3; | |||||
const uint32_t lv2_feature_id_state_make_path = 4; | |||||
const uint32_t lv2_feature_id_state_map_path = 5; | |||||
const uint32_t lv2_feature_id_uri_map = 6; | |||||
const uint32_t lv2_feature_id_urid_map = 7; | |||||
const uint32_t lv2_feature_id_urid_unmap = 8; | |||||
const uint32_t lv2_feature_id_worker = 9; | |||||
const uint32_t lv2_feature_id_data_access = 10; | |||||
const uint32_t lv2_feature_id_instance_access = 11; | |||||
const uint32_t lv2_feature_id_ui_parent = 12; | |||||
const uint32_t lv2_feature_id_ui_port_map = 13; | |||||
const uint32_t lv2_feature_id_ui_resize = 14; | |||||
const uint32_t lv2_feature_id_external_ui = 15; | |||||
const uint32_t lv2_feature_id_external_ui_old = 16; | |||||
const uint32_t lv2_feature_count = 17; | |||||
// event data/types | // event data/types | ||||
const unsigned int CARLA_EVENT_DATA_ATOM = 0x01; | |||||
const unsigned int CARLA_EVENT_DATA_EVENT = 0x02; | |||||
const unsigned int CARLA_EVENT_DATA_MIDI_LL = 0x04; | |||||
const unsigned int CARLA_EVENT_TYPE_MESSAGE = 0x10; | |||||
const unsigned int CARLA_EVENT_TYPE_MIDI = 0x20; | |||||
const unsigned int CARLA_EVENT_DATA_ATOM = 0x01; | |||||
const unsigned int CARLA_EVENT_DATA_EVENT = 0x02; | |||||
const unsigned int CARLA_EVENT_DATA_MIDI_LL = 0x04; | |||||
const unsigned int CARLA_EVENT_TYPE_MESSAGE = 0x10; | |||||
const unsigned int CARLA_EVENT_TYPE_MIDI = 0x20; | |||||
// pre-set uri[d] map ids | // pre-set uri[d] map ids | ||||
const uint32_t CARLA_URI_MAP_ID_NULL = 0; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_CHUNK = 1; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_PATH = 2; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_SEQUENCE = 3; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_STRING = 4; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_ERROR = 5; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_NOTE = 6; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_TRACE = 7; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_WARNING = 8; | |||||
const uint32_t CARLA_URI_MAP_ID_MIDI_EVENT = 9; | |||||
const uint32_t CARLA_URI_MAP_ID_TIME_POSITION = 10; // TODO - full timePos support | |||||
const uint32_t CARLA_URI_MAP_ID_COUNT = 11; | |||||
const uint32_t CARLA_URI_MAP_ID_NULL = 0; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_CHUNK = 1; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_PATH = 2; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_SEQUENCE = 3; | |||||
const uint32_t CARLA_URI_MAP_ID_ATOM_STRING = 4; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_ERROR = 5; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_NOTE = 6; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_TRACE = 7; | |||||
const uint32_t CARLA_URI_MAP_ID_LOG_WARNING = 8; | |||||
const uint32_t CARLA_URI_MAP_ID_MIDI_EVENT = 9; | |||||
const uint32_t CARLA_URI_MAP_ID_COUNT = 10; | |||||
enum Lv2ParameterDataType { | enum Lv2ParameterDataType { | ||||
LV2_PARAMETER_TYPE_CONTROL, | LV2_PARAMETER_TYPE_CONTROL, | ||||
@@ -2374,6 +2346,10 @@ public: | |||||
Log_Feature->printf = carla_lv2_log_printf; | Log_Feature->printf = carla_lv2_log_printf; | ||||
Log_Feature->vprintf = carla_lv2_log_vprintf; | Log_Feature->vprintf = carla_lv2_log_vprintf; | ||||
LV2_Programs_Host* Programs_Feature = new LV2_Programs_Host; | |||||
Programs_Feature->handle = this; | |||||
Programs_Feature->program_changed = carla_lv2_program_changed; | |||||
LV2_State_Make_Path* State_MakePath_Feature = new LV2_State_Make_Path; | LV2_State_Make_Path* State_MakePath_Feature = new LV2_State_Make_Path; | ||||
State_MakePath_Feature->handle = this; | State_MakePath_Feature->handle = this; | ||||
State_MakePath_Feature->path = carla_lv2_state_make_path; | State_MakePath_Feature->path = carla_lv2_state_make_path; | ||||
@@ -2399,10 +2375,6 @@ public: | |||||
Worker_Feature->handle = this; | Worker_Feature->handle = this; | ||||
Worker_Feature->schedule_work = carla_lv2_worker_schedule; | Worker_Feature->schedule_work = carla_lv2_worker_schedule; | ||||
LV2_Programs_Host* Programs_Feature = new LV2_Programs_Host; | |||||
Programs_Feature->handle = this; | |||||
Programs_Feature->program_changed = carla_lv2_program_changed; | |||||
lv2_rtsafe_memory_pool_provider* RT_MemPool_Feature = new lv2_rtsafe_memory_pool_provider; | lv2_rtsafe_memory_pool_provider* RT_MemPool_Feature = new lv2_rtsafe_memory_pool_provider; | ||||
rtmempool_allocator_init(RT_MemPool_Feature); | rtmempool_allocator_init(RT_MemPool_Feature); | ||||
@@ -2414,6 +2386,14 @@ public: | |||||
features[lv2_feature_id_logs]->URI = LV2_LOG__log; | features[lv2_feature_id_logs]->URI = LV2_LOG__log; | ||||
features[lv2_feature_id_logs]->data = Log_Feature; | features[lv2_feature_id_logs]->data = Log_Feature; | ||||
features[lv2_feature_id_programs] = new LV2_Feature; | |||||
features[lv2_feature_id_programs]->URI = LV2_PROGRAMS__Host; | |||||
features[lv2_feature_id_programs]->data = Programs_Feature; | |||||
features[lv2_feature_id_rtmempool] = new LV2_Feature; | |||||
features[lv2_feature_id_rtmempool]->URI = LV2_RTSAFE_MEMORY_POOL_URI; | |||||
features[lv2_feature_id_rtmempool]->data = RT_MemPool_Feature; | |||||
features[lv2_feature_id_state_make_path] = new LV2_Feature; | features[lv2_feature_id_state_make_path] = new LV2_Feature; | ||||
features[lv2_feature_id_state_make_path]->URI = LV2_STATE__makePath; | features[lv2_feature_id_state_make_path]->URI = LV2_STATE__makePath; | ||||
features[lv2_feature_id_state_make_path]->data = State_MakePath_Feature; | features[lv2_feature_id_state_make_path]->data = State_MakePath_Feature; | ||||
@@ -2438,14 +2418,6 @@ public: | |||||
features[lv2_feature_id_worker]->URI = LV2_WORKER__schedule; | features[lv2_feature_id_worker]->URI = LV2_WORKER__schedule; | ||||
features[lv2_feature_id_worker]->data = Worker_Feature; | features[lv2_feature_id_worker]->data = Worker_Feature; | ||||
features[lv2_feature_id_programs] = new LV2_Feature; | |||||
features[lv2_feature_id_programs]->URI = LV2_PROGRAMS__Host; | |||||
features[lv2_feature_id_programs]->data = Programs_Feature; | |||||
features[lv2_feature_id_rtmempool] = new LV2_Feature; | |||||
features[lv2_feature_id_rtmempool]->URI = LV2_RTSAFE_MEMORY_POOL_URI; | |||||
features[lv2_feature_id_rtmempool]->data = RT_MemPool_Feature; | |||||
handle = descriptor->instantiate(descriptor, get_sample_rate(), rdf_descriptor->Bundle, features); | handle = descriptor->instantiate(descriptor, get_sample_rate(), rdf_descriptor->Bundle, features); | ||||
if (handle) | if (handle) | ||||
@@ -2762,6 +2734,9 @@ public: | |||||
#endif | #endif | ||||
} | } | ||||
// ----------------- DynParam Feature ------------------------------------------------ | |||||
// TODO | |||||
// ----------------- Event Feature --------------------------------------------------- | // ----------------- Event Feature --------------------------------------------------- | ||||
static uint32_t carla_lv2_event_ref(LV2_Event_Callback_Data callback_data, LV2_Event* event) | static uint32_t carla_lv2_event_ref(LV2_Event_Callback_Data callback_data, LV2_Event* event) | ||||
{ | { | ||||
@@ -2819,6 +2794,18 @@ public: | |||||
return ret; | return ret; | ||||
} | } | ||||
// ----------------- Programs Feature ------------------------------------------------ | |||||
static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index) | |||||
{ | |||||
qDebug("Lv2Plugin::carla_lv2_program_changed(%p, %i)", handle, index); | |||||
if (handle) | |||||
{ | |||||
Lv2Plugin* plugin = (Lv2Plugin*)handle; | |||||
plugin->update_program(index); | |||||
} | |||||
} | |||||
// ----------------- State Feature --------------------------------------------------- | // ----------------- State Feature --------------------------------------------------- | ||||
static char* carla_lv2_state_make_path(LV2_State_Make_Path_Handle handle, const char* path) | static char* carla_lv2_state_make_path(LV2_State_Make_Path_Handle handle, const char* path) | ||||
{ | { | ||||
@@ -2996,17 +2983,8 @@ public: | |||||
{ | { | ||||
qDebug("Lv2Plugin::carla_lv2_uri_to_id(%p, %s, %s)", data, map, uri); | qDebug("Lv2Plugin::carla_lv2_uri_to_id(%p, %s, %s)", data, map, uri); | ||||
// Event types | |||||
if (map && strcmp(map, LV2_EVENT_URI) == 0) | |||||
{ | |||||
if (strcmp(uri, LV2_MIDI__MidiEvent) == 0) | |||||
return CARLA_URI_MAP_ID_MIDI_EVENT; | |||||
else if (strcmp(uri, LV2_TIME__Position) == 0) | |||||
return CARLA_URI_MAP_ID_TIME_POSITION; | |||||
} | |||||
// Atom types | // Atom types | ||||
else if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||||
if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_CHUNK; | return CARLA_URI_MAP_ID_ATOM_CHUNK; | ||||
else if (strcmp(uri, LV2_ATOM__Path) == 0) | else if (strcmp(uri, LV2_ATOM__Path) == 0) | ||||
return CARLA_URI_MAP_ID_ATOM_PATH; | return CARLA_URI_MAP_ID_ATOM_PATH; | ||||
@@ -3025,7 +3003,9 @@ public: | |||||
else if (strcmp(uri, LV2_LOG__Warning) == 0) | else if (strcmp(uri, LV2_LOG__Warning) == 0) | ||||
return CARLA_URI_MAP_ID_LOG_WARNING; | return CARLA_URI_MAP_ID_LOG_WARNING; | ||||
// TODO - position types | |||||
// Others | |||||
else if (strcmp(uri, LV2_MIDI__MidiEvent) == 0) | |||||
return CARLA_URI_MAP_ID_MIDI_EVENT; | |||||
// Custom types | // Custom types | ||||
if (data) | if (data) | ||||
@@ -3042,14 +3022,8 @@ public: | |||||
{ | { | ||||
qDebug("Lv2Plugin::carla_lv2_urid_map(%p, %s)", handle, uri); | qDebug("Lv2Plugin::carla_lv2_urid_map(%p, %s)", handle, uri); | ||||
// Event types | |||||
if (strcmp(uri, LV2_MIDI__MidiEvent) == 0) | |||||
return CARLA_URI_MAP_ID_MIDI_EVENT; | |||||
else if (strcmp(uri, LV2_TIME__Position) == 0) | |||||
return CARLA_URI_MAP_ID_TIME_POSITION; | |||||
// Atom types | // Atom types | ||||
else if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||||
if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||||
return CARLA_URI_MAP_ID_ATOM_CHUNK; | return CARLA_URI_MAP_ID_ATOM_CHUNK; | ||||
else if (strcmp(uri, LV2_ATOM__Path) == 0) | else if (strcmp(uri, LV2_ATOM__Path) == 0) | ||||
return CARLA_URI_MAP_ID_ATOM_PATH; | return CARLA_URI_MAP_ID_ATOM_PATH; | ||||
@@ -3068,7 +3042,9 @@ public: | |||||
else if (strcmp(uri, LV2_LOG__Warning) == 0) | else if (strcmp(uri, LV2_LOG__Warning) == 0) | ||||
return CARLA_URI_MAP_ID_LOG_WARNING; | return CARLA_URI_MAP_ID_LOG_WARNING; | ||||
// TODO - position types | |||||
// Others | |||||
else if (strcmp(uri, LV2_MIDI__MidiEvent) == 0) | |||||
return CARLA_URI_MAP_ID_MIDI_EVENT; | |||||
// Custom types | // Custom types | ||||
if (handle) | if (handle) | ||||
@@ -3087,8 +3063,6 @@ public: | |||||
// Event types | // Event types | ||||
if (urid == CARLA_URI_MAP_ID_MIDI_EVENT) | if (urid == CARLA_URI_MAP_ID_MIDI_EVENT) | ||||
return LV2_MIDI__MidiEvent; | return LV2_MIDI__MidiEvent; | ||||
else if (urid == CARLA_URI_MAP_ID_TIME_POSITION) | |||||
return LV2_TIME__Position; | |||||
// Atom types | // Atom types | ||||
else if (urid == CARLA_URI_MAP_ID_ATOM_CHUNK) | else if (urid == CARLA_URI_MAP_ID_ATOM_CHUNK) | ||||
@@ -3166,21 +3140,6 @@ public: | |||||
return LV2_WORKER_ERR_UNKNOWN; | return LV2_WORKER_ERR_UNKNOWN; | ||||
} | } | ||||
// ----------------- DynParam Feature ------------------------------------------------ | |||||
// TODO | |||||
// ----------------- Programs Feature ------------------------------------------------ | |||||
static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index) | |||||
{ | |||||
qDebug("Lv2Plugin::carla_lv2_program_changed(%p, %i)", handle, index); | |||||
if (handle) | |||||
{ | |||||
Lv2Plugin* plugin = (Lv2Plugin*)handle; | |||||
plugin->update_program(index); | |||||
} | |||||
} | |||||
// ----------------- UI Port-Map Feature --------------------------------------------- | // ----------------- UI Port-Map Feature --------------------------------------------- | ||||
static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol) | static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol) | ||||
{ | { | ||||
@@ -20,6 +20,33 @@ | |||||
#include <cstdint> | #include <cstdint> | ||||
#include "lv2/lv2.h" | |||||
#include "lv2/atom.h" | |||||
#include "lv2/atom-util.h" | |||||
#include "lv2/data-access.h" | |||||
#include "lv2/event.h" | |||||
#include "lv2/event-helpers.h" | |||||
#include "lv2/instance-access.h" | |||||
#include "lv2/log.h" | |||||
#include "lv2/midi.h" | |||||
#include "lv2/patch.h" | |||||
#include "lv2/port-props.h" | |||||
#include "lv2/presets.h" | |||||
#include "lv2/state.h" | |||||
#include "lv2/time.h" | |||||
#include "lv2/ui.h" | |||||
#include "lv2/units.h" | |||||
#include "lv2/uri-map.h" | |||||
#include "lv2/urid.h" | |||||
#include "lv2/worker.h" | |||||
#include "lv2/lv2dynparam.h" | |||||
#include "lv2/lv2-miditype.h" | |||||
#include "lv2/lv2-midifunctions.h" | |||||
#include "lv2/lv2_external_ui.h" | |||||
#include "lv2/lv2_programs.h" | |||||
#include "lv2/lv2_rtmempool.h" | |||||
// Base Types | // Base Types | ||||
typedef float LV2_Data; | typedef float LV2_Data; | ||||
typedef const char* LV2_URI; | typedef const char* LV2_URI; | ||||
@@ -147,7 +174,6 @@ struct LV2_RDF_PortScalePoint { | |||||
// Port Support Types | // Port Support Types | ||||
#define LV2_PORT_SUPPORTS_MIDI_EVENT 0x1000 | #define LV2_PORT_SUPPORTS_MIDI_EVENT 0x1000 | ||||
#define LV2_PORT_SUPPORTS_PATCH_MESSAGE 0x2000 | #define LV2_PORT_SUPPORTS_PATCH_MESSAGE 0x2000 | ||||
//#define LV2_PORT_SUPPORTS_TIME 0x4000 // TODO | |||||
#define LV2_IS_PORT_INPUT(x) ((x) & LV2_PORT_INPUT) | #define LV2_IS_PORT_INPUT(x) ((x) & LV2_PORT_INPUT) | ||||
#define LV2_IS_PORT_OUTPUT(x) ((x) & LV2_PORT_OUTPUT) | #define LV2_IS_PORT_OUTPUT(x) ((x) & LV2_PORT_OUTPUT) | ||||
@@ -190,9 +216,29 @@ struct LV2_RDF_PortScalePoint { | |||||
#define LV2_IS_PORT_TRIGGER(x) ((x) & LV2_PORT_TRIGGER) | #define LV2_IS_PORT_TRIGGER(x) ((x) & LV2_PORT_TRIGGER) | ||||
// Port Designation | // Port Designation | ||||
#define LV2_PORT_LATENCY 0x1 | |||||
#define LV2_IS_PORT_LATENCY(x) ((x) & LV2_PORT_LATENCY) | |||||
#define LV2_PORT_LATENCY 0x1 | |||||
#define LV2_PORT_TIME_BAR 0x2 | |||||
#define LV2_PORT_TIME_BAR_BEAT 0x3 | |||||
#define LV2_PORT_TIME_BEAT 0x4 | |||||
#define LV2_PORT_TIME_BEAT_UNIT 0x5 | |||||
#define LV2_PORT_TIME_BEATS_PER_BAR 0x6 | |||||
#define LV2_PORT_TIME_BEATS_PER_MINUTE 0x7 | |||||
#define LV2_PORT_TIME_FRAMES 0x8 | |||||
#define LV2_PORT_TIME_FRAMES_PER_SECOND 0x9 | |||||
#define LV2_PORT_TIME_POSITION 0xA | |||||
#define LV2_PORT_TIME_SPEED 0xB | |||||
#define LV2_IS_PORT_LATENCY(x) ((x) == LV2_PORT_LATENCY) | |||||
#define LV2_IS_PORT_TIME_BAR(x) ((x) == LV2_PORT_TIME_BAR) | |||||
#define LV2_IS_PORT_TIME_BAR_BEAT(x) ((x) == LV2_PORT_TIME_BAR_BEAT) | |||||
#define LV2_IS_PORT_TIME_BEAT(x) ((x) == LV2_PORT_TIME_BEAT) | |||||
#define LV2_IS_PORT_TIME_BEAT_UNIT(x) ((x) == LV2_PORT_TIME_BEAT_UNIT) | |||||
#define LV2_IS_PORT_TIME_BEATS_PER_BAR(x) ((x) == LV2_PORT_TIME_BEATS_PER_BAR) | |||||
#define LV2_IS_PORT_TIME_BEATS_PER_MINUTE(x) ((x) == LV2_PORT_TIME_BEATS_PER_MINUTE) | |||||
#define LV2_IS_PORT_TIME_FRAMES(x) ((x) == LV2_PORT_TIME_FRAMES) | |||||
#define LV2_IS_PORT_TIME_FRAMES_PER_SECOND(x) ((x) == LV2_PORT_TIME_FRAMES_PER_SECOND) | |||||
#define LV2_IS_PORT_TIME_POSITION(x) ((x) == LV2_PORT_TIME_POSITION) | |||||
#define LV2_IS_PORT_TIME_SPEED(x) ((x) == LV2_PORT_TIME_SPEED) | |||||
// Port | // Port | ||||
struct LV2_RDF_Port { | struct LV2_RDF_Port { | ||||
@@ -1724,12 +1770,16 @@ inline bool is_lv2_feature_supported(const char* uri) | |||||
return true; | return true; | ||||
else if (strcmp(uri, LV2_URID__unmap) == 0) | else if (strcmp(uri, LV2_URID__unmap) == 0) | ||||
return true; | return true; | ||||
#ifndef BUILD_BRIDGE_UI | |||||
else if (strcmp(uri, LV2_WORKER__schedule) == 0) | else if (strcmp(uri, LV2_WORKER__schedule) == 0) | ||||
return true; | return true; | ||||
#endif | |||||
else if (strcmp(uri, LV2_PROGRAMS__Host) == 0) | else if (strcmp(uri, LV2_PROGRAMS__Host) == 0) | ||||
return true; | return true; | ||||
#ifndef BUILD_BRIDGE_UI | |||||
else if (strcmp(uri, LV2_RTSAFE_MEMORY_POOL_URI) == 0) | else if (strcmp(uri, LV2_RTSAFE_MEMORY_POOL_URI) == 0) | ||||
return true; | return true; | ||||
#endif | |||||
else | else | ||||
return false; | return false; | ||||
} | } | ||||
@@ -1741,10 +1791,12 @@ inline bool is_lv2_ui_feature_supported(const char* uri) | |||||
#endif | #endif | ||||
if (is_lv2_feature_supported(uri)) | if (is_lv2_feature_supported(uri)) | ||||
return true; | return true; | ||||
#ifndef BUILD_BRIDGE_UI | |||||
else if (strcmp(uri, LV2_DATA_ACCESS_URI) == 0) | else if (strcmp(uri, LV2_DATA_ACCESS_URI) == 0) | ||||
return true; | return true; | ||||
else if (strcmp(uri, LV2_INSTANCE_ACCESS_URI) == 0) | else if (strcmp(uri, LV2_INSTANCE_ACCESS_URI) == 0) | ||||
return true; | return true; | ||||
#endif | |||||
else if (strcmp(uri, LV2_UI__noUserResize) == 0) | else if (strcmp(uri, LV2_UI__noUserResize) == 0) | ||||
return true; | return true; | ||||
else if (strcmp(uri, LV2_UI__fixedSize) == 0) | else if (strcmp(uri, LV2_UI__fixedSize) == 0) | ||||
@@ -1761,10 +1813,12 @@ inline bool is_lv2_ui_feature_supported(const char* uri) | |||||
return false; // TODO | return false; // TODO | ||||
else if (strcmp(uri, LV2_UI_PREFIX "makeResident") == 0) | else if (strcmp(uri, LV2_UI_PREFIX "makeResident") == 0) | ||||
return true; | return true; | ||||
#ifndef BUILD_BRIDGE_UI | |||||
else if (strcmp(uri, LV2_EXTERNAL_UI_URI) == 0) | else if (strcmp(uri, LV2_EXTERNAL_UI_URI) == 0) | ||||
return true; | return true; | ||||
else if (strcmp(uri, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0) | else if (strcmp(uri, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0) | ||||
return true; | return true; | ||||
#endif | |||||
else | else | ||||
return false; | return false; | ||||
} | } | ||||