|
- /* -*- Mode: C ; c-basic-offset: 2 -*- */
- /*****************************************************************************
- *
- * Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
- *
- * LV2 UI bundle shared library for communicating with a DSSI UI
- *
- * 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 (at your option) 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.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307, USA.
- *
- *****************************************************************************/
-
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <sys/types.h>
- #include <unistd.h>
- #include <errno.h>
-
- #include <lo/lo.h>
-
- #include "lv2_external_ui.h"
-
- #define MAX_OSC_PATH 1024
-
- struct control
- {
- LV2_External_UI_Widget virt; /* WARNING: code assumes this is the first struct member */
-
- LV2UI_Controller controller;
- LV2UI_Write_Function write_function;
- void (* ui_closed)(LV2UI_Controller controller);
-
- lo_server osc_server;
-
- bool running; /* true if UI launched and 'exiting' not received */
- bool visible; /* true if 'show' sent */
-
- lo_address osc_address; /* non-NULL if 'update' received */
-
- char osc_control_path[MAX_OSC_PATH];
- char osc_hide_path[MAX_OSC_PATH];
- char osc_quit_path[MAX_OSC_PATH];
- char osc_show_path[MAX_OSC_PATH];
- };
-
- #undef control_ptr
-
- static
- int
- osc_debug_handler(
- const char * path,
- const char * types,
- lo_arg ** argv,
- int argc,
- void * data,
- void * user_data)
- {
- int i;
-
- printf("got unhandled OSC message:\n");
- printf("path: <%s>\n", path);
- fflush(stdout);
- for (i = 0; i < argc; i++)
- {
- printf("arg %d '%c' ", i, types[i]);
- lo_arg_pp(types[i], argv[i]);
- printf("\n");
- }
- fflush(stdout);
-
- return 1;
- }
-
- int
- osc_exiting_handler(
- struct control * control_ptr,
- lo_arg ** argv)
- {
- //printf("OSC: got UI exit notification\n");
-
- control_ptr->running = false;
- control_ptr->visible = false;
-
- if (control_ptr->osc_address)
- {
- lo_address_free(control_ptr->osc_address);
- }
-
- control_ptr->ui_closed(control_ptr->controller);
-
- return 0;
- }
-
- int
- osc_control_handler(
- struct control * control_ptr,
- lo_arg ** argv)
- {
- int port = argv[0]->i;
- float value = argv[1]->f;
-
- //printf("OSC control handler: port %d = %f\n", port, value);
-
- control_ptr->write_function(control_ptr->controller, (uint32_t)port, sizeof(float), 0, &value);
-
- return 0;
- }
-
- int
- osc_update_handler(
- struct control * control_ptr,
- lo_arg ** argv)
- {
- const char * url = &argv[0]->s;
- char * path;
- char * host;
- char * port;
-
- //printf("OSC: got update request from <%s>\n", url);
-
- if (control_ptr->osc_address)
- {
- return 0;
- }
-
- host = lo_url_get_hostname(url);
- port = lo_url_get_port(url);
- control_ptr->osc_address = lo_address_new(host, port);
- free(host);
- free(port);
-
- path = lo_url_get_path(url);
-
- sprintf(control_ptr->osc_control_path, "%scontrol", path);
- sprintf(control_ptr->osc_hide_path, "%shide", path);
- sprintf(control_ptr->osc_show_path, "%sshow", path);
- sprintf(control_ptr->osc_quit_path, "%squit", path);
-
- free(path);
-
- control_ptr->running = true;
-
- return 0;
- }
-
- #define control_ptr ((struct control *)user_data)
-
- static
- int
- osc_message_handler(
- const char * path,
- const char * types,
- lo_arg ** argv,
- int argc,
- void * data,
- void * user_data)
- {
- const char *method;
-
- method = path;
- if (method[0] != '/' || method[1] != '/')
- return osc_debug_handler(path, types, argv, argc, data, user_data);
- method += 2;
-
- if (!strcmp(method, "update") && argc == 1 && !strcmp(types, "s"))
- {
- return osc_update_handler(control_ptr, argv);
- }
- else if (!strcmp(method, "control") && argc == 2 && !strcmp(types, "if"))
- {
- return osc_control_handler(control_ptr, argv);
- }
- else if (!strcmp(method, "exiting") && argc == 0)
- {
- return osc_exiting_handler(control_ptr, argv);
- }
-
- return osc_debug_handler(path, types, argv, argc, data, user_data);
- }
-
- #undef control_ptr
-
- #define control_ptr ((struct control *)_this_)
-
- static
- void
- run(
- LV2_External_UI_Widget * _this_)
- {
- //printf("run() called\n");
- while (lo_server_recv_noblock(control_ptr->osc_server, 0) != 0) {}
- }
-
- static
- void
- show(
- LV2_External_UI_Widget * _this_)
- {
- //printf("show() called\n");
-
- if (control_ptr->visible)
- {
- return;
- }
-
- if (control_ptr->osc_address)
- {
- lo_send(control_ptr->osc_address, control_ptr->osc_show_path, "");
- control_ptr->visible = true;
- }
- }
-
- static
- void
- hide(
- LV2_External_UI_Widget * _this_)
- {
- //printf("hide() called\n");
-
- if (!control_ptr->visible || !control_ptr->osc_address)
- {
- return;
- }
-
- lo_send(control_ptr->osc_address, control_ptr->osc_hide_path, "");
- control_ptr->visible = false;
- }
-
- #undef control_ptr
-
- static
- LV2UI_Handle
- instantiate(
- const struct _LV2UI_Descriptor * descriptor,
- const char * plugin_uri,
- const char * bundle_path,
- LV2UI_Write_Function write_function,
- LV2UI_Controller controller,
- LV2UI_Widget * widget,
- const LV2_Feature * const * features)
- {
- struct control * control_ptr;
- LV2_External_UI_Host * ui_host_ptr;
- char * filename;
- char * osc_url;
-
- //printf("instantiate('%s', '%s') called\n", plugin_uri, bundle_path);
-
- ui_host_ptr = NULL;
- while (*features != NULL)
- {
- if (strcmp((*features)->URI, LV2_EXTERNAL_UI__Host) == 0)
- {
- ui_host_ptr = (*features)->data;
- }
-
- features++;
- }
-
- if (ui_host_ptr == NULL)
- {
- goto fail;
- }
-
- control_ptr = malloc(sizeof(struct control));
- if (control_ptr == NULL)
- {
- goto fail;
- }
-
- control_ptr->virt.run = run;
- control_ptr->virt.show = show;
- control_ptr->virt.hide = hide;
-
- control_ptr->controller = controller;
- control_ptr->write_function = write_function;
- control_ptr->ui_closed = ui_host_ptr->ui_closed;
-
- filename = malloc(strlen(bundle_path) + strlen(UI_EXECUTABLE) + 1);
- if (filename == NULL)
- {
- goto fail_free_control;
- }
-
- strcpy(filename, bundle_path);
- strcat(filename, UI_EXECUTABLE);
-
- control_ptr->running = false;
- control_ptr->visible = false;
- control_ptr->osc_address = NULL;
-
- control_ptr->osc_server = lo_server_new(NULL, NULL);
- osc_url = lo_server_get_url(control_ptr->osc_server);
- //printf("host OSC URL is %s\n", osc_url);
- lo_server_add_method(control_ptr->osc_server, NULL, NULL, osc_message_handler, control_ptr);
-
- if (fork() == 0)
- {
- execlp(
- filename,
- filename,
- osc_url,
- plugin_uri,
- plugin_uri,
- ui_host_ptr->plugin_human_id != NULL ? ui_host_ptr->plugin_human_id : "",
- NULL);
- fprintf(stderr, "exec of UI failed: %s", strerror(errno));
- exit(1);
- }
-
- while (!control_ptr->running)
- {
- if (lo_server_recv_noblock(control_ptr->osc_server, 0) == 0)
- {
- usleep(300000);
- }
- }
-
- *widget = (LV2UI_Widget)control_ptr;
-
- return (LV2UI_Handle)control_ptr;
-
- fail_free_control:
- free(control_ptr);
-
- fail:
- return NULL;
- }
-
- #define control_ptr ((struct control *)ui)
-
- static
- void
- cleanup(
- LV2UI_Handle ui)
- {
- //printf("cleanup() called\n");
- free(control_ptr);
- }
-
- static
- void
- port_event(
- LV2UI_Handle ui,
- uint32_t port_index,
- uint32_t buffer_size,
- uint32_t format,
- const void * buffer)
- {
- //printf("port_event(%u, %f) called\n", (unsigned int)port_index, *(float *)buffer);
-
- lo_send(control_ptr->osc_address, control_ptr->osc_control_path, "if", (int)port_index, *(float *)buffer);
- }
-
- #undef control_ptr
-
- static LV2UI_Descriptor descriptors[] =
- {
- {UI_URI, instantiate, cleanup, port_event, NULL}
- };
-
- const LV2UI_Descriptor *
- lv2ui_descriptor(
- uint32_t index)
- {
- //printf("lv2ui_descriptor(%u) called\n", (unsigned int)index);
-
- if (index >= sizeof(descriptors) / sizeof(descriptors[0]))
- {
- return NULL;
- }
-
- return descriptors + index;
- }
|