| @@ -15,55 +15,80 @@ | |||
| * 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/carla_osc.h" | |||
| #ifdef BRIDGE_LV2_X11 | |||
| #error X11 UI uses Qt4 | |||
| #endif | |||
| #include <gtk/gtk.h> | |||
| #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*) | |||
| { | |||
| 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(); | |||
| } | |||
| void gtk_ui_destroy(GtkWidget*, void*) | |||
| { | |||
| window = nullptr; | |||
| gtk_main_quit(); | |||
| toolkit_quit(); | |||
| } | |||
| // ------------------------------------------------------------------------- | |||
| void toolkit_init() | |||
| { | |||
| int argc = 0; | |||
| char** argv = nullptr; | |||
| static int argc = 0; | |||
| static char** argv = { nullptr }; | |||
| 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_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_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 | |||
| gtk_main(); | |||
| @@ -73,22 +98,28 @@ void toolkit_quit() | |||
| { | |||
| if (window) | |||
| { | |||
| save_window_settings(); | |||
| gtk_widget_destroy(window); | |||
| gtk_main_quit(); | |||
| } | |||
| window = nullptr; | |||
| } | |||
| void toolkit_window_show() | |||
| { | |||
| gtk_widget_show_all(window); | |||
| if (window) | |||
| gtk_widget_show_all(window); | |||
| } | |||
| void toolkit_window_hide() | |||
| { | |||
| gtk_widget_hide_all(window); | |||
| if (window) | |||
| gtk_widget_hide_all(window); | |||
| } | |||
| 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 | |||
| */ | |||
| #include "carla_bridge_osc.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 | |||
| // FIXME, use x11 something | |||
| #include <QtGui/QDialog> | |||
| #endif | |||
| @@ -36,119 +31,76 @@ UiData* ui = nullptr; | |||
| // ------------------------------------------------------------------------- | |||
| // 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 | |||
| 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 | |||
| { | |||
| public: | |||
| Lv2UiData() : UiData() | |||
| Lv2UiData(const char* ui_title) : UiData(ui_title) | |||
| { | |||
| handle = nullptr; | |||
| widget = nullptr; | |||
| descriptor = nullptr; | |||
| rdf_descriptor = nullptr; | |||
| rdf_ui_descriptor = nullptr; | |||
| programs = nullptr; | |||
| #ifdef BRIDGE_LV2_X11 | |||
| x11_widget = new QDialog(nullptr); | |||
| x11_widget = new QDialog; | |||
| #endif | |||
| // 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; | |||
| URI_Map_Feature->callback_data = this; | |||
| URI_Map_Feature->uri_to_id = carla_lv2_uri_to_id; | |||
| @@ -161,54 +113,74 @@ public: | |||
| URID_Unmap_Feature->handle = this; | |||
| 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; | |||
| UI_Resize_Feature->handle = this; | |||
| 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 | |||
| 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 | |||
| features[lv2_feature_id_ui_parent] = nullptr; | |||
| features[lv2_feature_id_ui_parent]->data = nullptr; | |||
| #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() | |||
| { | |||
| 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_URID_Map*)features[lv2_feature_id_urid_map]->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; | |||
| for (uint32_t i=0; i < lv2_feature_count; i++) | |||
| @@ -216,50 +188,90 @@ public: | |||
| if (features[i]) | |||
| delete features[i]; | |||
| } | |||
| if (rdf_descriptor) | |||
| lv2_rdf_free(rdf_descriptor); | |||
| #ifdef WANT_X11 | |||
| //delete x11_widget; | |||
| #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; | |||
| } | |||
| } | |||
| 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; | |||
| } | |||
| virtual void close() | |||
| void close() | |||
| { | |||
| if (handle && descriptor && descriptor->cleanup) | |||
| 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) | |||
| { | |||
| @@ -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 | |||
| return x11_widget; | |||
| @@ -282,9 +326,248 @@ public: | |||
| #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: | |||
| @@ -292,7 +575,11 @@ private: | |||
| LV2UI_Widget widget; | |||
| const LV2UI_Descriptor* descriptor; | |||
| 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 | |||
| QDialog* x11_widget; | |||
| @@ -301,63 +588,53 @@ private: | |||
| int main(int argc, char* argv[]) | |||
| { | |||
| if (argc != 7) | |||
| if (argc != 5) | |||
| { | |||
| qCritical("%s: bad arguments", argv[0]); | |||
| 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 | |||
| toolkit_init(); | |||
| // Init LV2 | |||
| ui = new Lv2UiData; | |||
| // Init LV2-UI | |||
| ui = new Lv2UiData(ui_title); | |||
| // 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 | |||
| { | |||
| 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->lib_close(); | |||
| osc_send_exiting(); | |||
| osc_close(); | |||
| toolkit_quit(); | |||
| // Close toolkit | |||
| if (! ret) | |||
| toolkit_quit(); | |||
| delete ui; | |||
| ui = nullptr; | |||
| return 0; | |||
| return ret; | |||
| } | |||
| @@ -20,10 +20,11 @@ | |||
| #include "carla_includes.h" | |||
| #include <pthread.h> | |||
| #include <cstring> | |||
| #include <QtCore/QMutex> | |||
| void toolkit_init(); | |||
| void toolkit_loop(const char* ui_title, bool reparent); | |||
| void toolkit_loop(); | |||
| void toolkit_quit(); | |||
| void toolkit_window_show(); | |||
| 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 { | |||
| BRIDGE_MESSAGE_NULL = 0, | |||
| @@ -46,7 +47,6 @@ enum BridgeMessageType { | |||
| }; | |||
| struct QuequeBridgeMessage { | |||
| bool valid; | |||
| BridgeMessageType type; | |||
| int value1; | |||
| int value2; | |||
| @@ -58,14 +58,13 @@ struct QuequeBridgeMessage { | |||
| class UiData | |||
| { | |||
| 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++) | |||
| { | |||
| QuequeBridgeMessages[i].valid = false; | |||
| QuequeBridgeMessages[i].type = BRIDGE_MESSAGE_NULL; | |||
| QuequeBridgeMessages[i].value1 = 0; | |||
| QuequeBridgeMessages[i].value2 = 0; | |||
| @@ -75,17 +74,16 @@ public: | |||
| ~UiData() | |||
| { | |||
| pthread_mutex_destroy(&m_lock); | |||
| free((void*)m_title); | |||
| } | |||
| 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++) | |||
| { | |||
| if (QuequeBridgeMessages[i].valid == false) | |||
| if (QuequeBridgeMessages[i].type == BRIDGE_MESSAGE_NULL) | |||
| { | |||
| QuequeBridgeMessages[i].valid = true; | |||
| QuequeBridgeMessages[i].type = type; | |||
| QuequeBridgeMessages[i].value1 = value1; | |||
| QuequeBridgeMessages[i].value2 = value2; | |||
| @@ -93,36 +91,34 @@ public: | |||
| break; | |||
| } | |||
| } | |||
| pthread_mutex_unlock(&m_lock); | |||
| m_lock.unlock(); | |||
| } | |||
| bool run_messages() | |||
| { | |||
| pthread_mutex_lock(&m_lock); | |||
| m_lock.lock(); | |||
| 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) | |||
| { | |||
| case BRIDGE_MESSAGE_NULL: | |||
| break; | |||
| case BRIDGE_MESSAGE_PARAMETER: | |||
| update_parameter(m->value1, m->value3); | |||
| set_parameter(m->value1, m->value3); | |||
| break; | |||
| case BRIDGE_MESSAGE_PROGRAM: | |||
| update_program(m->value1); | |||
| set_program(m->value1); | |||
| break; | |||
| case BRIDGE_MESSAGE_MIDI_PROGRAM: | |||
| update_midi_program(m->value1, m->value2); | |||
| set_midi_program(m->value1, m->value2); | |||
| break; | |||
| case BRIDGE_MESSAGE_NOTE_ON: | |||
| send_note_on(m->value1, m->value2); | |||
| //send_note_on(m->value1, m->value2); | |||
| break; | |||
| case BRIDGE_MESSAGE_NOTE_OFF: | |||
| send_note_off(m->value1); | |||
| //send_note_off(m->value1); | |||
| break; | |||
| case BRIDGE_MESSAGE_SHOW_GUI: | |||
| if (m->value1) | |||
| @@ -135,31 +131,45 @@ public: | |||
| break; | |||
| case BRIDGE_MESSAGE_QUIT: | |||
| toolkit_quit(); | |||
| pthread_mutex_unlock(&m_lock); | |||
| m_lock.unlock(); | |||
| return false; | |||
| default: | |||
| break; | |||
| } | |||
| m->valid = false; | |||
| QuequeBridgeMessages[i].type = BRIDGE_MESSAGE_NULL; | |||
| } | |||
| else | |||
| break; | |||
| } | |||
| pthread_mutex_unlock(&m_lock); | |||
| m_lock.unlock(); | |||
| 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 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) | |||
| { | |||
| @@ -214,9 +224,14 @@ public: | |||
| #endif | |||
| } | |||
| // --------------------------------------------------------------------- | |||
| protected: | |||
| const char* m_title; | |||
| private: | |||
| void* m_lib; | |||
| pthread_mutex_t m_lock; | |||
| QMutex m_lock; | |||
| QuequeBridgeMessage QuequeBridgeMessages[MAX_BRIDGE_MESSAGES]; | |||
| }; | |||
| @@ -1,20 +1,28 @@ | |||
| # QtCreator project file | |||
| CONFIG = warn_on qt release | |||
| QT = core | |||
| CONFIG += warn_on qt debug link_pkgconfig | |||
| PKGCONFIG = liblo gtk+-2.0 | |||
| TEMPLATE = app | |||
| VERSION = 0.5.0 | |||
| VERSION = 0.5.0 | |||
| SOURCES = \ | |||
| ../carla_bridge_lv2.cpp \ | |||
| ../carla_bridge_gtk2.cpp \ | |||
| ../../carla-bridge/carla_osc.cpp | |||
| ../../carla-bridge/carla_bridge_osc.cpp | |||
| HEADERS = \ | |||
| ../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 = .. \ | |||
| ../../carla \ | |||
| ../../carla-bridge \ | |||
| ../../carla-includes | |||
| @@ -22,9 +30,6 @@ TARGET = carla-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 | |||
| */ | |||
| #include "carla_osc.h" | |||
| #include "carla_bridge_osc.h" | |||
| #include "carla_midi.h" | |||
| #ifdef BUILD_BRIDGE_UI | |||
| #include "carla_bridge_ui.h" | |||
| #else | |||
| // TODO | |||
| #include "carla_plugin.h" | |||
| extern void plugin_bridge_show_gui(bool yesno); | |||
| extern void plugin_bridge_quit(); | |||
| //CarlaPlugin* plugin = CarlaPlugins[0]; | |||
| #endif | |||
| #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; | |||
| 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* 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); | |||
| // 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); | |||
| free(osc_thread_path); | |||
| free(this_thread_path); | |||
| global_osc_server_path = strdup(osc_path_tmp); | |||
| // register message handler and start OSC thread | |||
| lo_server_thread_add_method(global_osc_server_thread, nullptr, nullptr, osc_message_handler, nullptr); | |||
| lo_server_thread_start(global_osc_server_thread); | |||
| // debug our server path just to make sure everything is ok | |||
| qDebug("carla-bridge OSC -> %s\n", global_osc_server_path); | |||
| } | |||
| void osc_close() | |||
| @@ -90,14 +88,16 @@ void osc_clear_data(OscData* 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); | |||
| 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); | |||
| else if (strcmp(method, "program") == 0) | |||
| return osc_handle_program(argv); | |||
| else if (strcmp(method, "midi_program") == 0) | |||
| return osc_handle_midi_program(argv); | |||
| // else if (strcmp(method, "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) | |||
| return osc_handle_show(); | |||
| 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 index = argv[0]->i; | |||
| @@ -173,7 +191,7 @@ int osc_handle_program(lo_arg** argv) | |||
| if (ui && index >= 0) | |||
| ui->queque_message(BRIDGE_MESSAGE_PROGRAM, index, 0, 0.0); | |||
| #else | |||
| if (CarlaPlugins[0]) | |||
| if (CarlaPlugins[0] && index >= 0) | |||
| CarlaPlugins[0]->set_program(index, false, true, true, true); | |||
| #endif | |||
| @@ -186,18 +204,50 @@ int osc_handle_midi_program(lo_arg** argv) | |||
| int program = argv[1]->i; | |||
| #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 | |||
| if (CarlaPlugins[0]) | |||
| if (CarlaPlugins[0] && bank >= 0 && program >= 0) | |||
| CarlaPlugins[0]->set_midi_program_full(bank, program, false, true, true, true); | |||
| #endif | |||
| 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() | |||
| { | |||
| #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) | |||
| { | |||
| 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) | |||
| { | |||
| 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) | |||
| { | |||
| 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) | |||
| { | |||
| 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) | |||
| { | |||
| char target_path[strlen(global_osc_data.path)+19]; | |||
| strcpy(target_path, global_osc_data.path); | |||
| 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) | |||
| { | |||
| 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); | |||
| 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) | |||
| { | |||
| 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); | |||
| 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) | |||
| { | |||
| 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); | |||
| 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 | |||
| */ | |||
| #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_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_hide(); | |||
| int osc_handle_quit(); | |||
| #ifndef BUILD_BRIDGE_UI | |||
| // bridge only | |||
| void osc_send_update(); | |||
| void osc_send_exiting(); | |||
| void osc_send_bridge_ains_peak(int index, double value); | |||
| void osc_send_bridge_aouts_peak(int index, double value); | |||
| void osc_send_bridge_audio_count(int ins, int outs, int total); | |||
| 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_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_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_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(); | |||
| #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; | |||
| static double lv2midi_get_event(LV2_MIDIState* state, | |||
| inline double lv2midi_get_event(LV2_MIDIState* state, | |||
| double* timestamp, | |||
| uint32_t* size, | |||
| 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) { | |||
| 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, | |||
| uint32_t size, | |||
| const unsigned char* data) { | |||
| @@ -2392,7 +2392,7 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
| content += " <CustomData>\n" | |||
| content += " <type>%s</type>\n" % (custom_data['type']) | |||
| 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 += "%s\n" % (custom_data['value']) | |||
| content += " </value>\n" | |||
| @@ -18,25 +18,10 @@ | |||
| #ifndef CARLA_OSC_H | |||
| #define CARLA_OSC_H | |||
| #include "carla_includes.h" | |||
| #include <lo/lo.h> | |||
| #include "carla_osc_includes.h" | |||
| 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_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_program(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_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_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(); | |||
| void osc_global_send_add_plugin(int plugin_id, const char* plugin_name); | |||
| void osc_global_send_remove_plugin(int plugin_id); | |||
| @@ -17,33 +17,6 @@ | |||
| #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" | |||
| extern "C" { | |||
| @@ -73,45 +46,44 @@ const unsigned int PARAMETER_IS_TRIGGER = 0x1000; | |||
| const unsigned int PARAMETER_IS_STRICT_BOUNDS = 0x2000; | |||
| // 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 | |||
| 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 | |||
| 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 { | |||
| LV2_PARAMETER_TYPE_CONTROL, | |||
| @@ -2374,6 +2346,10 @@ public: | |||
| 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; | |||
| @@ -2399,10 +2375,6 @@ public: | |||
| Worker_Feature->handle = this; | |||
| 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; | |||
| 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]->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]->URI = LV2_STATE__makePath; | |||
| 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]->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); | |||
| if (handle) | |||
| @@ -2762,6 +2734,9 @@ public: | |||
| #endif | |||
| } | |||
| // ----------------- DynParam Feature ------------------------------------------------ | |||
| // TODO | |||
| // ----------------- Event Feature --------------------------------------------------- | |||
| static uint32_t carla_lv2_event_ref(LV2_Event_Callback_Data callback_data, LV2_Event* event) | |||
| { | |||
| @@ -2819,6 +2794,18 @@ public: | |||
| 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 --------------------------------------------------- | |||
| 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); | |||
| // 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 | |||
| else if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||
| 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; | |||
| @@ -3025,7 +3003,9 @@ public: | |||
| else if (strcmp(uri, LV2_LOG__Warning) == 0) | |||
| 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 | |||
| if (data) | |||
| @@ -3042,14 +3022,8 @@ public: | |||
| { | |||
| 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 | |||
| else if (strcmp(uri, LV2_ATOM__Chunk) == 0) | |||
| 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; | |||
| @@ -3068,7 +3042,9 @@ public: | |||
| else if (strcmp(uri, LV2_LOG__Warning) == 0) | |||
| 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 | |||
| if (handle) | |||
| @@ -3087,8 +3063,6 @@ public: | |||
| // Event types | |||
| if (urid == CARLA_URI_MAP_ID_MIDI_EVENT) | |||
| return LV2_MIDI__MidiEvent; | |||
| else if (urid == CARLA_URI_MAP_ID_TIME_POSITION) | |||
| return LV2_TIME__Position; | |||
| // Atom types | |||
| else if (urid == CARLA_URI_MAP_ID_ATOM_CHUNK) | |||
| @@ -3166,21 +3140,6 @@ public: | |||
| 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 --------------------------------------------- | |||
| static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol) | |||
| { | |||
| @@ -20,6 +20,33 @@ | |||
| #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 | |||
| typedef float LV2_Data; | |||
| typedef const char* LV2_URI; | |||
| @@ -147,7 +174,6 @@ struct LV2_RDF_PortScalePoint { | |||
| // Port Support Types | |||
| #define LV2_PORT_SUPPORTS_MIDI_EVENT 0x1000 | |||
| #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_OUTPUT(x) ((x) & LV2_PORT_OUTPUT) | |||
| @@ -190,9 +216,29 @@ struct LV2_RDF_PortScalePoint { | |||
| #define LV2_IS_PORT_TRIGGER(x) ((x) & LV2_PORT_TRIGGER) | |||
| // 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 | |||
| struct LV2_RDF_Port { | |||
| @@ -1724,12 +1770,16 @@ inline bool is_lv2_feature_supported(const char* uri) | |||
| return true; | |||
| else if (strcmp(uri, LV2_URID__unmap) == 0) | |||
| return true; | |||
| #ifndef BUILD_BRIDGE_UI | |||
| else if (strcmp(uri, LV2_WORKER__schedule) == 0) | |||
| return true; | |||
| #endif | |||
| else if (strcmp(uri, LV2_PROGRAMS__Host) == 0) | |||
| return true; | |||
| #ifndef BUILD_BRIDGE_UI | |||
| else if (strcmp(uri, LV2_RTSAFE_MEMORY_POOL_URI) == 0) | |||
| return true; | |||
| #endif | |||
| else | |||
| return false; | |||
| } | |||
| @@ -1741,10 +1791,12 @@ inline bool is_lv2_ui_feature_supported(const char* uri) | |||
| #endif | |||
| if (is_lv2_feature_supported(uri)) | |||
| return true; | |||
| #ifndef BUILD_BRIDGE_UI | |||
| else if (strcmp(uri, LV2_DATA_ACCESS_URI) == 0) | |||
| return true; | |||
| else if (strcmp(uri, LV2_INSTANCE_ACCESS_URI) == 0) | |||
| return true; | |||
| #endif | |||
| else if (strcmp(uri, LV2_UI__noUserResize) == 0) | |||
| return true; | |||
| 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 | |||
| else if (strcmp(uri, LV2_UI_PREFIX "makeResident") == 0) | |||
| return true; | |||
| #ifndef BUILD_BRIDGE_UI | |||
| else if (strcmp(uri, LV2_EXTERNAL_UI_URI) == 0) | |||
| return true; | |||
| else if (strcmp(uri, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0) | |||
| return true; | |||
| #endif | |||
| else | |||
| return false; | |||
| } | |||