| @@ -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; | ||||
| } | } | ||||