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