From ebe35fe98381ff6dcabf5a1a86ed5e05e4e992b0 Mon Sep 17 00:00:00 2001 From: Jamie Bullock Date: Thu, 2 Feb 2012 19:16:50 +0000 Subject: - simplified file layout svn path=/trunk/externals/postlude/; revision=15936 --- pluginhost~/Makefile | 4 +- pluginhost~/doc/pluginhost~-help.pd | 161 ----- pluginhost~/handlers_osc.c | 311 ++++++++++ pluginhost~/handlers_osc.h | 40 ++ pluginhost~/handlers_pd.c | 1153 +++++++++++++++++++++++++++++++++++ pluginhost~/handlers_pd.h | 43 ++ pluginhost~/jload.c | 214 +++++++ pluginhost~/jsearch.c | 156 +++++ pluginhost~/jutils.h | 69 +++ pluginhost~/ph_common.c | 1117 +++++++++++++++++++++++++++++++++ pluginhost~/ph_common.h | 171 ++++++ pluginhost~/pluginhost~-help.pd | 161 +++++ pluginhost~/pluginhost~-meta.pd | 9 + pluginhost~/pluginhost~.c | 95 +++ pluginhost~/src/handlers_osc.c | 311 ---------- pluginhost~/src/handlers_osc.h | 40 -- pluginhost~/src/handlers_pd.c | 1153 ----------------------------------- pluginhost~/src/handlers_pd.h | 43 -- pluginhost~/src/jload.c | 214 ------- pluginhost~/src/jsearch.c | 156 ----- pluginhost~/src/jutils.h | 69 --- pluginhost~/src/ph_common.c | 1117 --------------------------------- pluginhost~/src/ph_common.h | 171 ------ pluginhost~/src/pluginhost~.c | 95 --- 24 files changed, 3541 insertions(+), 3532 deletions(-) delete mode 100644 pluginhost~/doc/pluginhost~-help.pd create mode 100644 pluginhost~/handlers_osc.c create mode 100644 pluginhost~/handlers_osc.h create mode 100644 pluginhost~/handlers_pd.c create mode 100644 pluginhost~/handlers_pd.h create mode 100644 pluginhost~/jload.c create mode 100644 pluginhost~/jsearch.c create mode 100644 pluginhost~/jutils.h create mode 100644 pluginhost~/ph_common.c create mode 100644 pluginhost~/ph_common.h create mode 100644 pluginhost~/pluginhost~-help.pd create mode 100644 pluginhost~/pluginhost~-meta.pd create mode 100644 pluginhost~/pluginhost~.c delete mode 100644 pluginhost~/src/handlers_osc.c delete mode 100644 pluginhost~/src/handlers_osc.h delete mode 100644 pluginhost~/src/handlers_pd.c delete mode 100644 pluginhost~/src/handlers_pd.h delete mode 100644 pluginhost~/src/jload.c delete mode 100644 pluginhost~/src/jsearch.c delete mode 100644 pluginhost~/src/jutils.h delete mode 100644 pluginhost~/src/ph_common.c delete mode 100644 pluginhost~/src/ph_common.h delete mode 100644 pluginhost~/src/pluginhost~.c diff --git a/pluginhost~/Makefile b/pluginhost~/Makefile index bb76067..d7a58ff 100644 --- a/pluginhost~/Makefile +++ b/pluginhost~/Makefile @@ -10,10 +10,10 @@ LIBRARY_NAME = pluginhost~ # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically -SOURCES = src/pluginhost~.c +SOURCES = pluginhost~.c # Additional source files -EXTRASOURCES = src/handlers_osc.c src/jload.c src/ph_common.c src/handlers_pd.c src/jsearch.c +EXTRASOURCES = handlers_osc.c jload.c ph_common.c handlers_pd.c jsearch.c # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically diff --git a/pluginhost~/doc/pluginhost~-help.pd b/pluginhost~/doc/pluginhost~-help.pd deleted file mode 100644 index 1227d33..0000000 --- a/pluginhost~/doc/pluginhost~-help.pd +++ /dev/null @@ -1,161 +0,0 @@ -#N canvas 41 96 1411 654 10; -#X obj 1268 524 catch~ mix; -#X text 602 15 pluginhost~ - a DSSI host for Pure Data --------------------------------- -; -#X obj 7 63 cnv 15 1400 300 empty empty pluginhost~_instance_1 20 12 -0 14 -257472 -66577 0; -#X obj 443 203 line; -#X msg 443 182 \$1 10; -#X obj 441 225 expr $f1 / 127 * 16383; -#X msg 443 122 0; -#X floatatom 300 185 5 0 0 0 - - -; -#X floatatom 443 165 5 0 0 0 - - -; -#X msg 72 256 n \$1; -#X obj 110 256 r chan; -#X obj 51 231 list prepend n 2; -#X obj 300 226 list prepend c 2; -#X obj 51 208 pack f f; -#X msg 33 147 60; -#X msg 78 147 80; -#X msg 300 205 7 \$1; -#X obj 441 247 list prepend b 2 0; -#X obj 441 324 throw~ mix; -#X obj 119 148 hsl 128 15 60 80 0 0 empty empty empty -2 -6 0 8 -262144 --1 -1 0 1; -#X obj 167 206 select -1; -#X obj 356 250 r chan; -#X obj 303 146 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144 --1 -1 0 1; -#X obj 446 144 hsl 128 15 -63 63 0 1 empty empty empty -2 -6 0 8 -262144 --1 -1 6300 1; -#X obj 600 291 r dssi1-config; -#X obj 708 179 s dssi1-config; -#X obj 912 178 s dssi1-config; -#X obj 1194 180 s dssi1-config; -#X floatatom 595 142 5 0 0 0 - - -; -#X msg 318 250 c \$1; -#X obj 528 268 r chan; -#X msg 473 268 b \$1 0; -#X obj 1014 337 s chan; -#X floatatom 1015 319 5 1 2 1 channel - -; -#X text 283 98 ----control change----; -#X obj 667 222 r chan; -#X text 447 97 ----pitch bend----; -#X text 585 97 --program change--; -#X text 105 96 -----notes-----; -#X text 718 97 --sysex patch/bank load--; -#X obj 5 371 cnv 15 600 300 empty empty pluginhost~_instance_2 20 12 -0 14 -225280 -66577 0; -#X obj 435 620 throw~ mix; -#X obj 474 122 loadbang; -#X msg 613 221 p \$1 0; -#X text 940 96 --configuration--; -#X text 947 113 (key value pair); -#X text 867 279 Select channel (hexter instance) for note \, bend \, -program and control data:; -#X obj 595 199 list prepend p 2 0; -#X text 1126 98 --show/hide GUI--; -#X obj 49 186 makenote 80 10000; -#X msg 1282 136 reset; -#X msg 1340 136 reset 1; -#X text 1286 98 -reset plugin-; -#X text 1286 115 (all notes off); -#X obj 229 315 print; -#X msg 78 305 listplugins; -#X msg 101 329 info; -#X msg 709 134 dssi load TX-SYX/TFI2.SYX 2; -#X msg 710 154 dssi load TX-SYX/TFI1.SYX 1; -#X msg 910 134 dssi configure polyphony 10 2; -#X msg 911 156 dssi configure GLOBAL:polyphony 10; -#X msg 1134 114 dssi hide; -#X msg 1135 135 dssi show; -#X msg 1206 114 dssi show 2; -#X text 806 212 LAST ARGUMENT GIVES PLUGIN INSTANCE TO BE CONFIGURED -\, NO LAST ARGUMENT=(ALL INSTANCES); -#X obj 388 620 print; -#X text 738 458 Usage: [pluginhost~ <[path to libary:plugin name] or -[plugin name]> ]; -#X obj 229 291 pluginhost~ hexter.so:hexter 2; -#X msg 193 342 control #1 445; -#X obj 451 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 --1 -1 0 1; -#X obj 378 582 pluginhost~ sine_faaa 6 -------------; -#X obj 284 438 expr $f1 \; $f1*2 \; $f1*3 \; $f1*4 \; $f1*5 \; $f1*6 -; -#X obj 285 397 loadbang; -#X msg 285 419 220; -#X obj 471 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 --1 -1 0 1; -#X obj 491 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 --1 -1 0 1; -#X obj 511 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 --1 -1 0 1; -#X obj 531 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 --1 -1 0 1; -#X obj 551 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 --1 -1 0 1; -#X text 591 561 <- Audio rate control inputs can be audio or control -values; -#X text 14 491 Experimental - use with caution!; -#X msg 54 509 plug sine_faac 6; -#X obj 1266 547 output~; -#X msg 733 376 dssi configure pitch_bend_range 12 1; -#X obj 1109 341 loadbang; -#X msg 1109 384 1; -#X msg 742 412 dssi configure portamento_time 50 1; -#X connect 0 0 82 0; -#X connect 0 0 82 1; -#X connect 3 0 5 0; -#X connect 4 0 3 0; -#X connect 5 0 17 0; -#X connect 6 0 23 0; -#X connect 7 0 16 0; -#X connect 8 0 4 0; -#X connect 9 0 11 1; -#X connect 10 0 9 0; -#X connect 11 0 67 0; -#X connect 12 0 67 0; -#X connect 13 0 11 0; -#X connect 14 0 49 0; -#X connect 15 0 49 0; -#X connect 16 0 12 0; -#X connect 17 0 67 0; -#X connect 19 0 49 0; -#X connect 20 1 49 0; -#X connect 21 0 29 0; -#X connect 22 0 7 0; -#X connect 23 0 8 0; -#X connect 24 0 67 0; -#X connect 28 0 47 0; -#X connect 29 0 12 1; -#X connect 30 0 31 0; -#X connect 31 0 17 1; -#X connect 33 0 32 0; -#X connect 35 0 43 0; -#X connect 42 0 6 0; -#X connect 43 0 47 1; -#X connect 47 0 67 0; -#X connect 49 0 13 0; -#X connect 49 1 13 1; -#X connect 50 0 27 0; -#X connect 51 0 27 0; -#X connect 55 0 67 0; -#X connect 56 0 67 0; -#X connect 57 0 25 0; -#X connect 58 0 25 0; -#X connect 59 0 26 0; -#X connect 60 0 26 0; -#X connect 61 0 27 0; -#X connect 62 0 27 0; -#X connect 63 0 27 0; -#X connect 67 0 54 0; -#X connect 67 1 18 0; -#X connect 67 2 18 0; -#X connect 68 0 67 0; -#X connect 72 0 73 0; -#X connect 73 0 71 0; -#X connect 81 0 70 0; -#X connect 83 0 67 0; -#X connect 84 0 85 0; -#X connect 85 0 33 0; -#X connect 86 0 67 0; diff --git a/pluginhost~/handlers_osc.c b/pluginhost~/handlers_osc.c new file mode 100644 index 0000000..4114baf --- /dev/null +++ b/pluginhost~/handlers_osc.c @@ -0,0 +1,311 @@ +/* pluginhost~ - A plugin host for Pd + * + * Copyright (C) 2006 Jamie Bullock and others + * + * This file incorporates code from the following sources: + * + * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. + * + * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 + * + * liblo (CPL license): Copyright (C) 2004 Steve Harris + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include "ph_common.h" + +/* + * taken from liblo lo_url_get_path by Steve Harris et al + */ +char *osc_get_valid_path(const char *url) +{ + char *path = malloc(strlen(url)); + + if (sscanf(url, "osc://%*[^:]:%*[0-9]%s", path)) { + return path; + } + if (sscanf(url, "osc.%*[^:]://%*[^:]:%*[0-9]%s", path) == 1) { + return path; + } + if (sscanf(url, "osc.unix://%*[^/]%s", path) == 1) { + return path; + } + if (sscanf(url, "osc.%*[^:]://%s", path)) { + return path; + } + + /* doesnt look like an OSC URL with port number and path*/ + return NULL; +} +/* end liblo code */ + +void handle_osc_debug(const char *path) +{ + + ph_debug_post("got unhandled OSC message:\npath: <%s>\n", path); + +} + +void handle_osc_program(ph *x, t_atom *argv, unsigned int i) +{ + unsigned long bank; + unsigned long program; + unsigned int n; + bool found; + ph_instance *instance; + + bank = atom_getfloat(&argv[0]); + program = atom_getfloat(&argv[1]); + instance = &x->instances[i]; + found = false; + + ph_debug_post("%d programs", instance->plugin_pgm_count); + + for (n = 0; n < instance->plugin_pgm_count; ++n) { + if (instance->plugin_pgms[n].Bank == bank && + instance->plugin_pgms[n].Program == program) { + ph_debug_post("OSC: setting bank %u, program %u, name %s\n", + bank, program, instance->plugin_pgms[n].Name); + found = true; + break; + } + } + + if (!found) { + pd_error(x, "UI requested unknown program: bank %lu, program %lu: " + "sending to plugin anyway (plugin should ignore it)\n", + bank, program); + } + + instance->pending_bank_msb = bank / 128; + instance->pending_bank_lsb = bank % 128; + instance->pending_pgm_change = program; + + ph_debug_post("bank = %d, program = %d, BankMSB = %d BankLSB = %d", + bank, program, instance->pending_bank_msb, + instance->pending_bank_lsb); + + ph_program_change(x, i); + +} + +void handle_osc_control(ph *x, t_atom *argv, int i) +{ + int port; + LADSPA_Data value; + ph_instance *instance; + + port = (int)atom_getfloat(&argv[0]); + value = atom_getfloat(&argv[1]); + instance = &x->instances[i]; + + x->plugin_control_input[instance->plugin_port_ctlin_numbers[port]] = value; + ph_debug_post("OSC: port %d = %f", port, value); + +} + +void handle_osc_midi(ph *x, t_atom *argv, unsigned int i) +{ + pd_error(x, "MIDI over OSC currently unsupported"); +} + +void handle_osc_configure(ph *x, t_atom *argv, int i) +{ + const char *key; + const char *value; + char *message; + + key = atom_getsymbol(&argv[0])->s_name; + value = atom_getsymbol(&argv[1])->s_name; + + ph_debug_post("%s()", __FUNCTION__); + + if (!x->descriptor->configure) { + return; + } + + if (!strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, + strlen(DSSI_RESERVED_CONFIGURE_PREFIX))) { + pd_error(x,"UI for plugin '' attempted to use reserved " + "configure key \"%s\", ignoring", key); + return; + } + + message = x->descriptor->configure(x->instance_handles[i], key, value); + + if (message) { + pd_error(x, "on configure '%s', plugin '' returned error '%s'", + key, message); + free(message); + } + + ph_query_programs(x, i); + +} + +void handle_osc_exiting(ph *x, t_atom *argv, int i) +{ + + ph_instance *instance; + + instance = &x->instances[i]; + + free(instance->ui_osc_control_path); + free(instance->ui_osc_configure_path); + free(instance->ui_osc_hide_path); + free(instance->ui_osc_program_path); + free(instance->ui_osc_show_path); + free(instance->ui_osc_quit_path); + instance->ui_osc_control_path = NULL; + instance->ui_osc_configure_path = NULL; + instance->ui_osc_hide_path = NULL; + instance->ui_osc_program_path = NULL; + instance->ui_osc_show_path = NULL; + instance->ui_osc_quit_path = NULL; + instance->ui_hidden = true; + +} + +void handle_osc_update(ph *x, t_atom *argv, unsigned int i) +{ + const char *url; + const char *path; + unsigned int n; + unsigned int ac = 3; + t_atom av[ac]; + ph_configure_pair *p; + ph_instance *instance; + + instance = &x->instances[i]; + url = atom_getsymbol(&argv[0])->s_name; + p = x->configure_buffer_head; + + ph_debug_post("OSC: got update request from <%s>, instance %d", + url, instance); + + path = osc_get_valid_path(url); + + if(path == NULL) { + pd_error(x, "invalid url: %s", url); + return; + } + + if (instance->ui_osc_control_path) { + free(instance->ui_osc_control_path); + } + instance->ui_osc_control_path = malloc(strlen(path) + 10); + sprintf(instance->ui_osc_control_path, "%s/control", path); + + if (instance->ui_osc_configure_path) { + free(instance->ui_osc_configure_path); + } + instance->ui_osc_configure_path = malloc(strlen(path) + 12); + sprintf(instance->ui_osc_configure_path, "%s/configure", path); + + if (instance->ui_osc_program_path) { + free(instance->ui_osc_program_path); + } + instance->ui_osc_program_path = malloc(strlen(path) + 10); + sprintf(instance->ui_osc_program_path, "%s/program", path); + + if (instance->ui_osc_quit_path) { + free(instance->ui_osc_quit_path); + } + instance->ui_osc_quit_path = malloc(strlen(path) + 10); + sprintf(instance->ui_osc_quit_path, "%s/quit", path); + + if (instance->ui_osc_show_path) { + free(instance->ui_osc_show_path); + } + instance->ui_osc_show_path = malloc(strlen(path) + 10); + sprintf(instance->ui_osc_show_path, "%s/show", path); + + if (instance->ui_osc_hide_path) { + free(instance->ui_osc_hide_path); + } + instance->ui_osc_hide_path = (char *)malloc(strlen(path) + 10); + sprintf(instance->ui_osc_hide_path, "%s/hide", path); + + free((char *)path); + + while(p){ + if(p->instance == i) { + ph_send_configure(x, p->key, p->value, i); + } + p = p->next; + } + + /* Send current bank/program */ + if (instance->pending_pgm_change >= 0) { + ph_program_change(x, i); + } + + ph_debug_post("pending_pgm_change = %d", instance->pending_pgm_change); + + if (instance->pending_pgm_change < 0) { + unsigned long bank; + unsigned long program; + ac = 3; + + program = instance->current_pgm; + bank = instance->current_bank; + instance->ui_needs_pgm_update = 0; + + SETSYMBOL(av, gensym(instance->ui_osc_program_path)); + SETFLOAT(av+1, bank); + SETFLOAT(av+2, program); + + ph_instance_send_osc(x->message_out, instance, ac, av); + + } + + /* Send control ports */ + for (n = 0; n < x->plugin_control_ins; n++) { + + ac = 3; + + SETSYMBOL(av, gensym(instance->ui_osc_control_path)); + SETFLOAT(av+1, x->plugin_ctlin_port_numbers[n]); + SETFLOAT(av+2, x->plugin_control_input[n]); + + ph_instance_send_osc(x->message_out, instance, ac, av); + + ph_debug_post("Port: %d, Default value: %.2f", + x->plugin_ctlin_port_numbers[n], x->plugin_control_input[n]); + + } + + /* Send 'show' */ + if (instance->ui_show) { + + ac = 2; + + SETSYMBOL(av, gensym(instance->ui_osc_show_path)); + SETSYMBOL(av, gensym("")); + + ph_instance_send_osc(x->message_out, instance, ac, av); + + instance->ui_hidden = false; + instance->ui_show = false; + } +} + diff --git a/pluginhost~/handlers_osc.h b/pluginhost~/handlers_osc.h new file mode 100644 index 0000000..a45c56a --- /dev/null +++ b/pluginhost~/handlers_osc.h @@ -0,0 +1,40 @@ +/* pluginhost~ - A plugin host for Pd + * + * Copyright (C) 2006 Jamie Bullock and others + * + * This file incorporates code from the following sources: + * + * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. + * + * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 + * + * liblo (CPL license): Copyright (C) 2004 Steve Harris + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "m_pd.h" +#include "ph_common.h" + +void handle_osc_debug(const char *path); +void handle_osc_program(ph *x, t_atom *argv, unsigned int i); +void handle_osc_control(ph *x, t_atom *argv, int i); +void handle_osc_midi(ph *x, t_atom *argv, unsigned int i); +void handle_osc_configure(ph *x, t_atom *argv, int i); +void handle_osc_exiting(ph *x, t_atom *argv, int i); +void handle_osc_update(ph *x, t_atom *argv, unsigned int i); + diff --git a/pluginhost~/handlers_pd.c b/pluginhost~/handlers_pd.c new file mode 100644 index 0000000..bf5fd45 --- /dev/null +++ b/pluginhost~/handlers_pd.c @@ -0,0 +1,1153 @@ +/* %s - A plugin host for Pd + * + * Copyright (C) 2006 Jamie Bullock and others + * + * This file incorporates code from the following sources: + * + * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. + * + * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 + * + * liblo (CPL license): Copyright (C) 2004 Steve Harris + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include /* for uint8_t */ + +#include "jutils.h" +#include "handlers_osc.h" +#include "ph_common.h" + +#define DX7_VOICE_SIZE_PACKED 128 /*From hexter_types.h by Sean Bolton */ +#define DX7_DUMP_SIZE_BULK 4096+8 +#define DX7_BANK_SIZE 32 +#define DX7_MAX_PATCH_SIZE 16384 +#define ASCII_t 116 +#define ASCII_p 112 +#define ASCII_n 110 +#define ASCII_c 99 +#define ASCII_b 98 +#define ASCII_a 97 +#define TYPE_STRING_SIZE 20 +#define OSC_ADDR_MAX 8192 + +#if DEBUG == 1 +#define CHECKSUM_PATCH_FILES_ON_LOAD 1 +#endif + +#define CLASS_NAME_STR "pluginhost~" + + +/*From dx7_voice.h by Sean Bolton */ +typedef struct _dx7_patch_t { + uint8_t data[128]; +} dx7_patch_t; + + +/*From dx7_voice_data.c by Sean Bolton */ +static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* + * dx7_bulk_dump_checksum + ** Taken from dx7_voice_data.c by Sean Bolton ** + */ +static int +dx7_bulk_dump_checksum(uint8_t *data, int length) +{ + int sum = 0; + int i; + + for (i = 0; i < length; sum -= data[i++]); + return sum & 0x7F; +} + +/* + * encode_7in6 + ** Taken from gui_data.c by Sean Bolton ** + * + * encode a block of 7-bit data, in base64-ish style + */ +char *encode_7in6(uint8_t *data, int length) +{ + char *buffer; + int in, reg, above, below, shift, out; + int outchars = (length * 7 + 5) / 6; + unsigned int sum = 0; + + if (!(buffer = (char *)malloc(25 + outchars))) + return NULL; + + out = snprintf(buffer, 12, "%d ", length); + + in = reg = above = below = 0; + while (outchars) { + if (above == 6) { + buffer[out] = base64[reg >> 7]; + reg &= 0x7f; + above = 0; + out++; + outchars--; + } + if (below == 0) { + if (in < length) { + reg |= data[in] & 0x7f; + sum += data[in]; + } + below = 7; + in++; + } + shift = 6 - above; + if (below < shift) shift = below; + reg <<= shift; + above += shift; + below -= shift; + } + + snprintf(buffer + out, 12, " %d", sum); + + return buffer; +} + + + +/* end hexter code */ + + +static void ph_ladspa_description(ph *x, t_atom *at, + DSSI_Descriptor *psDescriptor){ + at[0].a_w.w_symbol = + gensym ((char*)psDescriptor->LADSPA_Plugin->Name); + outlet_anything (x->message_out, gensym ("name"), 1, at); + at[0].a_w.w_symbol = + gensym ((char*)psDescriptor->LADSPA_Plugin->Label); + outlet_anything (x->message_out, gensym ("label"), 1, at); + at[0].a_type = A_FLOAT; + at[0].a_w.w_float = psDescriptor->LADSPA_Plugin->UniqueID; + outlet_anything (x->message_out, gensym ("id"), 1, at); + at[0].a_type = A_SYMBOL; + at[0].a_w.w_symbol = + gensym ((char*)psDescriptor->LADSPA_Plugin->Maker); + outlet_anything (x->message_out, gensym ("maker"), 1, at); +} + +static void ph_midibuf_add(ph *x, int type, unsigned int chan, int param, int val) +{ + + if(chan > x->n_instances - 1){ + pd_error(x, "note discarded: MIDI data is for a bogus channel"); + return; + } + + t_int time_ref = x->time_ref; + t_int mapped; + + //mapped = x->channel_map[chan + 1] - 1; + /* FIX: get rid of mapping functionality */ + mapped = chan; + + x->midi_event_buf[x->buf_write_index].time.time.tv_sec = + (t_int)(clock_gettimesince(time_ref) * .001); + x->midi_event_buf[x->buf_write_index].time.time.tv_nsec = + (t_int)(clock_gettimesince(time_ref) * 1000); /*actually usec - we can't store this in nsec! */ + + if ((type == SND_SEQ_EVENT_NOTEON && val != 0) || + type != SND_SEQ_EVENT_NOTEON) { + x->midi_event_buf[x->buf_write_index].type = type; + switch (type) { + case SND_SEQ_EVENT_NOTEON: + x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; + x->midi_event_buf[x->buf_write_index].data.note.note = param; + x->midi_event_buf[x->buf_write_index].data.note.velocity = val; + break; + case SND_SEQ_EVENT_NOTEOFF: + x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; + x->midi_event_buf[x->buf_write_index].data.note.note = param; + x->midi_event_buf[x->buf_write_index].data.note.velocity = val; + break; + case SND_SEQ_EVENT_CONTROLLER: + x->midi_event_buf[x->buf_write_index].data.control.channel = mapped; + x->midi_event_buf[x->buf_write_index].data.control.param = param; + x->midi_event_buf[x->buf_write_index].data.control.value = val; + break; + case SND_SEQ_EVENT_PITCHBEND: + x->midi_event_buf[x->buf_write_index].data.control.channel = mapped; + x->midi_event_buf[x->buf_write_index].data.control.param = 0; + x->midi_event_buf[x->buf_write_index].data.control.value = val; + break; + case SND_SEQ_EVENT_CHANPRESS: + x->midi_event_buf[x->buf_write_index].data.control.channel = mapped; + x->midi_event_buf[x->buf_write_index].data.control.param = 0; + x->midi_event_buf[x->buf_write_index].data.control.value = val; + break; + case SND_SEQ_EVENT_KEYPRESS: + x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; + x->midi_event_buf[x->buf_write_index].data.note.note = param; + x->midi_event_buf[x->buf_write_index].data.note.velocity = val; + break; + case SND_SEQ_EVENT_PGMCHANGE: + x->instances[mapped].pending_bank_msb = (param - 1) / 128; + x->instances[mapped].pending_bank_lsb = (param - 1) % 128; + x->instances[mapped].pending_pgm_change = val; + x->instances[mapped].ui_needs_pgm_update = 1; + ph_debug_post("pgm chabge received in buffer: MSB: %d, LSB %d, prog: %d", + x->instances[mapped].pending_bank_msb, x->instances[mapped].pending_bank_lsb, val); + + ph_program_change(x, mapped); + break; + } + } + else if (type == SND_SEQ_EVENT_NOTEON && val == 0) { + x->midi_event_buf[x->buf_write_index].type = SND_SEQ_EVENT_NOTEOFF; + x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; + x->midi_event_buf[x->buf_write_index].data.note.note = param; + x->midi_event_buf[x->buf_write_index].data.note.velocity = val; + } + + ph_debug_post("MIDI received in buffer: chan %d, param %d, val %d, mapped to %d", + chan, param, val, mapped); + + x->buf_write_index = (x->buf_write_index + 1) % EVENT_BUFSIZE; +} + +static void ph_set_control_input_by_index (ph *x, + unsigned int ctrl_input_index, float value, unsigned int i) +{ + long port, portno; + t_int argc = 3; + t_atom argv[argc]; + ph_instance *instance; + + if (ctrl_input_index >= x->plugin_control_ins) { + pd_error(x, "control port number %d is out of range [1, %d]", + ctrl_input_index + 1, x->plugin_control_ins); + return; + } + + ph_debug_post("ctrl input number = %d", ctrl_input_index); + + port = x->plugin_ctlin_port_numbers[ctrl_input_index]; + + instance = &x->instances[i]; + + /* TODO - temporary hack */ + if(x->is_dssi) { + portno = instance->plugin_port_ctlin_numbers[ctrl_input_index + 1]; + } else { + portno = instance->plugin_port_ctlin_numbers[ctrl_input_index]; + } + + ph_debug_post("Global ctrl input number = %d", ctrl_input_index); + ph_debug_post("Global ctrl input value = %.2f", value); + + /* set the appropriate control port value */ + x->plugin_control_input[portno] = value; + + /* Update the UI if there is one */ + if(!x->is_dssi){ + return; + } + + if(instance->ui_osc_control_path == NULL){ + pd_error(x, "unable to send to NULL control path"); + return; + } + + SETSYMBOL(argv, gensym(instance->ui_osc_control_path)); + SETFLOAT(argv+1, port); + SETFLOAT(argv+2, value); + ph_instance_send_osc(x->message_out, instance, argc, argv); + +} + +static unsigned ph_get_param_num (ph *x, const char *str) +/* find out if str points to a parameter number or not and return the + number or zero. The number string has to begin with a '#' character */ +{ + long num = 0; + char* strend = NULL; + + if (str == NULL) { + return 0; + } + if (str[0] != '#') { + return 0; + } + num = strtol (&str[1], &strend, 10); + if (str[1] == 0 || *strend != 0) { + /* invalid string */ + return 0; + } + else if (num >= 1 && num <= (long)x->plugin_control_ins) { + /* string ok and within range */ + return (unsigned)num; + } + else { + /* number out of range */ + return 0; + } +} + +static void ph_set_control_input_by_name (ph *x, + const char* name, + float value, + unsigned int i) +{ + unsigned port_index = 0; + unsigned ctrl_input_index = 0; + int found_port = 0; /* boolean */ + + if (name == NULL || strlen (name) == 0) { + pd_error(x, "no control port name specified"); + return; + } + + /* compare control name to LADSPA control input ports' names + case-insensitively */ + found_port = 0; + ctrl_input_index = 0; + for (port_index = 0; port_index < x->descriptor->LADSPA_Plugin->PortCount; + port_index++) + { + LADSPA_PortDescriptor port_type; + port_type = x->descriptor->LADSPA_Plugin->PortDescriptors[port_index]; + if (LADSPA_IS_PORT_CONTROL (port_type) + && LADSPA_IS_PORT_INPUT (port_type)) + { + const char* port_name = NULL; + unsigned cmp_length = 0; + port_name = x->descriptor->LADSPA_Plugin->PortNames[port_index]; + cmp_length = MIN (strlen(name), strlen(port_name)); + if (cmp_length != 0 + && strncasecmp (name, port_name, cmp_length) == 0) + { + /* found the first port to match */ + found_port = 1; + break; + } + ctrl_input_index++; + } + } + + if (!found_port) { + pd_error(x, "plugin doesn't have a control input port named \"%s\"", + name); + return; + } + + ph_set_control_input_by_index (x, ctrl_input_index, value, i); + +} + +static void ph_ladspa_describe(const char * pcFullFilename, + void * pvPluginHandle, + DSSI_Descriptor_Function fDescriptorFunction, + void* user_data, + int is_dssi) +{ + + ph *x = (((void**)user_data)[0]); + t_atom at[1]; + DSSI_Descriptor *psDescriptor; + long lIndex; + + at[0].a_type = A_SYMBOL; + at[0].a_w.w_symbol = gensym ((char*)pcFullFilename); + outlet_anything (x->message_out, gensym ("library"), 1, at); + + if(is_dssi){ + ph_debug_post("DSSI plugin found by listinfo"); + + for (lIndex = 0; + (psDescriptor = (DSSI_Descriptor *) + fDescriptorFunction(lIndex)) != NULL; lIndex++) + ph_ladspa_description(x, &at[0], psDescriptor); + } + + else if(!is_dssi) + lIndex = 0; + do{ + psDescriptor = ladspa_to_dssi((LADSPA_Descriptor *)fDescriptorFunction(lIndex++)); + if(psDescriptor->LADSPA_Plugin != NULL){ + ph_ladspa_description(x, &at[0], psDescriptor); + free((DSSI_Descriptor *)psDescriptor); + } + else + break; + } while(1); +} + +static void ph_show(ph *x, unsigned int i, bool toggle) +{ + /* TODO:OSC */ +/* + if(instance->ui_target){ + if (instance->ui_hidden && toggle) { + lo_send(instance->ui_target, + instance->ui_osc_show_path, ""); + instance->ui_hidden = 0; + } + else if (!instance->ui_hidden && !toggle) { + instance->ui_osc_hide_path, ""); + instance->ui_hidden = 1; + } + } + else if(toggle){ + instance->ui_show = 1; + ph_load_gui(x, instance); + + } + */ +} + +static t_int ph_configure_buffer(ph *x, char *key, + char *value, unsigned int i) +{ + + ph_configure_pair *current; + ph_configure_pair *p; + ph_instance *instance; + + instance = &x->instances[i]; + current = x->configure_buffer_head; + + while(current){ + if(!strcmp(current->key, key) && current->instance == i) { + break; + } + current = current->next; + } + if(current) { + free(current->value); + } else { + current = malloc(sizeof(ph_configure_pair)); + current->next = x->configure_buffer_head; + current->key = strdup(key); + current->instance = i; + x->configure_buffer_head = current; + } + current->value = strdup(value); + p = x->configure_buffer_head; + + /*TODO: eventually give ability to query this buffer (to outlet?) */ + while(p){ + ph_debug_post("key: %s", p->key); + ph_debug_post("val: %s", p->value); + ph_debug_post("instance: %d", p->instance); + p = p->next; + } + + return 0; +} + +static t_int *ph_perform(t_int *w) +{ + unsigned int instance; + unsigned int i; + unsigned int N; + int timediff; + int framediff; + t_float **inputs; + t_float **outputs; + ph *x; + + x = (ph *)(w[1]); + N = (unsigned int)(w[2]); + inputs = (t_float **)(&w[3]); + outputs = (t_float **)(&w[3] + x->plugin_ins); + + if(x->dsp){ + x->dsp_loop = true; + + for(i = 0; i < x->plugin_ins; i++) + memcpy(x->plugin_input_buffers[i], inputs[i], N * + sizeof(LADSPA_Data)); + + for (i = 0; i < x->n_instances; i++) + x->instance_event_counts[i] = 0; + + for (;x->buf_read_index != x->buf_write_index; x->buf_read_index = + (x->buf_read_index + 1) % EVENT_BUFSIZE) { + + instance = x->midi_event_buf[x->buf_read_index].data.note.channel; + + if(instance > x->n_instances){ + pd_error(x, + "%s: %s: discarding spurious MIDI data, for instance %d", + CLASS_NAME_STR, + x->descriptor->LADSPA_Plugin->Label, + instance); + ph_debug_post("n_instances = %d", x->n_instances); + + continue; + } + + if (x->instance_event_counts[instance] == EVENT_BUFSIZE){ + pd_error(x, "MIDI overflow on channel %d", instance); + continue; + } + + timediff = (int)(clock_gettimesince(x->time_ref) * 1000) - + x->midi_event_buf[x->buf_read_index].time.time.tv_nsec; + framediff = (int)((t_float)timediff * .000001 / x->sr_inv); + + if (framediff >= (int)N || framediff < 0) + x->midi_event_buf[x->buf_read_index].time.tick = 0; + else + x->midi_event_buf[x->buf_read_index].time.tick = + N - framediff - 1; + + x->instance_event_buffers[instance] + [x->instance_event_counts[instance]] = + x->midi_event_buf[x->buf_read_index]; + ph_debug_post("%s, note received on channel %d", + x->descriptor->LADSPA_Plugin->Label, + x->instance_event_buffers[instance] + [x->instance_event_counts[instance]].data.note.channel); + + x->instance_event_counts[instance]++; + + ph_debug_post("Instance event count for instance %d of %d: %d\n", + instance + 1, x->n_instances, x->instance_event_counts[instance]); + + + } + + i = 0; + while(i < x->n_instances){ + if(x->instance_handles[i] && + x->descriptor->run_multiple_synths){ + x->descriptor->run_multiple_synths + (x->n_instances, x->instance_handles, + (unsigned long)N, x->instance_event_buffers, + &x->instance_event_counts[0]); + break; + } + else if (x->instance_handles[i] && + x->descriptor->run_synth){ + x->descriptor->run_synth(x->instance_handles[i], + (unsigned long)N, x->instance_event_buffers[i], + x->instance_event_counts[i]); + i++; + } + else if (x->instance_handles[i] && + x->descriptor->LADSPA_Plugin->run){ + x->descriptor->LADSPA_Plugin->run + (x->instance_handles[i], N); + i++; + } + } + + + for(i = 0; i < x->plugin_outs; i++) + memcpy(outputs[i], (t_float *)x->plugin_output_buffers[i], N * + sizeof(LADSPA_Data)); + + x->dsp_loop = false; + } + return w + (x->plugin_ins + x->plugin_outs + 3); +} + + +/* ======================================== */ + +void handle_pd_bang(ph *x) +{ + t_atom at[3]; + + at[0].a_type = A_FLOAT; + at[1].a_type = A_SYMBOL; + at[2].a_type = A_SYMBOL; + + if(x->plugin_label != NULL){ + at[0].a_w.w_float = x->n_instances; + at[1].a_w.w_symbol = gensym ((char *)x->plugin_label); + } + else{ + at[0].a_w.w_float = 0; + at[1].a_w.w_symbol = gensym ("plugin"); + } + at[2].a_w.w_symbol = gensym ("instances"); + outlet_anything (x->message_out, gensym ("running"), 3, at); +} + +void handle_pd_list(ph *x, t_symbol *s, int argc, t_atom *argv) +{ + char msg_type[TYPE_STRING_SIZE]; + int ev_type = 0; + atom_string(argv, msg_type, TYPE_STRING_SIZE); + int chan = (int)atom_getfloatarg(1, argc, argv) - 1; + int param = (int)atom_getfloatarg(2, argc, argv); + int val = (int)atom_getfloatarg(3, argc, argv); + int n_instances = x->n_instances; + + switch (msg_type[0]){ + case ASCII_n: ev_type = SND_SEQ_EVENT_NOTEON; + break; + case ASCII_c: ev_type = SND_SEQ_EVENT_CONTROLLER; + break; + case ASCII_p: ev_type = SND_SEQ_EVENT_PGMCHANGE; + break; + case ASCII_b: ev_type = SND_SEQ_EVENT_PITCHBEND; + break; + case ASCII_t: ev_type = SND_SEQ_EVENT_CHANPRESS; + break; + case ASCII_a: ev_type = SND_SEQ_EVENT_KEYPRESS; + break; + } + ph_debug_post("initial midi NOTE:, arg1 = %d, arg2 = %d, arg3 = %d, arg4 = %d",ev_type,chan,param,val); + + if(ev_type != 0) { + if(chan >= 0) { + ph_midibuf_add(x, ev_type, chan, param, val); + } else { + while(n_instances--) { + ph_midibuf_add(x, ev_type, n_instances, param, val); + } + } + } +} + +void handle_pd_dsp(ph *x, t_signal **sp) +{ + if(!x->n_instances){ + return; + } + + + t_int *dsp_vector, i, M; + + M = x->plugin_ins + x->plugin_outs + 2; + + dsp_vector = (t_int *) getbytes(M * sizeof(t_int)); + + dsp_vector[0] = (t_int)x; + dsp_vector[1] = (t_int)sp[0]->s_n; + + for(i = 2; i < M; i++) + dsp_vector[i] = (t_int)sp[i - 1]->s_vec; + + dsp_addv(ph_perform, M, dsp_vector); + +} + +void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->is_dssi) { + pd_error(x, "plugin is not a DSSI plugin, operation not supported"); + } + + char msg_type[TYPE_STRING_SIZE]; + char *debug; + char *filename; + char *filepath; + char *key; + char *value; + char *temp; + char mydir[MAXPDSTRING]; + int instance = -1; + int pathlen; + int toggle; + int fd; + int n_instances = x->n_instances; + int count; + int chan; + int maxpatches; + unsigned int i; + t_float val; + long filelength = 0; + unsigned char *raw_patch_data = NULL; + FILE *fp = NULL; + size_t filename_length, key_size, value_size; + dx7_patch_t patchbuf[DX7_BANK_SIZE]; + dx7_patch_t *firstpatch; + atom_string(argv, msg_type, TYPE_STRING_SIZE); + debug = NULL; + key = NULL; + value = NULL; + maxpatches = 128; + firstpatch = &patchbuf[0]; + val = 0; + + /*TODO: Temporary - at the moment we always load the first 32 patches to 0 */ + if(strcmp(msg_type, "configure")){ + instance = (int)atom_getfloatarg(2, argc, argv) - 1; + + if(!strcmp(msg_type, "load") && x->descriptor->configure){ + filename = argv[1].a_w.w_symbol->s_name; + pd_error(x, "loading patch: %s for instance %d", + filename, instance); + + if(!strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter") || + !strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter6")) { + + key = malloc(10 * sizeof(char)); /* holds "patchesN" */ + strcpy(key, "patches0"); + + /* TODO: duplicates code from load_plugin() */ + fd = canvas_open(x->x_canvas, filename, "", + mydir, &filename, MAXPDSTRING, 0); + + if(fd >= 0){ + filepath = mydir; + pathlen = strlen(mydir); + temp = &mydir[pathlen]; + sprintf(temp, "/%s", filename); + fp = fopen(filepath, "rb"); + } + else{ + pd_error(x, "unable to get file descriptor"); + } + + /*From dx7_voice_data by Sean Bolton */ + if(fp == NULL){ + pd_error(x, "unable to open patch file: %s", filename); + return; + } + if (fseek(fp, 0, SEEK_END) || + (filelength = ftell(fp)) == -1 || + fseek(fp, 0, SEEK_SET)) { + pd_error(x, "couldn't get length of patch file: %s", + filename); + fclose(fp); + return; + } + if (filelength == 0) { + pd_error(x, "patch file has zero length"); + fclose(fp); + return; + } else if (filelength > DX7_MAX_PATCH_SIZE) { + pd_error(x, "patch file is too large"); + fclose(fp); + return; + } + if (!(raw_patch_data = (unsigned char *)malloc(filelength))) { + pd_error(x, "couldn't allocate memory for raw patch file"); + fclose(fp); + return; + } + if (fread(raw_patch_data, 1, filelength, fp) + != (size_t)filelength) { + pd_error(x, "short read on patch file: %s", filename); + free(raw_patch_data); + fclose(fp); + return; + } + fclose(fp); + ph_debug_post("Patch file length is %ul", filelength); + + /* figure out what kind of file it is */ + filename_length = strlen(filename); + if (filename_length > 4 && + !strcmp(filename + filename_length - 4, ".dx7") && + filelength % DX7_VOICE_SIZE_PACKED == 0) { + /* It's a raw DX7 patch bank */ + ph_debug_post("Raw DX7 format patch bank passed"); + + count = filelength / DX7_VOICE_SIZE_PACKED; + count = count > maxpatches ? maxpatches : count; + + memcpy(firstpatch, raw_patch_data, count * + DX7_VOICE_SIZE_PACKED); + + } else if (filelength > 6 && + raw_patch_data[0] == 0xf0 && + raw_patch_data[1] == 0x43 && + /*This was used to fix some problem with Galaxy exports - possibly dump in worng format. It is not needed, but it did work, so in future, we may be able to support more formats not just DX7 */ + /* ((raw_patch_data[2] & 0xf0) == 0x00 || + raw_patch_data[2] == 0x7e) &&*/ + (raw_patch_data[2] & 0xf0) == 0x00 && + raw_patch_data[3] == 0x09 && + (raw_patch_data[4] == 0x10 || + raw_patch_data[4] == 0x20) && + /* 0x10 is actual, 0x20 matches typo in manual */ + raw_patch_data[5] == 0x00) { + /* It's a DX7 sys-ex 32 voice dump */ + + ph_debug_post("SYSEX header check passed"); + + + if (filelength != DX7_DUMP_SIZE_BULK || + raw_patch_data[DX7_DUMP_SIZE_BULK - 1] != 0xf7) { + pd_error(x, "badly formatted DX7 32 voice dump!"); + count = 0; + +#ifdef CHECKSUM_PATCH_FILES_ON_LOAD + } else if (dx7_bulk_dump_checksum(&raw_patch_data[6], + DX7_VOICE_SIZE_PACKED * 32) != + raw_patch_data[DX7_DUMP_SIZE_BULK - 2]) { + + pd_error(x, "DX7 32 voice dump with bad checksum!"); + count = 0; +#endif + + + } else { + + count = 32; + if (count > maxpatches) + count = maxpatches; + memcpy(firstpatch, raw_patch_data + 6, count * DX7_VOICE_SIZE_PACKED); + + } + } else { + + /* unsuccessful load */ + pd_error(x, "unknown patch bank file format!"); + count = 0; + + } + + free(raw_patch_data); + + if(count == 32) + value = encode_7in6((uint8_t *)&patchbuf[0].data[0], + count * DX7_VOICE_SIZE_PACKED); + + } + else if(!strcmp(x->descriptor->LADSPA_Plugin->Label, + "FluidSynth-DSSI")){ + key = malloc(6 * sizeof(char)); + strcpy(key, "load"); + value = filename; + } + else{ + pd_error(x, "%s patches are not supported", + x->descriptor->LADSPA_Plugin->Label); + } + } + + if(!strcmp(msg_type, "dir") && x->descriptor->configure){ + pathlen = strlen(argv[1].a_w.w_symbol->s_name) + 2; + x->project_dir = malloc((pathlen) * sizeof(char)); + atom_string(&argv[1], x->project_dir, pathlen); + pd_error(x, "project directory for instance %d has been set to: %s", instance, x->project_dir); + key = DSSI_PROJECT_DIRECTORY_KEY; + value = x->project_dir; + } else if (!strcmp(msg_type, "dir")) { + pd_error(x, "%s: %s %s: operation not supported", + CLASS_NAME_STR, + msg_type, + argv[1].a_w.w_symbol->s_name); + } + + if(!strcmp(msg_type, "show") || !strcmp(msg_type, "hide")){ + instance = (int)atom_getfloatarg(1, argc, argv) - 1; + if(!strcmp(msg_type, "show")) + toggle = 1; + else + toggle = 0; + + if(instance == -1){ + while(n_instances--) + ph_show(x, n_instances, toggle); + } + else + ph_show(x, instance, toggle); + } + + if(!strcmp(msg_type, "remap")) { + /* remap channel to instance */ + for(i = 0; i < x->n_instances && i < 128; i++){ + chan = (int)atom_getfloatarg(1 + i, argc, argv); + pd_error(x, "remapped MIDI channel %d to %d", 1+i, chan); + x->channel_map[i+1] = chan; + } + } + + } + + /*Use this to send arbitrary configure message to plugin */ + else if(!strcmp(msg_type, "configure")){ + key = + (char *)malloc(key_size = (strlen(argv[1].a_w.w_symbol->s_name) + 2) * sizeof(char)); + atom_string(&argv[1], key, key_size); + if(argc >= 3){ + if (argv[2].a_type == A_FLOAT){ + val = atom_getfloatarg(2, argc, argv); + value = (char *)malloc(TYPE_STRING_SIZE * + sizeof(char)); + sprintf(value, "%.2f", val); + } + else if(argv[2].a_type == A_SYMBOL){ + value = + (char *)malloc(value_size = + (strlen(argv[2].a_w.w_symbol->s_name) + 2) * + sizeof(char)); + atom_string(&argv[2], value, value_size); + } + + } + + if(argc == 4 && argv[3].a_type == A_FLOAT) + instance = atom_getfloatarg(3, argc, argv) - 1; + else if (n_instances) + instance = -1; + } + + if(key != NULL && value != NULL){ + + if(instance == -1){ + while(n_instances--){ + debug = ph_send_configure(x, key, value, n_instances); + ph_configure_buffer(x, key, value, n_instances); + } + } + /*TODO: Put some error checking in here to make sure instance is valid*/ + /* FIX: this is all a big hack (putting UI stuff in the host). Either + * hexter needs to expose these settings somehow (e.g. as configure + * key-value pairs), or we need a [hexter_ui] external/patch that + * mirrors the functionality of hexter_gtk */ + else{ + if(!strcmp(key, "pitch_bend_range")){ + x->instances[instance].perf_buffer[3] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "portamento_time")) { + x->instances[instance].perf_buffer[5] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "mod_wheel_sensitivity")) { + x->instances[instance].perf_buffer[9] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "mod_wheel_assign")) { + x->instances[instance].perf_buffer[10] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "foot_sensitivity")) { + x->instances[instance].perf_buffer[11] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "foot_assign")) { + x->instances[instance].perf_buffer[12] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "pressure_sensitivity")) { + x->instances[instance].perf_buffer[13] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "pressure_assign")) { + x->instances[instance].perf_buffer[14] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "breath_sensitivity")) { + x->instances[instance].perf_buffer[15] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else if (!strcmp(key, "breath_assign")) { + x->instances[instance].perf_buffer[16] = atoi(value); + char *p = encode_7in6(x->instances[instance].perf_buffer, + DX7_PERFORMANCE_SIZE); + debug = ph_send_configure(x, "performance", p, instance); + } else { + debug = ph_send_configure(x, key, value, instance); + } + ph_configure_buffer(x, key, value, instance); + } + } + ph_debug_post("The plugin returned %s", debug); + +} + +void handle_pd_control (ph *x, t_symbol* ctrl_name, t_float ctrl_value, + t_float instance) +/* Change the value of a named control port of the plug-in */ +{ + unsigned param = 0; + int i = instance - 1; + unsigned int n = x->n_instances; + + if (i > (int)x->n_instances || i < -1){ + pd_error(x, "control: invalid instance number %d", i); + return; + } + + ph_debug_post("Received LADSPA control data for instance %d", i); + + if (ctrl_name->s_name == NULL || strlen (ctrl_name->s_name) == 0) { + pd_error(x, "control messages must have a name and a value"); + return; + } + param = ph_get_param_num(x, ctrl_name->s_name); + if (param) { + if(i >= 0) { + ph_set_control_input_by_index (x, param - 1, ctrl_value, i); + } else if (i == -1) { + while(n--) { + ph_set_control_input_by_index (x, param - 1, ctrl_value, n); + } + } + } else if (i >= 0) { + ph_set_control_input_by_name (x, ctrl_name->s_name, + ctrl_value, i); + } else if (i == -1) { + while(n--) { + ph_set_control_input_by_name (x, ctrl_name->s_name, ctrl_value, n); + } + } +} + +void handle_pd_info (ph *x) +{ + unsigned int i, + ctrl_portno, + audio_portno; + t_atom argv[7]; + + ctrl_portno = audio_portno = 0; + + if (x->descriptor == NULL) + return; + + for(i = 0; i < x->descriptor->LADSPA_Plugin->PortCount; i++){ + memcpy(&argv[0], &x->port_info[i].type, + sizeof(t_atom)); + memcpy(&argv[1], &x->port_info[i].data_type, + sizeof(t_atom)); + memcpy(&argv[3], &x->port_info[i].name, + sizeof(t_atom)); + memcpy(&argv[4], &x->port_info[i].lower_bound, + sizeof(t_atom)); + memcpy(&argv[5], &x->port_info[i].upper_bound, + sizeof(t_atom)); + memcpy(&argv[6], &x->port_info[i].p_default, + sizeof(t_atom)); + argv[2].a_type = A_FLOAT; + if(!strcmp(argv[1].a_w.w_symbol->s_name, "control")) + argv[2].a_w.w_float = (t_float)++ctrl_portno; + + else if(!strcmp(argv[1].a_w.w_symbol->s_name, "audio")) + argv[2].a_w.w_float = (t_float)++audio_portno; + + outlet_anything (x->message_out, gensym ("port"), 7, argv); + } +} + +void handle_pd_reset(ph *x, t_float i) +{ + unsigned int n; + const LADSPA_Descriptor *ladspa; + + ladspa = x->descriptor->LADSPA_Plugin; + + for(n = 0; n < x->n_instances; n++) { + if ((int)i == -1 || n == (int)i) { + if (ladspa->deactivate && ladspa->activate){ + ladspa->deactivate(x->instance_handles[n]); + ladspa->activate(x->instance_handles[n]); + } + } + } +} + +void handle_pd_listplugins (ph *x) +{ + void* user_data[1]; + user_data[0] = x; + LADSPAPluginSearch(ph_ladspa_describe,(void*)user_data); +} + +void handle_pd_osc(ph *x, t_symbol *s, int argc, t_atom *argv) +{ + + unsigned int i; + const char *method; + char path[OSC_ADDR_MAX]; + ph_instance *instance; + + instance = NULL; + + atom_string(argv, path, TYPE_STRING_SIZE); + + if (strncmp(path, "/dssi/", 6)){ + handle_osc_debug(path); + } + + for (i = 0; i < x->n_instances; i++) { + instance = &x->instances[i]; + if (!strncmp(path + 6, instance->osc_url_path, + strlen(instance->osc_url_path))) { + break; + } + } + + if(instance == NULL) { + pd_error(x, "instance not found"); + return; + } + + if (!instance->osc_url_path){ + handle_osc_debug(path); + } + + method = path + 6 + strlen(instance->osc_url_path); + + if (*method != '/' || *(method + 1) == 0){ + handle_osc_debug(path); + } + + method++; + + switch(argc) { + case 2: + + if (!strcmp(method, "configure") && + argv[1].a_type == A_SYMBOL && + argv[2].a_type == A_SYMBOL) { + handle_osc_configure(x, &argv[1], i); + } else if (!strcmp(method, "control") && + argv[1].a_type == A_FLOAT && + argv[2].a_type == A_FLOAT) { + handle_osc_control(x, argv, i); + } else if (!strcmp(method, "program") && + argv[1].a_type == A_FLOAT && + argv[2].a_type == A_FLOAT) { + handle_osc_program(x, argv, i); + } + break; + + case 1: + if (!strcmp(method, "midi")) { + handle_osc_midi(x, argv, i); + } else if (!strcmp(method, "update") && + argv[1].a_type == A_SYMBOL) { + handle_osc_update(x, argv, i); + } + break; + case 0: + if (!strcmp(method, "exiting")) { + handle_osc_exiting(x, argv, i); + } + break; + default: + handle_osc_debug(path); + break; + } +} diff --git a/pluginhost~/handlers_pd.h b/pluginhost~/handlers_pd.h new file mode 100644 index 0000000..ec934da --- /dev/null +++ b/pluginhost~/handlers_pd.h @@ -0,0 +1,43 @@ +/* pluginhost~ - A plugin host for Pd + * + * Copyright (C) 2006 Jamie Bullock and others + * + * This file incorporates code from the following sources: + * + * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. + * + * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 + * + * liblo (CPL license): Copyright (C) 2004 Steve Harris + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "m_pd.h" +#include "ph_common.h" + +void handle_pd_bang(ph *x); +void handle_pd_info(ph *x); +void handle_pd_listplugins(ph *x); +void handle_pd_dsp(ph *x, t_signal **sp); +void handle_pd_reset(ph *x, t_float i); +void handle_pd_list(ph *x, t_symbol *s, int argc, t_atom *argv); +void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv); +void handle_pd_control (ph *x, t_symbol* ctrl_name, t_float ctrl_value, + t_float instance); +void handle_pd_plug(ph *x, t_symbol *s, int argc, t_atom *argv); +void handle_pd_osc(ph *x, t_symbol *s, int argc, t_atom *argv); diff --git a/pluginhost~/jload.c b/pluginhost~/jload.c new file mode 100644 index 0000000..1672b91 --- /dev/null +++ b/pluginhost~/jload.c @@ -0,0 +1,214 @@ +/* load.c + + Free software by Richard W.E. Furse. Do with as you will. No + warranty. */ + +/* patched by Jarno Seppänen, jams@cs.tut.fi, for plugin~ */ + +/* patched by Jamie Bullock, jamie@postlude.co.uk, for dssi~ */ + +/*****************************************************************************/ + +#include +#include +#include +#include + +/*****************************************************************************/ + +#include "ladspa.h" +#include "jutils.h" + +/*****************************************************************************/ + +/* This function provides a wrapping of dlopen(). When the filename is + not an absolute path (i.e. does not begin with / character), this + routine will search the LADSPA_PATH for the file. */ +static void * +dlopenLADSPA(const char * pcFilename, int iFlag) { + + char * pcBuffer; + const char * pcEnd; + const char * pcLADSPAPath; + const char * pcStart; + int iEndsInSO; + int iNeedSlash; + size_t iFilenameLength; + void * pvResult; + char *pluginPath; + + + iFilenameLength = strlen(pcFilename); + pvResult = NULL; + + /* First we just try calling dlopen(). This works if the user knows + about dlopen() and has placed the file on the LD_LIBRARY path or + has used an absolute directory. */ + pvResult = dlopen(pcFilename, iFlag); + if (pvResult != NULL) + return pvResult; + + /* If the filename is not absolute then we wish to check along the + LADSPA_PATH path to see if we can find the file there. */ + if (pcFilename[0] != '/') { + + pcLADSPAPath = NULL; + + if(getenv("LADSPA_PATH") && getenv("DSSI_PATH")){ + pluginPath = malloc(sizeof(char) * + (strlen(getenv("LADSPA_PATH")) + 1) + + sizeof(char) * strlen(getenv("DSSI_PATH"))); + sprintf(pluginPath, "%s:%s", + getenv("LADSPA_PATH"), getenv("DSSI_PATH")); + pcLADSPAPath = pluginPath; + free(pluginPath); + } + if (pcLADSPAPath == NULL) { + fprintf(stderr, "Warning: no LADSPA_PATH and DSSI_PATH, assuming /usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi\n"); + pcLADSPAPath = + "/usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi"; + } + + if (pcLADSPAPath) { + + pcStart = pcLADSPAPath; + while (*pcStart != '\0') { + pcEnd = pcStart; + while (*pcEnd != ':' && *pcEnd != '\0') + pcEnd++; + + pcBuffer = malloc(iFilenameLength + 2 + (pcEnd - pcStart)); + if (pcEnd > pcStart) + strncpy(pcBuffer, pcStart, pcEnd - pcStart); + iNeedSlash = 0; + if (pcEnd > pcStart) + if (*(pcEnd - 1) != '/') { + iNeedSlash = 1; + pcBuffer[pcEnd - pcStart] = '/'; + } + strcpy(pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename); + + pvResult = dlopen(pcBuffer, iFlag); + + free (pcBuffer); + if (pvResult != NULL){ + return pvResult; + } + + pcStart = pcEnd; + if (*pcStart == ':') + pcStart++; + } + } else { + fputs ("warning: You haven't specified the LADSPA_PATH environment variable and didn't specify an absolute path to the plug-in.\n" + "Please set the LADSPA_PATH variable to point to your LADSPA plug-in directories (eg. \"export LADSPA_PATH=/usr/local/lib/ladspa\").\n", stderr); + } + } + + /* As a last ditch effort, check if filename does not end with + ".so". In this case, add this suffix and recurse. */ + iEndsInSO = 0; + if (iFilenameLength > 3) + iEndsInSO = (strcmp(pcFilename + iFilenameLength - 3, ".so") == 0); + if (!iEndsInSO) { + pcBuffer = malloc(iFilenameLength + 4); + strcpy(pcBuffer, pcFilename); + strcat(pcBuffer, ".so"); + pvResult = dlopenLADSPA(pcBuffer, iFlag); + } + + if (pvResult != NULL) + return pvResult; + + /* If nothing has worked, then at least we can make sure we set the + correct error message - and this should correspond to a call to + dlopen() with the actual filename requested. The dlopen() manual + page does not specify whether the first or last error message + will be kept when multiple calls are made to dlopen(). We've + covered the former case - now we can handle the latter by calling + dlopen() again here. */ + return dlopen(pcFilename, iFlag); +} + +/*****************************************************************************/ + +void * +loadLADSPAPluginLibrary(const char * pcPluginFilename) { + + void * pvPluginHandle; + + pvPluginHandle = dlopenLADSPA(pcPluginFilename, RTLD_NOW); + if (!pvPluginHandle) { + fprintf(stderr, + "Failed to load plugin \"%s\": %s\n", + pcPluginFilename, + dlerror()); +#if 0 + exit(1); +#else + return NULL; +#endif + } + + return pvPluginHandle; +} + +/*****************************************************************************/ + +void +unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary) { + dlclose(pvLADSPAPluginLibrary); +} + +/*****************************************************************************/ + +const LADSPA_Descriptor * +findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary, + const char * pcPluginLibraryFilename, + const char * pcPluginLabel) { + + const LADSPA_Descriptor * psDescriptor; + LADSPA_Descriptor_Function pfDescriptorFunction; + unsigned long lPluginIndex; + + dlerror(); + pfDescriptorFunction + = (LADSPA_Descriptor_Function)dlsym(pvLADSPAPluginLibrary, + "ladspa_descriptor"); + if (!pfDescriptorFunction) { + const char * pcError = dlerror(); + if (pcError) + fprintf(stderr, + "Unable to find ladspa_descriptor() function in plugin " + "library file \"%s\": %s.\n" + "Are you sure this is a LADSPA plugin file?\n", + pcPluginLibraryFilename, + pcError); +#if 0 + exit(1); +#else + return NULL; +#endif + } + + for (lPluginIndex = 0;; lPluginIndex++) { + psDescriptor = pfDescriptorFunction(lPluginIndex); + if (psDescriptor == NULL) { + fprintf(stderr, + "Unable to find label \"%s\" in plugin library file \"%s\".\n", + pcPluginLabel, + pcPluginLibraryFilename); +#if 0 + exit(1); +#else + return NULL; +#endif + } + if (strcmp(psDescriptor->Label, pcPluginLabel) == 0) + return psDescriptor; + } +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/pluginhost~/jsearch.c b/pluginhost~/jsearch.c new file mode 100644 index 0000000..5d69b1b --- /dev/null +++ b/pluginhost~/jsearch.c @@ -0,0 +1,156 @@ +/* search.c + + Free software by Richard W.E. Furse. Do with as you will. No + warranty. */ + +/* patched by Jarno Seppänen, jams@cs.tut.fi, for plugin~ */ + +/* patched by Jamie Bullock, jamie@postlude.co.uk, for dssi~ */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +/*****************************************************************************/ + +#include "dssi.h" +#include "jutils.h" + +/*****************************************************************************/ + +/* Search just the one directory. */ + static void +LADSPADirectoryPluginSearch (const char * pcDirectory, + LADSPAPluginSearchCallbackFunction fCallbackFunction, + void* user_data) +{ + char * pcFilename; + DIR * psDirectory; + DSSI_Descriptor_Function fDescriptorFunction; + long lDirLength; + long iNeedSlash; + struct dirent * psDirectoryEntry; + void * pvPluginHandle; + bool is_DSSI = false; + + lDirLength = strlen(pcDirectory); + if (!lDirLength) + return; + if (pcDirectory[lDirLength - 1] == '/') + iNeedSlash = 0; + else + iNeedSlash = 1; + + psDirectory = opendir(pcDirectory); + if (!psDirectory) + return; + + while (1) { + + psDirectoryEntry = readdir(psDirectory); + if (!psDirectoryEntry) { + closedir(psDirectory); + return; + } + + pcFilename = malloc(lDirLength + + strlen(psDirectoryEntry->d_name) + + 1 + iNeedSlash); + strcpy(pcFilename, pcDirectory); + if (iNeedSlash) + strcat(pcFilename, "/"); + strcat(pcFilename, psDirectoryEntry->d_name); + + pvPluginHandle = dlopen(pcFilename, RTLD_LAZY); + if (pvPluginHandle) { + /* This is a file and the file is a shared library! */ + + dlerror(); + if((fDescriptorFunction = + (DSSI_Descriptor_Function)dlsym(pvPluginHandle, + "ladspa_descriptor"))) { + is_DSSI = false; + } else if ((fDescriptorFunction = + (DSSI_Descriptor_Function)dlsym(pvPluginHandle, + "dssi_descriptor"))) { + is_DSSI = true; + } + + if (dlerror() == NULL && fDescriptorFunction) { + /* We've successfully found a ladspa_descriptor function. Pass + it to the callback function. */ + fCallbackFunction(pcFilename, + pvPluginHandle, + fDescriptorFunction, + user_data, + is_DSSI); + dlclose (pvPluginHandle); + } + else { + /* It was a library, but not a LADSPA one. Unload it. */ + dlclose(pcFilename); + } + } + } +} + +/*****************************************************************************/ + + void +LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction, + void* user_data) +{ + + char * pcBuffer; + const char * pcEnd; + const char * pcLADSPAPath; + char *pluginPath; + const char * pcStart; + + + pcLADSPAPath = NULL; + + if(getenv("LADSPA_PATH") && getenv("DSSI_PATH")){ + pluginPath = malloc(sizeof(char) * + (strlen(getenv("LADSPA_PATH")) + 1) + + sizeof(char) * strlen(getenv("DSSI_PATH"))); + sprintf(pluginPath, "%s:%s", + getenv("LADSPA_PATH"), getenv("DSSI_PATH")); + pcLADSPAPath = pluginPath; + free(pluginPath); + } + if (pcLADSPAPath == NULL) { + fprintf(stderr, "Warning: no LADSPA_PATH and DSSI_PATH, assuming /usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi\n"); + pcLADSPAPath = + "/usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi"; + } + + pcStart = pcLADSPAPath; + while (*pcStart != '\0') { + pcEnd = pcStart; + while (*pcEnd != ':' && *pcEnd != '\0') + pcEnd++; + + pcBuffer = malloc(1 + pcEnd - pcStart); + if (pcEnd > pcStart) + strncpy(pcBuffer, pcStart, pcEnd - pcStart); + pcBuffer[pcEnd - pcStart] = '\0'; + + LADSPADirectoryPluginSearch(pcBuffer, fCallbackFunction, user_data); + + pcStart = pcEnd; + if (*pcStart == ':') + pcStart++; + } +} + + +/*****************************************************************************/ + +/* EOF */ diff --git a/pluginhost~/jutils.h b/pluginhost~/jutils.h new file mode 100644 index 0000000..fdf718f --- /dev/null +++ b/pluginhost~/jutils.h @@ -0,0 +1,69 @@ +/* utils.h + + Free software by Richard W.E. Furse. Do with as you will. No + warranty. */ + +/* patched by Jarno Seppänen, jams@cs.tut.fi, for plugin~ */ + +/* patched by Jamie Bullock, jamie@postlude.co.uk, for dssi~ */ + +#ifndef LADSPA_SDK_LOAD_PLUGIN_LIB +#define LADSPA_SDK_LOAD_PLUGIN_LIB + +/*****************************************************************************/ + +#include "dssi.h" + +/*****************************************************************************/ + +/* Functions in load.c: */ + +/* This function call takes a plugin library filename, searches for + the library along the LADSPA_PATH, loads it with dlopen() and + returns a plugin handle for use with findPluginDescriptor() or + unloadLADSPAPluginLibrary(). Errors are handled by writing a + message to stderr and calling exit(1). It is alright (although + inefficient) to call this more than once for the same file. */ +void * loadLADSPAPluginLibrary(const char * pcPluginFilename); + +/* This function unloads a LADSPA plugin library. */ +void unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary); + +/* This function locates a LADSPA plugin within a plugin library + loaded with loadLADSPAPluginLibrary(). Errors are handled by + writing a message to stderr and calling exit(1). Note that the + plugin library filename is only included to help provide + informative error messages. */ +const LADSPA_Descriptor * +findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary, + const char * pcPluginLibraryFilename, + const char * pcPluginLabel); + +/*****************************************************************************/ + +/* Functions in search.c: */ + +/* Callback function for use with LADSPAPluginSearch(). The callback + function passes the filename (full path), a plugin handle (dlopen() + style) and a LADSPA_DescriptorFunction (from which + LADSPA_Descriptors can be acquired). */ +typedef void LADSPAPluginSearchCallbackFunction +(const char * pcFullFilename, + void * pvPluginHandle, + DSSI_Descriptor_Function fDescriptorFunction, + void* user_data, + int is_DSSI); + +/* Search through the $(LADSPA_PATH) (or a default path) for any + LADSPA plugin libraries. Each plugin library is tested using + dlopen() and dlsym(,"ladspa_descriptor"). After loading each + library, the callback function is called to process it. This + function leaves items passed to the callback function open. */ +void LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction, + void* user_data); + +/*****************************************************************************/ + +#endif + +/* EOF */ diff --git a/pluginhost~/ph_common.c b/pluginhost~/ph_common.c new file mode 100644 index 0000000..2915b15 --- /dev/null +++ b/pluginhost~/ph_common.c @@ -0,0 +1,1117 @@ +/* pluginhost~ - A plugin host for Pd + * + * Copyright (C) 2006 Jamie Bullock and others + * + * This file incorporates code from the following sources: + * + * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. + * + * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 + * + * liblo (CPL license): Copyright (C) 2004 Steve Harris + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include /* for exit() */ +#include /* for fork() */ +#include /* for kill() */ +#include /* for readdir() */ +#include /* for dlsym() */ +#include + +#include "dssi.h" + +#include "jutils.h" +#include "ph_common.h" + +#define DEBUG_STRING_SIZE 8192 + +/*From dx7_voice_data.c */ +uint8_t dx7_init_performance[DX7_PERFORMANCE_SIZE] = { 0, 0, 0, 2, 0, 0, 0, 0, + 0, 15, 1, 0, 4, 15, 2, 15, + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static LADSPA_Data ph_get_port_default(ph *x, int port) +{ + LADSPA_Descriptor *plugin = (LADSPA_Descriptor *)x->descriptor->LADSPA_Plugin; + LADSPA_PortRangeHint hint = plugin->PortRangeHints[port]; + float lower = hint.LowerBound * + (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? x->sr : 1.0f); + float upper = hint.UpperBound * + (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? x->sr : 1.0f); + + if (!LADSPA_IS_HINT_HAS_DEFAULT(hint.HintDescriptor)) { + if (!LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) || + !LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) { + /* No hint, its not bounded, wild guess */ + return 0.0f; + } + + if (lower <= 0.0f && upper >= 0.0f) { + /* It spans 0.0, 0.0 is often a good guess */ + return 0.0f; + } + + /* No clues, return minimum */ + return lower; + } + + /* Try all the easy ones */ + + if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor)) { + return 0.0f; + } else if (LADSPA_IS_HINT_DEFAULT_1(hint.HintDescriptor)) { + return 1.0f; + } else if (LADSPA_IS_HINT_DEFAULT_100(hint.HintDescriptor)) { + return 100.0f; + } else if (LADSPA_IS_HINT_DEFAULT_440(hint.HintDescriptor)) { + return 440.0f; + } + + /* All the others require some bounds */ + + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) { + if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor)) { + return lower; + } + } + if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) { + if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor)) { + return upper; + } + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) { + if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) { + return lower * 0.75f + upper * 0.25f; + } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) { + return lower * 0.5f + upper * 0.5f; + } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) { + return lower * 0.25f + upper * 0.75f; + } + } + } + + /* fallback */ + return 0.0f; +} + + + +static void ph_set_port_info(ph *x) +{ + t_int i; + + for (i = 0; i < (t_int)x->descriptor->LADSPA_Plugin->PortCount; i++) { + + x->port_info[i].type.a_type = A_SYMBOL; + x->port_info[i].data_type.a_type = A_SYMBOL; + x->port_info[i].name.a_type = A_SYMBOL; + x->port_info[i].upper_bound.a_type = A_FLOAT; + x->port_info[i].lower_bound.a_type = A_FLOAT; + x->port_info[i].p_default.a_type = A_FLOAT; + + LADSPA_PortDescriptor pod = + x->descriptor->LADSPA_Plugin->PortDescriptors[i]; + ph_debug_post("Port %d: %s", i, x->descriptor->LADSPA_Plugin->PortNames[i]); + + if (LADSPA_IS_PORT_AUDIO(pod)) { + x->port_info[i].data_type.a_w.w_symbol = + gensym("audio"); + if (LADSPA_IS_PORT_INPUT(pod)){ + x->port_info[i].type.a_w.w_symbol = + gensym("in"); + ++x->plugin_ins; + } + else if (LADSPA_IS_PORT_OUTPUT(pod)){ + x->port_info[i].type.a_w.w_symbol = + gensym("out"); + ++x->plugin_outs; + } + } + else if (LADSPA_IS_PORT_CONTROL(pod)) { + x->port_info[i].data_type.a_w.w_symbol = + gensym("control"); + if (LADSPA_IS_PORT_INPUT(pod)){ + x->port_info[i].type.a_w.w_symbol = + gensym("in"); + ++x->plugin_control_ins; + } + else if (LADSPA_IS_PORT_OUTPUT(pod)){ + ++x->plugin_control_outs; + x->port_info[i].type.a_w.w_symbol = + gensym("out"); + } + } + if (LADSPA_IS_HINT_BOUNDED_BELOW( + x->descriptor->LADSPA_Plugin->PortRangeHints[i].HintDescriptor)) + x->port_info[i].lower_bound.a_w.w_float = + x->descriptor->LADSPA_Plugin-> + PortRangeHints[i].LowerBound; + else + x->port_info[i].lower_bound.a_w.w_float = 0; + + if (LADSPA_IS_HINT_BOUNDED_ABOVE( + x->descriptor->LADSPA_Plugin->PortRangeHints[i].HintDescriptor)) + x->port_info[i].upper_bound.a_w.w_float = + x->descriptor->LADSPA_Plugin-> + PortRangeHints[i].UpperBound; + else + x->port_info[i].lower_bound.a_w.w_float = 1; + + x->port_info[i].p_default.a_w.w_float = (float) + ph_get_port_default(x, i); + + x->port_info[i].name.a_w.w_symbol = + gensym ((char *) + x->descriptor->LADSPA_Plugin->PortNames[i]); + } + ph_debug_post("%d inputs, %d outputs, %d control inputs, %d control outs", x->plugin_ins, x->plugin_outs, x->plugin_control_ins, x->plugin_control_outs); + +} + +static void ph_assign_ports(ph *x) +{ + unsigned int i; + + ph_debug_post("%d instances", x->n_instances); + + + x->plugin_ins *= x->n_instances; + x->plugin_outs *= x->n_instances; + x->plugin_control_ins *= x->n_instances; + x->plugin_control_outs *= x->n_instances; + + ph_debug_post("%d plugin outs", x->plugin_outs); + + + x->plugin_input_buffers = + (float **)malloc(x->plugin_ins * sizeof(float *)); + x->plugin_output_buffers = + (float **)malloc(x->plugin_outs * sizeof(float *)); + x->plugin_control_input = + (float *)calloc(x->plugin_control_ins, sizeof(float)); + x->plugin_control_output = + (float *)calloc(x->plugin_control_outs, sizeof(float)); + for(i = 0; i < x->plugin_ins; i++) + x->plugin_input_buffers[i] = + (float *)calloc(x->blksize, sizeof(float)); + for(i = 0; i < x->plugin_outs; i++) + x->plugin_output_buffers[i] = + (float *)calloc(x->blksize, sizeof(float)); + x->instance_event_buffers = + (snd_seq_event_t **)malloc(x->n_instances * sizeof(snd_seq_event_t *)); + + x->instance_handles = (LADSPA_Handle *)malloc(x->n_instances * + sizeof(LADSPA_Handle)); + x->instance_event_counts = (unsigned long *)malloc(x->n_instances * + sizeof(unsigned long)); + + for(i = 0; i < x->n_instances; i++){ + x->instance_event_buffers[i] = (snd_seq_event_t *)malloc(EVENT_BUFSIZE * + sizeof(snd_seq_event_t)); + + x->instances[i].plugin_port_ctlin_numbers = + (int *)malloc(x->descriptor->LADSPA_Plugin->PortCount * + sizeof(int)); + } + + x->plugin_ctlin_port_numbers = + (unsigned long *)malloc(sizeof(unsigned long) * x->plugin_control_ins); + + ph_debug_post("Buffers assigned!"); + + +} + +static void ph_init_instance(ph *x, unsigned int i) +{ + + x->instances[i].plugin_pgm_count = 0; + x->instances[i].ui_needs_pgm_update = 0; + x->instances[i].ui_osc_control_path = NULL; + x->instances[i].ui_osc_configure_path = NULL; + x->instances[i].ui_osc_program_path = NULL; + x->instances[i].ui_osc_show_path = NULL; + x->instances[i].ui_osc_hide_path = NULL; + x->instances[i].ui_osc_quit_path = NULL; + x->instances[i].osc_url_path = NULL; + x->instances[i].current_bank = 0; + x->instances[i].current_pgm = 0; + x->instances[i].pending_pgm_change = -1; + x->instances[i].pending_bank_lsb = -1; + x->instances[i].pending_bank_msb = -1; + x->instances[i].ui_hidden = 1; + x->instances[i].ui_show = 0; + memcpy(x->instances[i].perf_buffer, &dx7_init_performance, DX7_PERFORMANCE_SIZE); + + //x->instances[i].plugin_port_ctlin_numbers = NULL; + x->instances[i].plugin_pgms = NULL; + + ph_debug_post("Instance %d initialized!", i); + +} + +static void ph_connect_ports(ph *x, unsigned int i) +{ + + unsigned int n; + + for(n = 0; n < x->descriptor->LADSPA_Plugin->PortCount; n++){ + ph_debug_post("PortCount: %d of %d", n, + x->descriptor->LADSPA_Plugin->PortCount); + + LADSPA_PortDescriptor pod = + x->descriptor->LADSPA_Plugin->PortDescriptors[n]; + + x->instances[i].plugin_port_ctlin_numbers[n] = -1; + + if (LADSPA_IS_PORT_AUDIO(pod)) { + if (LADSPA_IS_PORT_INPUT(pod)) { + x->descriptor->LADSPA_Plugin->connect_port + (x->instance_handles[i], n, + x->plugin_input_buffers[x->ports_in++]); + } + else if (LADSPA_IS_PORT_OUTPUT(pod)) { + x->descriptor->LADSPA_Plugin->connect_port + (x->instance_handles[i], n, + x->plugin_output_buffers[x->ports_out++]); + ph_debug_post("Audio Input port %d connected", x->ports_in); + ph_debug_post("Audio Output port %d connected", x->ports_out); + + } + } + else if (LADSPA_IS_PORT_CONTROL(pod)) { + if (LADSPA_IS_PORT_INPUT(pod)) { + x->plugin_ctlin_port_numbers[x->ports_control_in] = (unsigned long) i; + x->instances[i].plugin_port_ctlin_numbers[n] = + x->ports_control_in; + x->plugin_control_input[x->ports_control_in] = + (t_float) ph_get_port_default(x, n); + ph_debug_post("default for port %d, control_in, %d is %.2f", n, + x->ports_control_in, + x->plugin_control_input[x->ports_control_in]); + + + x->descriptor->LADSPA_Plugin->connect_port + (x->instance_handles[i], n, + &x->plugin_control_input[x->ports_control_in++]); + + } else if (LADSPA_IS_PORT_OUTPUT(pod)) { + x->descriptor->LADSPA_Plugin->connect_port + (x->instance_handles[i], n, + &x->plugin_control_output[x->ports_control_out++]); + } + ph_debug_post("control port %d connected", x->ports_control_in); + ph_debug_post("control port %d connected", x->ports_control_out); + + } + } +} + +static void ph_activate_plugin(ph *x, unsigned int i) +{ + + if(x->descriptor->LADSPA_Plugin->activate){ + ph_debug_post("trying to activate instance: %d", i); + + x->descriptor->LADSPA_Plugin->activate(x->instance_handles[i]); + } + ph_debug_post("plugin activated!"); + +} + +static void ph_deactivate_plugin(ph *x, unsigned int instance) +{ + + if(x->descriptor->LADSPA_Plugin->deactivate) { + x->descriptor->LADSPA_Plugin->deactivate(x->instance_handles[instance]); + } + ph_debug_post("plugin deactivated!"); + +} + +static void ph_cleanup_plugin(ph *x, unsigned int instance) +{ + if (x->descriptor->LADSPA_Plugin && + x->descriptor->LADSPA_Plugin->cleanup) { + x->descriptor->LADSPA_Plugin->cleanup + (x->instance_handles[instance]); + } +} + +static void ph_get_current_pgm(ph *x, unsigned int i) +{ + t_int argc = 3; + t_atom argv[argc]; + ph_instance *instance; + unsigned int pgm; + + instance = &x->instances[i]; + pgm = instance->current_pgm; + + SETFLOAT(argv, i); + SETFLOAT(argv+1, instance->plugin_pgms[pgm].Program); + SETSYMBOL(argv+2, gensym(instance->plugin_pgms[pgm].Name)); + outlet_anything(x->message_out, gensym ("program"), argc, argv); + +} + +static void ph_init_programs(ph *x, unsigned int i) +{ + ph_instance *instance = &x->instances[i]; + ph_debug_post("Setting up program data"); + ph_query_programs(x, i); + + if (x->descriptor->select_program && instance->plugin_pgm_count > 0) { + + /* select program at index 0 */ + unsigned long bank = instance->plugin_pgms[0].Bank; + instance->pending_bank_msb = bank / 128; + instance->pending_bank_lsb = bank % 128; + instance->pending_pgm_change = instance->plugin_pgms[0].Program; + instance->ui_needs_pgm_update = 1; + } +} + +/* TODO:OSC */ +#if 0 +static void ph_load_gui(ph *x, int instance) +{ + t_int err = 0; + char *gui_path; + struct dirent *dir_entry = NULL; + char *gui_base; + size_t baselen; + DIR *dp; + char *gui_str; + + gui_base = (char *)malloc((baselen = sizeof(char) * (strlen(x->plugin_full_path) - strlen(".so"))) + 1); + + strncpy(gui_base, x->plugin_full_path, baselen); + gui_base[baselen] = '\0'; + + /* don't use strndup - GNU only */ + /* gui_base = strndup(x->plugin_full_path, baselen);*/ + ph_debug_post("gui_base: %s", gui_base); + + + gui_str = (char *)malloc(sizeof(char) * (strlen("channel 00") + 1)); + sprintf (gui_str,"channel %02d", instance); + + ph_debug_post("GUI name string, %s", gui_str); + + + if(!(dp = opendir(gui_base))){ + post("pluginhost~: unable to find GUI in %s, continuing without...", gui_base); + return; + } + else { + while((dir_entry = readdir(dp))){ + if (dir_entry->d_name[0] == '.') continue; + if (strchr(dir_entry->d_name, '_')){ + if (strstr(dir_entry->d_name, "gtk") || + strstr(dir_entry->d_name, "qt") || + strstr(dir_entry->d_name, "text")) + break; + } + } + ph_debug_post("GUI filename: %s", dir_entry->d_name); + + } + + gui_path = (char *)malloc(sizeof(char) * (strlen(gui_base) + strlen("/") + + strlen(dir_entry->d_name) + 1)); + + sprintf(gui_path, "%s/%s", gui_base, dir_entry->d_name); + + free(gui_base); + ph_debug_post("gui_path: %s", gui_path); + + + /* osc_url_base was of the form: + * osc.udp://127.0.0.1:9997/dssi + */ + osc_url = (char *)malloc + (sizeof(char) * (strlen(x->osc_url_base) + + strlen(instance->osc_url_path) + 2)); + + sprintf(osc_url, "%s/%s", x->osc_url_base, + instance->osc_url_path); + post("pluginhost~: instance %d URL: %s",instance, osc_url); + ph_debug_post("Trying to open GUI!"); + + + instance->gui_pid = fork(); + if (instance->gui_pid == 0){ + err = execlp(gui_path, gui_path, osc_url, dir_entry->d_name, + x->descriptor->LADSPA_Plugin->Label, gui_str, NULL); + perror("exec failed"); + exit(1); /* terminates the process */ + } + + ph_debug_post("errorcode = %d", err); + + + free(gui_path); + free(osc_url); + free(gui_str); + if(dp){ + + ph_debug_post("directory handle closed = %d", closedir(dp)); + + } +} +#endif + +static t_int ph_configure_buffer_free(ph *x) +{ + ph_configure_pair *curr, *prev; + prev = curr = NULL; + + for(curr = x->configure_buffer_head; curr != NULL; curr = curr->next){ + if(prev != NULL) + free(prev); + free(curr->key); + free(curr->value); + prev = curr; + } + free(curr); + + return 0; +} + +static void ph_search_plugin_callback ( + const char* full_filename, + void* plugin_handle, + DSSI_Descriptor_Function descriptor_function, + void* user_data, + int is_dssi) +{ + DSSI_Descriptor* descriptor = NULL; + unsigned plug_index = 0; + + char** out_lib_name = (char**)(((void**)user_data)[0]); + char* name = (char*)(((void**)user_data)[1]); + + /* Stop searching when a first matching plugin is found */ + if (*out_lib_name == NULL) + { + ph_debug_post("pluginhost~: searching plugin \"%s\"...", full_filename); + + for(plug_index = 0;(is_dssi ? + (descriptor = + (DSSI_Descriptor *)descriptor_function(plug_index)) : + ((DSSI_Descriptor *)(descriptor = + ladspa_to_dssi((LADSPA_Descriptor *) + descriptor_function(plug_index)))->LADSPA_Plugin)) + != NULL; plug_index++){ + ph_debug_post("pluginhost~: label \"%s\"", descriptor->LADSPA_Plugin->Label); + + if (strcasecmp (name, descriptor->LADSPA_Plugin->Label) + == 0) + { + *out_lib_name = strdup (full_filename); + ph_debug_post("pluginhost~: found plugin \"%s\" in library \"%s\"", + name, full_filename); + + /* if(!is_dssi){ + free((DSSI_Descriptor *)descriptor); + descriptor = NULL; + }*/ + break; + } + /* if (descriptor != NULL){ + free((DSSI_Descriptor *)descriptor); + descriptor = NULL; + }*/ + } + } +} + +static const char* plugin_tilde_search_plugin_by_label (ph *x, + const char *name) +{ + char* lib_name = NULL; + void* user_data[2]; + + user_data[0] = (void*)(&lib_name); + user_data[1] = (void*)name; + ph_debug_post("search plugin by label: '%s'\n", name); + + + lib_name = NULL; + LADSPAPluginSearch (ph_search_plugin_callback, + (void*)user_data); + + /* The callback (allocates and) writes lib_name, if it finds the plugin */ + return lib_name; + +} + +static void osc_setup(ph *x, unsigned int i) +{ + ph_instance *instance = &x->instances[i]; + + if(i == 0){ + x->osc_port = OSC_PORT; + } + instance->osc_url_path = malloc(sizeof(char) * + (strlen(x->plugin_basename) + + strlen(x->descriptor->LADSPA_Plugin->Label) + + //strlen("chan00") + 3)); + 6 + 3)); + sprintf(instance->osc_url_path, "%s/%s/chan%02d", x->plugin_basename, + x->descriptor->LADSPA_Plugin->Label, i); + ph_debug_post("OSC Path is: %s", instance->osc_url_path); + +} + +/* ==================================== */ + +void ph_debug_post(const char *fmt, ...) +{ +#if DEBUG == 1 + unsigned int currpos; + char newfmt[DEBUG_STRING_SIZE]; + char result[DEBUG_STRING_SIZE]; + size_t fmt_length; + va_list args; + + fmt_length = strlen(fmt); + + sprintf(newfmt, "%s: ", PH_NAME); + strncat(newfmt, fmt, fmt_length); + currpos = strlen(PH_NAME) + 2 + fmt_length; + newfmt[currpos] = '\0'; + + va_start(args, fmt); + vsprintf(result, newfmt, args); + va_end(args); + + post(result); +#endif +} + +void ph_quit_plugin(ph *x) +{ + + unsigned int i; + t_atom argv[2]; + t_int argc; + ph_instance *instance; + + argc = 2; + + for(i = 0; i < x->n_instances; i++) { + instance = &x->instances[i]; + if(x->is_dssi){ + argc = 2; + if(instance->ui_osc_quit_path != NULL) { + SETSYMBOL(argv, gensym(instance->ui_osc_quit_path)); + SETSYMBOL(argv+1, gensym("")); + ph_instance_send_osc(x->message_out, instance, argc, argv); + } + } + ph_deactivate_plugin(x, i); + ph_cleanup_plugin(x, i); + } +} + +void ph_query_programs(ph *x, unsigned int i) +{ + unsigned int n; + ph_instance *instance = &x->instances[i]; + ph_debug_post("querying programs"); + + /* free old lot */ + if (instance->plugin_pgms != NULL) { + for (n = 0; n < instance->plugin_pgm_count; n++) { + free((void *)instance->plugin_pgms[n].Name); + } + free(instance->plugin_pgms); + instance->plugin_pgms = NULL; + instance->plugin_pgm_count = 0; + } + + instance->pending_bank_lsb = -1; + instance->pending_bank_msb = -1; + instance->pending_pgm_change = -1; + + if (x->descriptor->get_program && + x->descriptor->select_program) { + + /* Count the plugins first */ + for (n = 0; x->descriptor-> + get_program(x->instance_handles[i], n); ++n); + + if (n > 0) { + instance->plugin_pgm_count = n; + instance->plugin_pgms = malloc(n * sizeof(DSSI_Program_Descriptor)); + while (n > 0) { + const DSSI_Program_Descriptor *descriptor; + --n; + descriptor = x->descriptor->get_program( + x->instance_handles[i], n); + instance->plugin_pgms[n].Bank = descriptor->Bank; + instance->plugin_pgms[n].Program = descriptor->Program; + instance->plugin_pgms[n].Name = strdup(descriptor->Name); + ph_debug_post("program %d is MIDI bank %lu program %lu," + " named '%s'",i, + instance->plugin_pgms[n].Bank, + instance->plugin_pgms[n].Program, + instance->plugin_pgms[n].Name); + } + } else { + assert(instance->plugin_pgm_count == 0); + } + } +} + +void ph_program_change(ph *x, unsigned int i) +{ + /* jack-dssi-host queues program changes by using pending program change variables. In the audio callback, if a program change is received via MIDI it over writes the pending value (if any) set by the GUI. If unset, or processed the value will default back to -1. The following call to select_program is then made. I don't think it eventually needs to be done this way - i.e. do we need 'pending'? */ + ph_instance *instance; + t_int argc = 3; + t_atom argv[argc]; + + instance = &x->instances[i]; + + ph_debug_post("executing program change"); + + if (instance->pending_pgm_change >= 0){ + if (instance->pending_bank_lsb >= 0) { + if (instance->pending_bank_msb >= 0) { + instance->current_bank = + instance->pending_bank_lsb + 128 * instance->pending_bank_msb; + } else { + instance->current_bank = instance->pending_bank_lsb + + 128 * (instance->current_bank / 128); + } + } else if (instance->pending_bank_msb >= 0) { + instance->current_bank = + (instance->current_bank % 128) + 128 * instance->pending_bank_msb; + } + + instance->current_pgm = instance->pending_pgm_change; + + if (x->descriptor->select_program) { + x->descriptor->select_program(x->instance_handles[i], + instance->current_bank, instance->current_pgm); + } + if (instance->ui_needs_pgm_update){ + ph_debug_post("Updating GUI program"); + + /* TODO - this is a hack to make text ui work*/ + if(x->is_dssi){ + // FIX: need to check this because if we don't have a UI, + // update didn't get called + if (false) { + SETSYMBOL(argv, gensym(instance->ui_osc_program_path)); + SETFLOAT(argv+1, instance->current_bank); + SETFLOAT(argv+2, instance->current_pgm); + ph_instance_send_osc(x->message_out, instance, argc, argv); + } + } + + } + instance->ui_needs_pgm_update = 0; + instance->pending_pgm_change = -1; + instance->pending_bank_msb = -1; + instance->pending_bank_lsb = -1; + } + ph_get_current_pgm(x, i); +} + +char *ph_send_configure(ph *x, const char *key, const char *value, + unsigned int i) +{ + + char *debug; + + debug = x->descriptor->configure(x->instance_handles[i], key, value); + /* TODO:OSC */ + /* if(instance->ui_target != NULL && x->is_dssi) { + lo_send(instance->ui_target, + instance->ui_osc_configure_path, + "ss", key, value); + } + */ + ph_query_programs(x, i); + + return debug; +} + +void ph_instance_send_osc(t_outlet *outlet, ph_instance *instance, + t_int argc, t_atom *argv) +{ + + outlet_anything(outlet, gensym("connect"), UI_TARGET_ELEMS, + instance->ui_target); + outlet_anything(outlet, gensym("send"), argc, argv); + outlet_anything(outlet, gensym("disconnect"), 0, NULL); + +} + +void *ph_load_plugin(ph *x, t_int argc, t_atom *argv) +{ + char *plugin_basename = NULL, + *plugin_full_path = NULL, + *tmpstr, + *plugin_label, + plugin_dir[MAXPDSTRING]; + + ph_debug_post("argc = %d", argc); + + unsigned int i; + int stop; + int fd; + size_t pathlen; + + stop = 0; + + if (!argc){ + pd_error(x, "no arguments given, please supply a path"); + return x; + } + + char *argstr = strdup(argv[0].a_w.w_symbol->s_name); + + if(strstr(argstr, ":") != NULL){ + tmpstr = strtok(argstr, ":"); + plugin_full_path = strdup(tmpstr); + plugin_label = strtok(NULL, ":"); + // first part of the string is empty, i.e. ':mystring' + if (plugin_label == NULL) { + x->plugin_label = plugin_full_path; + plugin_full_path = NULL; + } else { + x->plugin_label = strdup(plugin_label); + } + } else { + x->plugin_label = strdup(argstr); + tmpstr = (char *)plugin_tilde_search_plugin_by_label(x, x->plugin_label); + if(tmpstr) { + plugin_full_path = strdup(tmpstr); + } + } + + free(argstr); + ph_debug_post("plugin path = %s", plugin_full_path); + ph_debug_post("plugin name = %s", x->plugin_label); + + if(plugin_full_path == NULL){ + pd_error(x, "can't get path to plugin"); + return x; + } + + x->plugin_full_path = (char *)plugin_full_path; + + /* search for it in the 'canvas' path, which + * includes the Pd search dirs and any 'extra' paths set with + * [declare] */ + fd = canvas_open(x->x_canvas, plugin_full_path, "", + plugin_dir, &plugin_basename, MAXPDSTRING, 0); + + if (fd >= 0) { + ph_debug_post("plugin directory is %s, filename is %s", + plugin_dir, plugin_basename); + + x->plugin_basename = strdup(plugin_basename); + pathlen = strlen(plugin_dir); + tmpstr = &plugin_dir[pathlen]; + sprintf(tmpstr, "/%s", plugin_basename); + tmpstr = plugin_dir; + x->plugin_handle = loadLADSPAPluginLibrary(tmpstr); + } else { + /* try to load as is: this will work if plugin_full_path is an + * absolute path, or the name of a library that is in DSSI_PATH + * or LADSPA_PATH environment variables */ + x->plugin_handle = loadLADSPAPluginLibrary(plugin_full_path); + } + + if (x->plugin_handle == NULL) { + error("pluginhost~: can't find plugin in Pd paths, " + "try using [declare] to specify the path."); + return x; + } + + tmpstr = strdup(plugin_full_path); + /* Don't bother working out the plugin name if we used canvas_open() + * to get the path */ + if(plugin_basename == NULL){ + if(!strstr(tmpstr, ".so")){ + pd_error(x, "invalid plugin path, must end in .so"); + return x; + } + plugin_basename = strtok((char *)tmpstr, "/"); + while(strstr(plugin_basename, ".so") == NULL) { + plugin_basename = strtok(NULL, "/"); + } + x->plugin_basename = strdup(plugin_basename); + ph_debug_post("plugin basename = %s", x->plugin_basename); + } + free(tmpstr); + if((x->desc_func = (DSSI_Descriptor_Function)dlsym(x->plugin_handle, + "dssi_descriptor"))){ + x->is_dssi = true; + x->descriptor = (DSSI_Descriptor *)x->desc_func(0); + } + else if((x->desc_func = + (DSSI_Descriptor_Function)dlsym(x->plugin_handle, + "ladspa_descriptor"))){ + x->is_dssi = false; + x->descriptor = ladspa_to_dssi((LADSPA_Descriptor *)x->desc_func(0)); + } + + if(argc >= 2) { + x->n_instances = (t_int)argv[1].a_w.w_float; + } else { + x->n_instances = 1; + } + + ph_debug_post("n_instances = %d", x->n_instances); + + x->instances = (ph_instance *)malloc(sizeof(ph_instance) * + x->n_instances); + + if(!x->descriptor){ + pd_error(x, "error: couldn't get plugin descriptor"); + return x; + } + + ph_debug_post("%s loaded successfully!", + x->descriptor->LADSPA_Plugin->Label); + + x->port_info = (ph_port_info *)malloc + (x->descriptor->LADSPA_Plugin->PortCount * + sizeof(ph_port_info)); + + ph_set_port_info(x); + ph_assign_ports(x); + + for(i = 0; i < x->n_instances; i++){ + x->instance_handles[i] = + x->descriptor->LADSPA_Plugin-> + instantiate(x->descriptor->LADSPA_Plugin, x->sr); + if (!x->instance_handles[i]){ + pd_error(x, "instantiation of instance %d failed", i); + stop = 1; + break; + } + } + + if(!stop){ + for(i = 0;i < x->n_instances; i++) + ph_init_instance(x, i); + for(i = 0;i < x->n_instances; i++) + ph_connect_ports(x, i); + for(i = 0;i < x->n_instances; i++) + ph_activate_plugin(x, i); + + if(x->is_dssi){ + for(i = 0;i < x->n_instances; i++) + osc_setup(x, i); +#if LOADGUI + for(i = 0;i < x->n_instances; i++) + ph_load_gui(x, i); +#endif + + for(i = 0;i < x->n_instances; i++) + ph_init_programs(x, i); + + for(i = 0; i < x->n_instances && i < 128; i++){ + x->channel_map[i] = i; + } + } + } + + x->message_out = outlet_new (&x->x_obj, gensym("control")); + + if(x->plugin_outs){ + x->outlets = (t_outlet **)getbytes(x->plugin_outs * sizeof(t_outlet *)); + for(i = 0;i < x->plugin_outs; i++) + x->outlets[i] = outlet_new(&x->x_obj, &s_signal); + } + else { + pd_error(x, "plugin has no outputs"); + } + if(x->plugin_ins){ + x->inlets = (t_inlet **)getbytes(x->plugin_ins * sizeof(t_inlet *)); + for(i = 0;i < x->plugin_ins; i++) { + x->inlets[i] = inlet_new(&x->x_obj, &x->x_obj.ob_pd, + &s_signal, &s_signal); + } + } + else { + pd_error(x, "plugin has no inputs"); + } + + x->dsp = true; + post("%s: %d instances of %s, ready.", PH_NAME, x->n_instances, + x->plugin_label); + + return (void *)x; +} + +void ph_init_plugin(ph *x) +{ + + x->port_info = NULL; + x->descriptor = NULL; + x->instance_event_counts = NULL; + x->instances = NULL; + x->instance_handles = NULL; + x->osc_url_base = NULL; + x->configure_buffer_head = NULL; + x->project_dir = NULL; + x->outlets = NULL; + x->inlets = NULL; + x->message_out = NULL; + x->plugin_handle = NULL; + x->plugin_full_path = NULL; + x->plugin_label = NULL; + x->plugin_basename = NULL; + x->plugin_control_input = NULL; + x->plugin_control_output = NULL; + x->plugin_input_buffers = NULL; + x->plugin_output_buffers = NULL; + x->plugin_ctlin_port_numbers = NULL; + x->plugin_ins = 0; + x->plugin_outs = 0; + x->plugin_control_ins = 0; + x->plugin_control_outs = 0; + x->is_dssi = 0; + x->n_instances = 0; + x->dsp = 0; + x->dsp_loop = 0; + x->ports_in = 0; + x->ports_out = 0; + x->ports_control_in = 0; + x->ports_control_out = 0; + x->buf_write_index = 0; + x->buf_read_index = 0; + +} + +void ph_free_plugin(ph *x) +{ + unsigned int i; + unsigned int n; + + if(x->plugin_label != NULL) { + free((char *)x->plugin_label); + } + + if(x->plugin_handle == NULL) { + return; + } + + free((LADSPA_Handle)x->instance_handles); + free(x->plugin_ctlin_port_numbers); + free((t_float *)x->plugin_input_buffers); + free(x->instance_event_counts); + free(x->plugin_control_input); + free(x->plugin_control_output); + + i = x->n_instances; + + while(i--){ + ph_instance *instance = &x->instances[i]; + + /* TODO:OSC */ + /* + if(instance->gui_pid){ + ph_debug_post("Killing GUI process PID = %d", instance->gui_pid); + + kill(instance->gui_pid, SIGINT); + } */ + if (instance->plugin_pgms) { + for (n = 0; n < instance->plugin_pgm_count; n++) { + free((void *)instance->plugin_pgms[n].Name); + } + free(instance->plugin_pgms); + instance->plugin_pgms = NULL; + instance->plugin_pgm_count = 0; + } + free(x->instance_event_buffers[i]); + if(x->is_dssi){ + free(instance->ui_osc_control_path); + free(instance->ui_osc_configure_path); + free(instance->ui_osc_program_path); + free(instance->ui_osc_show_path); + free(instance->ui_osc_hide_path); + free(instance->ui_osc_quit_path); + free(instance->osc_url_path); + } + free(instance->plugin_port_ctlin_numbers); + if(x->plugin_outs) { + free(x->plugin_output_buffers[i]); + } + } + if(x->is_dssi) { + if(x->project_dir != NULL) { + free(x->project_dir); + } + free(x->osc_url_base); + ph_configure_buffer_free(x); + } + free((snd_seq_event_t *)x->instance_event_buffers); + free(x->instances); + free((t_float *)x->plugin_output_buffers); + + if(x->plugin_ins){ + for(n = 0; n < x->plugin_ins; n++) { + inlet_free((t_inlet *)x->inlets[n]); + } + freebytes(x->inlets, x->plugin_ins * sizeof(t_inlet *)); + } + + if(x->plugin_outs){ + for(n = 0; n < x->plugin_outs; n++) { + outlet_free((t_outlet *)x->outlets[n]); + } + freebytes(x->outlets, x->plugin_outs * sizeof(t_outlet *)); + } + if(x->message_out) { + outlet_free(x->message_out); + } + if(x->plugin_basename) { + free(x->plugin_basename); + } + if(x->port_info) { + free(x->port_info); + } +} + +DSSI_Descriptor *ladspa_to_dssi(LADSPA_Descriptor *ladspaDesc) +{ + DSSI_Descriptor *dssiDesc; + dssiDesc = (DSSI_Descriptor *)calloc(1, sizeof(DSSI_Descriptor)); + ((DSSI_Descriptor *)dssiDesc)->DSSI_API_Version = 1; + ((DSSI_Descriptor *)dssiDesc)->LADSPA_Plugin = + (LADSPA_Descriptor *)ladspaDesc; + return (DSSI_Descriptor *)dssiDesc; +} diff --git a/pluginhost~/ph_common.h b/pluginhost~/ph_common.h new file mode 100644 index 0000000..a3d57a9 --- /dev/null +++ b/pluginhost~/ph_common.h @@ -0,0 +1,171 @@ +/* pluginhost~ - A plugin host for Pd + * + * Copyright (C) 2006 Jamie Bullock and others + * + * This file incorporates code from the following sources: + * + * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. + * + * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 + * + * liblo (CPL license): Copyright (C) 2004 Steve Harris + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "m_pd.h" +#include "dssi.h" + +#define PH_NAME "pluginhost~" +#define PH_VERSION 0.997 +#define EVENT_BUFSIZE 1024 +#define OSC_PORT 9998 +#define UI_TARGET_ELEMS 2 + +/*From hexter_types.h by Sean Bolton */ +#define DX7_PERFORMANCE_SIZE 64 + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +#ifndef HEADER_PH_COMMON + +typedef struct _ph_instance { + + unsigned int plugin_pgm_count; + bool ui_needs_pgm_update; + char *ui_osc_control_path; + char *ui_osc_configure_path; + char *ui_osc_program_path; + char *ui_osc_show_path; + char *ui_osc_hide_path; + char *ui_osc_quit_path; + char *osc_url_path; + long current_bank; + long current_pgm; + int pending_pgm_change; + int pending_bank_lsb; + int pending_bank_msb; + int ui_hidden; + int ui_show; + t_atom ui_target[UI_TARGET_ELEMS]; /* host, port */ + uint8_t perf_buffer[DX7_PERFORMANCE_SIZE]; + + + int *plugin_port_ctlin_numbers; /*not sure if this should go here?*/ + DSSI_Program_Descriptor *plugin_pgms; + +} ph_instance; + +typedef struct ph_configure_pair { + + struct ph_configure_pair *next; + unsigned int instance; + char *value; + char *key; + +} ph_configure_pair; + +typedef struct _port_info { + + t_atom lower_bound; + t_atom upper_bound; + t_atom data_type; + t_atom p_default; + t_atom type; + t_atom name; + +} ph_port_info; + +typedef struct _ph { + + t_object x_obj; /* gah, this has to be first element in the struct, WTF? */ + + int sr; + int blksize; + int time_ref; + int ports_in; + int ports_out; + int ports_control_in; + int ports_control_out; + int buf_write_index; + int buf_read_index; + + bool is_dssi; + bool dsp; + bool dsp_loop; + + char *plugin_basename; + char *plugin_label; + char *plugin_full_path; + char *project_dir; + void *plugin_handle; + char *osc_url_base; + + float f; + float sr_inv; + float **plugin_input_buffers; + float **plugin_output_buffers; + float *plugin_control_input; + float *plugin_control_output; + + unsigned int osc_port; + unsigned int n_instances; + unsigned int plugin_ins; + unsigned int plugin_outs; + unsigned int plugin_control_ins; + unsigned int plugin_control_outs; + unsigned long *instance_event_counts; + unsigned long *plugin_ctlin_port_numbers; + unsigned char channel_map[128]; + + DSSI_Descriptor_Function desc_func; + DSSI_Descriptor *descriptor; + LADSPA_Handle *instance_handles; + + t_inlet **inlets; + t_outlet **outlets; + t_outlet *message_out; + t_canvas *x_canvas; + + ph_port_info *port_info; + ph_instance *instances; + ph_configure_pair *configure_buffer_head; + + snd_seq_event_t **instance_event_buffers; + snd_seq_event_t midi_event_buf[EVENT_BUFSIZE]; + +} ph; + +void ph_debug_post(const char *fmt, ...); +void ph_quit_plugin(ph *x); +void ph_init_plugin(ph *x); +void ph_free_plugin(ph *x); +void ph_query_programs(ph *x, unsigned int i); +void ph_program_change(ph *x, unsigned int i); +void ph_instance_send_osc(t_outlet *outlet, ph_instance *instance, + t_int argc, t_atom *argv); +void *ph_load_plugin(ph *x, t_int argc, t_atom *argv); +char *ph_send_configure(ph *x, const char *key, const char *value, + unsigned int i); +DSSI_Descriptor *ladspa_to_dssi(LADSPA_Descriptor *ladspaDesc); + +#define HEADER_PH_COMMON +#endif + diff --git a/pluginhost~/pluginhost~-help.pd b/pluginhost~/pluginhost~-help.pd new file mode 100644 index 0000000..1227d33 --- /dev/null +++ b/pluginhost~/pluginhost~-help.pd @@ -0,0 +1,161 @@ +#N canvas 41 96 1411 654 10; +#X obj 1268 524 catch~ mix; +#X text 602 15 pluginhost~ - a DSSI host for Pure Data --------------------------------- +; +#X obj 7 63 cnv 15 1400 300 empty empty pluginhost~_instance_1 20 12 +0 14 -257472 -66577 0; +#X obj 443 203 line; +#X msg 443 182 \$1 10; +#X obj 441 225 expr $f1 / 127 * 16383; +#X msg 443 122 0; +#X floatatom 300 185 5 0 0 0 - - -; +#X floatatom 443 165 5 0 0 0 - - -; +#X msg 72 256 n \$1; +#X obj 110 256 r chan; +#X obj 51 231 list prepend n 2; +#X obj 300 226 list prepend c 2; +#X obj 51 208 pack f f; +#X msg 33 147 60; +#X msg 78 147 80; +#X msg 300 205 7 \$1; +#X obj 441 247 list prepend b 2 0; +#X obj 441 324 throw~ mix; +#X obj 119 148 hsl 128 15 60 80 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 167 206 select -1; +#X obj 356 250 r chan; +#X obj 303 146 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144 +-1 -1 0 1; +#X obj 446 144 hsl 128 15 -63 63 0 1 empty empty empty -2 -6 0 8 -262144 +-1 -1 6300 1; +#X obj 600 291 r dssi1-config; +#X obj 708 179 s dssi1-config; +#X obj 912 178 s dssi1-config; +#X obj 1194 180 s dssi1-config; +#X floatatom 595 142 5 0 0 0 - - -; +#X msg 318 250 c \$1; +#X obj 528 268 r chan; +#X msg 473 268 b \$1 0; +#X obj 1014 337 s chan; +#X floatatom 1015 319 5 1 2 1 channel - -; +#X text 283 98 ----control change----; +#X obj 667 222 r chan; +#X text 447 97 ----pitch bend----; +#X text 585 97 --program change--; +#X text 105 96 -----notes-----; +#X text 718 97 --sysex patch/bank load--; +#X obj 5 371 cnv 15 600 300 empty empty pluginhost~_instance_2 20 12 +0 14 -225280 -66577 0; +#X obj 435 620 throw~ mix; +#X obj 474 122 loadbang; +#X msg 613 221 p \$1 0; +#X text 940 96 --configuration--; +#X text 947 113 (key value pair); +#X text 867 279 Select channel (hexter instance) for note \, bend \, +program and control data:; +#X obj 595 199 list prepend p 2 0; +#X text 1126 98 --show/hide GUI--; +#X obj 49 186 makenote 80 10000; +#X msg 1282 136 reset; +#X msg 1340 136 reset 1; +#X text 1286 98 -reset plugin-; +#X text 1286 115 (all notes off); +#X obj 229 315 print; +#X msg 78 305 listplugins; +#X msg 101 329 info; +#X msg 709 134 dssi load TX-SYX/TFI2.SYX 2; +#X msg 710 154 dssi load TX-SYX/TFI1.SYX 1; +#X msg 910 134 dssi configure polyphony 10 2; +#X msg 911 156 dssi configure GLOBAL:polyphony 10; +#X msg 1134 114 dssi hide; +#X msg 1135 135 dssi show; +#X msg 1206 114 dssi show 2; +#X text 806 212 LAST ARGUMENT GIVES PLUGIN INSTANCE TO BE CONFIGURED +\, NO LAST ARGUMENT=(ALL INSTANCES); +#X obj 388 620 print; +#X text 738 458 Usage: [pluginhost~ <[path to libary:plugin name] or +[plugin name]> ]; +#X obj 229 291 pluginhost~ hexter.so:hexter 2; +#X msg 193 342 control #1 445; +#X obj 451 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 378 582 pluginhost~ sine_faaa 6 -------------; +#X obj 284 438 expr $f1 \; $f1*2 \; $f1*3 \; $f1*4 \; $f1*5 \; $f1*6 +; +#X obj 285 397 loadbang; +#X msg 285 419 220; +#X obj 471 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 491 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 511 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 531 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X obj 551 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144 +-1 -1 0 1; +#X text 591 561 <- Audio rate control inputs can be audio or control +values; +#X text 14 491 Experimental - use with caution!; +#X msg 54 509 plug sine_faac 6; +#X obj 1266 547 output~; +#X msg 733 376 dssi configure pitch_bend_range 12 1; +#X obj 1109 341 loadbang; +#X msg 1109 384 1; +#X msg 742 412 dssi configure portamento_time 50 1; +#X connect 0 0 82 0; +#X connect 0 0 82 1; +#X connect 3 0 5 0; +#X connect 4 0 3 0; +#X connect 5 0 17 0; +#X connect 6 0 23 0; +#X connect 7 0 16 0; +#X connect 8 0 4 0; +#X connect 9 0 11 1; +#X connect 10 0 9 0; +#X connect 11 0 67 0; +#X connect 12 0 67 0; +#X connect 13 0 11 0; +#X connect 14 0 49 0; +#X connect 15 0 49 0; +#X connect 16 0 12 0; +#X connect 17 0 67 0; +#X connect 19 0 49 0; +#X connect 20 1 49 0; +#X connect 21 0 29 0; +#X connect 22 0 7 0; +#X connect 23 0 8 0; +#X connect 24 0 67 0; +#X connect 28 0 47 0; +#X connect 29 0 12 1; +#X connect 30 0 31 0; +#X connect 31 0 17 1; +#X connect 33 0 32 0; +#X connect 35 0 43 0; +#X connect 42 0 6 0; +#X connect 43 0 47 1; +#X connect 47 0 67 0; +#X connect 49 0 13 0; +#X connect 49 1 13 1; +#X connect 50 0 27 0; +#X connect 51 0 27 0; +#X connect 55 0 67 0; +#X connect 56 0 67 0; +#X connect 57 0 25 0; +#X connect 58 0 25 0; +#X connect 59 0 26 0; +#X connect 60 0 26 0; +#X connect 61 0 27 0; +#X connect 62 0 27 0; +#X connect 63 0 27 0; +#X connect 67 0 54 0; +#X connect 67 1 18 0; +#X connect 67 2 18 0; +#X connect 68 0 67 0; +#X connect 72 0 73 0; +#X connect 73 0 71 0; +#X connect 81 0 70 0; +#X connect 83 0 67 0; +#X connect 84 0 85 0; +#X connect 85 0 33 0; +#X connect 86 0 67 0; diff --git a/pluginhost~/pluginhost~-meta.pd b/pluginhost~/pluginhost~-meta.pd new file mode 100644 index 0000000..0f11c41 --- /dev/null +++ b/pluginhost~/pluginhost~-meta.pd @@ -0,0 +1,9 @@ +#N canvas 10 10 200 200 10; +#N canvas 20 20 420 300 META 0; +#X text 10 10 META this is a prototype of a libdir meta file; +#X text 10 30 NAME pluginhost~; +#X text 10 50 AUTHOR Jamie Bullock; +#X text 10 70 DESCRIPTION pluginhost~ is a LADSPA and DSSI plugin host for Pure Data, supporting multiple plugin instances per object; +#X text 10 90 LICENSE GNU GPL; +#X text 10 110 VERSION 1.0; +#X restore 10 10 pd META; diff --git a/pluginhost~/pluginhost~.c b/pluginhost~/pluginhost~.c new file mode 100644 index 0000000..76faff1 --- /dev/null +++ b/pluginhost~/pluginhost~.c @@ -0,0 +1,95 @@ +/* pluginhost~ - A plugin host for Pd + * + * Copyright (C) 2006 Jamie Bullock and others + * + * This file incorporates code from the following sources: + * + * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. + * + * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 + * + * liblo (CPL license): Copyright (C) 2004 Steve Harris + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include + +#include "ph_common.h" +#include "handlers_pd.h" + +static t_class *ph_class; + +static void *ph_new(t_symbol *s, t_int argc, t_atom *argv) +{ + + ph *x = (ph *)pd_new(ph_class); + post("\n========================================\n" + "%s(): version %.2f\n========================================\n", + PH_NAME, PH_VERSION); + + ph_init_plugin(x); + + x->sr = (int)sys_getsr(); + x->sr_inv = 1 / (t_float)x->sr; + x->dsp = 0; + x->time_ref = (t_int)clock_getlogicaltime; + x->blksize = sys_getblksize(); + x->x_canvas = canvas_getcurrent(); + + return ph_load_plugin(x, argc, argv); + +} + +static void ph_free(ph *x) +{ + ph_quit_plugin(x); + ph_free_plugin(x); +} + +static void ph_sigchld_handler(int sig) +{ + wait(NULL); +} + +void pluginhost_tilde_setup(void) +{ + + ph_class = class_new(gensym("pluginhost~"), (t_newmethod)ph_new, + (t_method)ph_free, sizeof(ph), 0, A_GIMME, 0); + class_addlist(ph_class, handle_pd_list); + class_addbang(ph_class, handle_pd_bang); + class_addmethod(ph_class, (t_method)handle_pd_dsp, gensym("dsp"), 0); + class_addmethod (ph_class,(t_method)handle_pd_info, gensym ("info"), 0); + class_addmethod(ph_class, (t_method)handle_pd_dssi, + gensym("dssi"), A_GIMME, 0); + class_addmethod (ph_class,(t_method)handle_pd_control, + gensym ("control"),A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod (ph_class,(t_method)handle_pd_listplugins, + gensym ("listplugins"),0); + class_addmethod (ph_class,(t_method)handle_pd_reset, + gensym ("reset"), A_DEFFLOAT, 0); + class_addmethod (ph_class, (t_method)handle_pd_osc, + gensym("osc"), A_GIMME, 0); + class_sethelpsymbol(ph_class, gensym("pluginhost~-help")); + + CLASS_MAINSIGNALIN(ph_class, ph, f); + signal(SIGCHLD, ph_sigchld_handler); +} + diff --git a/pluginhost~/src/handlers_osc.c b/pluginhost~/src/handlers_osc.c deleted file mode 100644 index 4114baf..0000000 --- a/pluginhost~/src/handlers_osc.c +++ /dev/null @@ -1,311 +0,0 @@ -/* pluginhost~ - A plugin host for Pd - * - * Copyright (C) 2006 Jamie Bullock and others - * - * This file incorporates code from the following sources: - * - * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - * - * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. - * - * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 - * - * liblo (CPL license): Copyright (C) 2004 Steve Harris - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include - -#include "ph_common.h" - -/* - * taken from liblo lo_url_get_path by Steve Harris et al - */ -char *osc_get_valid_path(const char *url) -{ - char *path = malloc(strlen(url)); - - if (sscanf(url, "osc://%*[^:]:%*[0-9]%s", path)) { - return path; - } - if (sscanf(url, "osc.%*[^:]://%*[^:]:%*[0-9]%s", path) == 1) { - return path; - } - if (sscanf(url, "osc.unix://%*[^/]%s", path) == 1) { - return path; - } - if (sscanf(url, "osc.%*[^:]://%s", path)) { - return path; - } - - /* doesnt look like an OSC URL with port number and path*/ - return NULL; -} -/* end liblo code */ - -void handle_osc_debug(const char *path) -{ - - ph_debug_post("got unhandled OSC message:\npath: <%s>\n", path); - -} - -void handle_osc_program(ph *x, t_atom *argv, unsigned int i) -{ - unsigned long bank; - unsigned long program; - unsigned int n; - bool found; - ph_instance *instance; - - bank = atom_getfloat(&argv[0]); - program = atom_getfloat(&argv[1]); - instance = &x->instances[i]; - found = false; - - ph_debug_post("%d programs", instance->plugin_pgm_count); - - for (n = 0; n < instance->plugin_pgm_count; ++n) { - if (instance->plugin_pgms[n].Bank == bank && - instance->plugin_pgms[n].Program == program) { - ph_debug_post("OSC: setting bank %u, program %u, name %s\n", - bank, program, instance->plugin_pgms[n].Name); - found = true; - break; - } - } - - if (!found) { - pd_error(x, "UI requested unknown program: bank %lu, program %lu: " - "sending to plugin anyway (plugin should ignore it)\n", - bank, program); - } - - instance->pending_bank_msb = bank / 128; - instance->pending_bank_lsb = bank % 128; - instance->pending_pgm_change = program; - - ph_debug_post("bank = %d, program = %d, BankMSB = %d BankLSB = %d", - bank, program, instance->pending_bank_msb, - instance->pending_bank_lsb); - - ph_program_change(x, i); - -} - -void handle_osc_control(ph *x, t_atom *argv, int i) -{ - int port; - LADSPA_Data value; - ph_instance *instance; - - port = (int)atom_getfloat(&argv[0]); - value = atom_getfloat(&argv[1]); - instance = &x->instances[i]; - - x->plugin_control_input[instance->plugin_port_ctlin_numbers[port]] = value; - ph_debug_post("OSC: port %d = %f", port, value); - -} - -void handle_osc_midi(ph *x, t_atom *argv, unsigned int i) -{ - pd_error(x, "MIDI over OSC currently unsupported"); -} - -void handle_osc_configure(ph *x, t_atom *argv, int i) -{ - const char *key; - const char *value; - char *message; - - key = atom_getsymbol(&argv[0])->s_name; - value = atom_getsymbol(&argv[1])->s_name; - - ph_debug_post("%s()", __FUNCTION__); - - if (!x->descriptor->configure) { - return; - } - - if (!strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, - strlen(DSSI_RESERVED_CONFIGURE_PREFIX))) { - pd_error(x,"UI for plugin '' attempted to use reserved " - "configure key \"%s\", ignoring", key); - return; - } - - message = x->descriptor->configure(x->instance_handles[i], key, value); - - if (message) { - pd_error(x, "on configure '%s', plugin '' returned error '%s'", - key, message); - free(message); - } - - ph_query_programs(x, i); - -} - -void handle_osc_exiting(ph *x, t_atom *argv, int i) -{ - - ph_instance *instance; - - instance = &x->instances[i]; - - free(instance->ui_osc_control_path); - free(instance->ui_osc_configure_path); - free(instance->ui_osc_hide_path); - free(instance->ui_osc_program_path); - free(instance->ui_osc_show_path); - free(instance->ui_osc_quit_path); - instance->ui_osc_control_path = NULL; - instance->ui_osc_configure_path = NULL; - instance->ui_osc_hide_path = NULL; - instance->ui_osc_program_path = NULL; - instance->ui_osc_show_path = NULL; - instance->ui_osc_quit_path = NULL; - instance->ui_hidden = true; - -} - -void handle_osc_update(ph *x, t_atom *argv, unsigned int i) -{ - const char *url; - const char *path; - unsigned int n; - unsigned int ac = 3; - t_atom av[ac]; - ph_configure_pair *p; - ph_instance *instance; - - instance = &x->instances[i]; - url = atom_getsymbol(&argv[0])->s_name; - p = x->configure_buffer_head; - - ph_debug_post("OSC: got update request from <%s>, instance %d", - url, instance); - - path = osc_get_valid_path(url); - - if(path == NULL) { - pd_error(x, "invalid url: %s", url); - return; - } - - if (instance->ui_osc_control_path) { - free(instance->ui_osc_control_path); - } - instance->ui_osc_control_path = malloc(strlen(path) + 10); - sprintf(instance->ui_osc_control_path, "%s/control", path); - - if (instance->ui_osc_configure_path) { - free(instance->ui_osc_configure_path); - } - instance->ui_osc_configure_path = malloc(strlen(path) + 12); - sprintf(instance->ui_osc_configure_path, "%s/configure", path); - - if (instance->ui_osc_program_path) { - free(instance->ui_osc_program_path); - } - instance->ui_osc_program_path = malloc(strlen(path) + 10); - sprintf(instance->ui_osc_program_path, "%s/program", path); - - if (instance->ui_osc_quit_path) { - free(instance->ui_osc_quit_path); - } - instance->ui_osc_quit_path = malloc(strlen(path) + 10); - sprintf(instance->ui_osc_quit_path, "%s/quit", path); - - if (instance->ui_osc_show_path) { - free(instance->ui_osc_show_path); - } - instance->ui_osc_show_path = malloc(strlen(path) + 10); - sprintf(instance->ui_osc_show_path, "%s/show", path); - - if (instance->ui_osc_hide_path) { - free(instance->ui_osc_hide_path); - } - instance->ui_osc_hide_path = (char *)malloc(strlen(path) + 10); - sprintf(instance->ui_osc_hide_path, "%s/hide", path); - - free((char *)path); - - while(p){ - if(p->instance == i) { - ph_send_configure(x, p->key, p->value, i); - } - p = p->next; - } - - /* Send current bank/program */ - if (instance->pending_pgm_change >= 0) { - ph_program_change(x, i); - } - - ph_debug_post("pending_pgm_change = %d", instance->pending_pgm_change); - - if (instance->pending_pgm_change < 0) { - unsigned long bank; - unsigned long program; - ac = 3; - - program = instance->current_pgm; - bank = instance->current_bank; - instance->ui_needs_pgm_update = 0; - - SETSYMBOL(av, gensym(instance->ui_osc_program_path)); - SETFLOAT(av+1, bank); - SETFLOAT(av+2, program); - - ph_instance_send_osc(x->message_out, instance, ac, av); - - } - - /* Send control ports */ - for (n = 0; n < x->plugin_control_ins; n++) { - - ac = 3; - - SETSYMBOL(av, gensym(instance->ui_osc_control_path)); - SETFLOAT(av+1, x->plugin_ctlin_port_numbers[n]); - SETFLOAT(av+2, x->plugin_control_input[n]); - - ph_instance_send_osc(x->message_out, instance, ac, av); - - ph_debug_post("Port: %d, Default value: %.2f", - x->plugin_ctlin_port_numbers[n], x->plugin_control_input[n]); - - } - - /* Send 'show' */ - if (instance->ui_show) { - - ac = 2; - - SETSYMBOL(av, gensym(instance->ui_osc_show_path)); - SETSYMBOL(av, gensym("")); - - ph_instance_send_osc(x->message_out, instance, ac, av); - - instance->ui_hidden = false; - instance->ui_show = false; - } -} - diff --git a/pluginhost~/src/handlers_osc.h b/pluginhost~/src/handlers_osc.h deleted file mode 100644 index a45c56a..0000000 --- a/pluginhost~/src/handlers_osc.h +++ /dev/null @@ -1,40 +0,0 @@ -/* pluginhost~ - A plugin host for Pd - * - * Copyright (C) 2006 Jamie Bullock and others - * - * This file incorporates code from the following sources: - * - * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - * - * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. - * - * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 - * - * liblo (CPL license): Copyright (C) 2004 Steve Harris - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "m_pd.h" -#include "ph_common.h" - -void handle_osc_debug(const char *path); -void handle_osc_program(ph *x, t_atom *argv, unsigned int i); -void handle_osc_control(ph *x, t_atom *argv, int i); -void handle_osc_midi(ph *x, t_atom *argv, unsigned int i); -void handle_osc_configure(ph *x, t_atom *argv, int i); -void handle_osc_exiting(ph *x, t_atom *argv, int i); -void handle_osc_update(ph *x, t_atom *argv, unsigned int i); - diff --git a/pluginhost~/src/handlers_pd.c b/pluginhost~/src/handlers_pd.c deleted file mode 100644 index bf5fd45..0000000 --- a/pluginhost~/src/handlers_pd.c +++ /dev/null @@ -1,1153 +0,0 @@ -/* %s - A plugin host for Pd - * - * Copyright (C) 2006 Jamie Bullock and others - * - * This file incorporates code from the following sources: - * - * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - * - * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. - * - * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 - * - * liblo (CPL license): Copyright (C) 2004 Steve Harris - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include /* for uint8_t */ - -#include "jutils.h" -#include "handlers_osc.h" -#include "ph_common.h" - -#define DX7_VOICE_SIZE_PACKED 128 /*From hexter_types.h by Sean Bolton */ -#define DX7_DUMP_SIZE_BULK 4096+8 -#define DX7_BANK_SIZE 32 -#define DX7_MAX_PATCH_SIZE 16384 -#define ASCII_t 116 -#define ASCII_p 112 -#define ASCII_n 110 -#define ASCII_c 99 -#define ASCII_b 98 -#define ASCII_a 97 -#define TYPE_STRING_SIZE 20 -#define OSC_ADDR_MAX 8192 - -#if DEBUG == 1 -#define CHECKSUM_PATCH_FILES_ON_LOAD 1 -#endif - -#define CLASS_NAME_STR "pluginhost~" - - -/*From dx7_voice.h by Sean Bolton */ -typedef struct _dx7_patch_t { - uint8_t data[128]; -} dx7_patch_t; - - -/*From dx7_voice_data.c by Sean Bolton */ -static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* - * dx7_bulk_dump_checksum - ** Taken from dx7_voice_data.c by Sean Bolton ** - */ -static int -dx7_bulk_dump_checksum(uint8_t *data, int length) -{ - int sum = 0; - int i; - - for (i = 0; i < length; sum -= data[i++]); - return sum & 0x7F; -} - -/* - * encode_7in6 - ** Taken from gui_data.c by Sean Bolton ** - * - * encode a block of 7-bit data, in base64-ish style - */ -char *encode_7in6(uint8_t *data, int length) -{ - char *buffer; - int in, reg, above, below, shift, out; - int outchars = (length * 7 + 5) / 6; - unsigned int sum = 0; - - if (!(buffer = (char *)malloc(25 + outchars))) - return NULL; - - out = snprintf(buffer, 12, "%d ", length); - - in = reg = above = below = 0; - while (outchars) { - if (above == 6) { - buffer[out] = base64[reg >> 7]; - reg &= 0x7f; - above = 0; - out++; - outchars--; - } - if (below == 0) { - if (in < length) { - reg |= data[in] & 0x7f; - sum += data[in]; - } - below = 7; - in++; - } - shift = 6 - above; - if (below < shift) shift = below; - reg <<= shift; - above += shift; - below -= shift; - } - - snprintf(buffer + out, 12, " %d", sum); - - return buffer; -} - - - -/* end hexter code */ - - -static void ph_ladspa_description(ph *x, t_atom *at, - DSSI_Descriptor *psDescriptor){ - at[0].a_w.w_symbol = - gensym ((char*)psDescriptor->LADSPA_Plugin->Name); - outlet_anything (x->message_out, gensym ("name"), 1, at); - at[0].a_w.w_symbol = - gensym ((char*)psDescriptor->LADSPA_Plugin->Label); - outlet_anything (x->message_out, gensym ("label"), 1, at); - at[0].a_type = A_FLOAT; - at[0].a_w.w_float = psDescriptor->LADSPA_Plugin->UniqueID; - outlet_anything (x->message_out, gensym ("id"), 1, at); - at[0].a_type = A_SYMBOL; - at[0].a_w.w_symbol = - gensym ((char*)psDescriptor->LADSPA_Plugin->Maker); - outlet_anything (x->message_out, gensym ("maker"), 1, at); -} - -static void ph_midibuf_add(ph *x, int type, unsigned int chan, int param, int val) -{ - - if(chan > x->n_instances - 1){ - pd_error(x, "note discarded: MIDI data is for a bogus channel"); - return; - } - - t_int time_ref = x->time_ref; - t_int mapped; - - //mapped = x->channel_map[chan + 1] - 1; - /* FIX: get rid of mapping functionality */ - mapped = chan; - - x->midi_event_buf[x->buf_write_index].time.time.tv_sec = - (t_int)(clock_gettimesince(time_ref) * .001); - x->midi_event_buf[x->buf_write_index].time.time.tv_nsec = - (t_int)(clock_gettimesince(time_ref) * 1000); /*actually usec - we can't store this in nsec! */ - - if ((type == SND_SEQ_EVENT_NOTEON && val != 0) || - type != SND_SEQ_EVENT_NOTEON) { - x->midi_event_buf[x->buf_write_index].type = type; - switch (type) { - case SND_SEQ_EVENT_NOTEON: - x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; - x->midi_event_buf[x->buf_write_index].data.note.note = param; - x->midi_event_buf[x->buf_write_index].data.note.velocity = val; - break; - case SND_SEQ_EVENT_NOTEOFF: - x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; - x->midi_event_buf[x->buf_write_index].data.note.note = param; - x->midi_event_buf[x->buf_write_index].data.note.velocity = val; - break; - case SND_SEQ_EVENT_CONTROLLER: - x->midi_event_buf[x->buf_write_index].data.control.channel = mapped; - x->midi_event_buf[x->buf_write_index].data.control.param = param; - x->midi_event_buf[x->buf_write_index].data.control.value = val; - break; - case SND_SEQ_EVENT_PITCHBEND: - x->midi_event_buf[x->buf_write_index].data.control.channel = mapped; - x->midi_event_buf[x->buf_write_index].data.control.param = 0; - x->midi_event_buf[x->buf_write_index].data.control.value = val; - break; - case SND_SEQ_EVENT_CHANPRESS: - x->midi_event_buf[x->buf_write_index].data.control.channel = mapped; - x->midi_event_buf[x->buf_write_index].data.control.param = 0; - x->midi_event_buf[x->buf_write_index].data.control.value = val; - break; - case SND_SEQ_EVENT_KEYPRESS: - x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; - x->midi_event_buf[x->buf_write_index].data.note.note = param; - x->midi_event_buf[x->buf_write_index].data.note.velocity = val; - break; - case SND_SEQ_EVENT_PGMCHANGE: - x->instances[mapped].pending_bank_msb = (param - 1) / 128; - x->instances[mapped].pending_bank_lsb = (param - 1) % 128; - x->instances[mapped].pending_pgm_change = val; - x->instances[mapped].ui_needs_pgm_update = 1; - ph_debug_post("pgm chabge received in buffer: MSB: %d, LSB %d, prog: %d", - x->instances[mapped].pending_bank_msb, x->instances[mapped].pending_bank_lsb, val); - - ph_program_change(x, mapped); - break; - } - } - else if (type == SND_SEQ_EVENT_NOTEON && val == 0) { - x->midi_event_buf[x->buf_write_index].type = SND_SEQ_EVENT_NOTEOFF; - x->midi_event_buf[x->buf_write_index].data.note.channel = mapped; - x->midi_event_buf[x->buf_write_index].data.note.note = param; - x->midi_event_buf[x->buf_write_index].data.note.velocity = val; - } - - ph_debug_post("MIDI received in buffer: chan %d, param %d, val %d, mapped to %d", - chan, param, val, mapped); - - x->buf_write_index = (x->buf_write_index + 1) % EVENT_BUFSIZE; -} - -static void ph_set_control_input_by_index (ph *x, - unsigned int ctrl_input_index, float value, unsigned int i) -{ - long port, portno; - t_int argc = 3; - t_atom argv[argc]; - ph_instance *instance; - - if (ctrl_input_index >= x->plugin_control_ins) { - pd_error(x, "control port number %d is out of range [1, %d]", - ctrl_input_index + 1, x->plugin_control_ins); - return; - } - - ph_debug_post("ctrl input number = %d", ctrl_input_index); - - port = x->plugin_ctlin_port_numbers[ctrl_input_index]; - - instance = &x->instances[i]; - - /* TODO - temporary hack */ - if(x->is_dssi) { - portno = instance->plugin_port_ctlin_numbers[ctrl_input_index + 1]; - } else { - portno = instance->plugin_port_ctlin_numbers[ctrl_input_index]; - } - - ph_debug_post("Global ctrl input number = %d", ctrl_input_index); - ph_debug_post("Global ctrl input value = %.2f", value); - - /* set the appropriate control port value */ - x->plugin_control_input[portno] = value; - - /* Update the UI if there is one */ - if(!x->is_dssi){ - return; - } - - if(instance->ui_osc_control_path == NULL){ - pd_error(x, "unable to send to NULL control path"); - return; - } - - SETSYMBOL(argv, gensym(instance->ui_osc_control_path)); - SETFLOAT(argv+1, port); - SETFLOAT(argv+2, value); - ph_instance_send_osc(x->message_out, instance, argc, argv); - -} - -static unsigned ph_get_param_num (ph *x, const char *str) -/* find out if str points to a parameter number or not and return the - number or zero. The number string has to begin with a '#' character */ -{ - long num = 0; - char* strend = NULL; - - if (str == NULL) { - return 0; - } - if (str[0] != '#') { - return 0; - } - num = strtol (&str[1], &strend, 10); - if (str[1] == 0 || *strend != 0) { - /* invalid string */ - return 0; - } - else if (num >= 1 && num <= (long)x->plugin_control_ins) { - /* string ok and within range */ - return (unsigned)num; - } - else { - /* number out of range */ - return 0; - } -} - -static void ph_set_control_input_by_name (ph *x, - const char* name, - float value, - unsigned int i) -{ - unsigned port_index = 0; - unsigned ctrl_input_index = 0; - int found_port = 0; /* boolean */ - - if (name == NULL || strlen (name) == 0) { - pd_error(x, "no control port name specified"); - return; - } - - /* compare control name to LADSPA control input ports' names - case-insensitively */ - found_port = 0; - ctrl_input_index = 0; - for (port_index = 0; port_index < x->descriptor->LADSPA_Plugin->PortCount; - port_index++) - { - LADSPA_PortDescriptor port_type; - port_type = x->descriptor->LADSPA_Plugin->PortDescriptors[port_index]; - if (LADSPA_IS_PORT_CONTROL (port_type) - && LADSPA_IS_PORT_INPUT (port_type)) - { - const char* port_name = NULL; - unsigned cmp_length = 0; - port_name = x->descriptor->LADSPA_Plugin->PortNames[port_index]; - cmp_length = MIN (strlen(name), strlen(port_name)); - if (cmp_length != 0 - && strncasecmp (name, port_name, cmp_length) == 0) - { - /* found the first port to match */ - found_port = 1; - break; - } - ctrl_input_index++; - } - } - - if (!found_port) { - pd_error(x, "plugin doesn't have a control input port named \"%s\"", - name); - return; - } - - ph_set_control_input_by_index (x, ctrl_input_index, value, i); - -} - -static void ph_ladspa_describe(const char * pcFullFilename, - void * pvPluginHandle, - DSSI_Descriptor_Function fDescriptorFunction, - void* user_data, - int is_dssi) -{ - - ph *x = (((void**)user_data)[0]); - t_atom at[1]; - DSSI_Descriptor *psDescriptor; - long lIndex; - - at[0].a_type = A_SYMBOL; - at[0].a_w.w_symbol = gensym ((char*)pcFullFilename); - outlet_anything (x->message_out, gensym ("library"), 1, at); - - if(is_dssi){ - ph_debug_post("DSSI plugin found by listinfo"); - - for (lIndex = 0; - (psDescriptor = (DSSI_Descriptor *) - fDescriptorFunction(lIndex)) != NULL; lIndex++) - ph_ladspa_description(x, &at[0], psDescriptor); - } - - else if(!is_dssi) - lIndex = 0; - do{ - psDescriptor = ladspa_to_dssi((LADSPA_Descriptor *)fDescriptorFunction(lIndex++)); - if(psDescriptor->LADSPA_Plugin != NULL){ - ph_ladspa_description(x, &at[0], psDescriptor); - free((DSSI_Descriptor *)psDescriptor); - } - else - break; - } while(1); -} - -static void ph_show(ph *x, unsigned int i, bool toggle) -{ - /* TODO:OSC */ -/* - if(instance->ui_target){ - if (instance->ui_hidden && toggle) { - lo_send(instance->ui_target, - instance->ui_osc_show_path, ""); - instance->ui_hidden = 0; - } - else if (!instance->ui_hidden && !toggle) { - instance->ui_osc_hide_path, ""); - instance->ui_hidden = 1; - } - } - else if(toggle){ - instance->ui_show = 1; - ph_load_gui(x, instance); - - } - */ -} - -static t_int ph_configure_buffer(ph *x, char *key, - char *value, unsigned int i) -{ - - ph_configure_pair *current; - ph_configure_pair *p; - ph_instance *instance; - - instance = &x->instances[i]; - current = x->configure_buffer_head; - - while(current){ - if(!strcmp(current->key, key) && current->instance == i) { - break; - } - current = current->next; - } - if(current) { - free(current->value); - } else { - current = malloc(sizeof(ph_configure_pair)); - current->next = x->configure_buffer_head; - current->key = strdup(key); - current->instance = i; - x->configure_buffer_head = current; - } - current->value = strdup(value); - p = x->configure_buffer_head; - - /*TODO: eventually give ability to query this buffer (to outlet?) */ - while(p){ - ph_debug_post("key: %s", p->key); - ph_debug_post("val: %s", p->value); - ph_debug_post("instance: %d", p->instance); - p = p->next; - } - - return 0; -} - -static t_int *ph_perform(t_int *w) -{ - unsigned int instance; - unsigned int i; - unsigned int N; - int timediff; - int framediff; - t_float **inputs; - t_float **outputs; - ph *x; - - x = (ph *)(w[1]); - N = (unsigned int)(w[2]); - inputs = (t_float **)(&w[3]); - outputs = (t_float **)(&w[3] + x->plugin_ins); - - if(x->dsp){ - x->dsp_loop = true; - - for(i = 0; i < x->plugin_ins; i++) - memcpy(x->plugin_input_buffers[i], inputs[i], N * - sizeof(LADSPA_Data)); - - for (i = 0; i < x->n_instances; i++) - x->instance_event_counts[i] = 0; - - for (;x->buf_read_index != x->buf_write_index; x->buf_read_index = - (x->buf_read_index + 1) % EVENT_BUFSIZE) { - - instance = x->midi_event_buf[x->buf_read_index].data.note.channel; - - if(instance > x->n_instances){ - pd_error(x, - "%s: %s: discarding spurious MIDI data, for instance %d", - CLASS_NAME_STR, - x->descriptor->LADSPA_Plugin->Label, - instance); - ph_debug_post("n_instances = %d", x->n_instances); - - continue; - } - - if (x->instance_event_counts[instance] == EVENT_BUFSIZE){ - pd_error(x, "MIDI overflow on channel %d", instance); - continue; - } - - timediff = (int)(clock_gettimesince(x->time_ref) * 1000) - - x->midi_event_buf[x->buf_read_index].time.time.tv_nsec; - framediff = (int)((t_float)timediff * .000001 / x->sr_inv); - - if (framediff >= (int)N || framediff < 0) - x->midi_event_buf[x->buf_read_index].time.tick = 0; - else - x->midi_event_buf[x->buf_read_index].time.tick = - N - framediff - 1; - - x->instance_event_buffers[instance] - [x->instance_event_counts[instance]] = - x->midi_event_buf[x->buf_read_index]; - ph_debug_post("%s, note received on channel %d", - x->descriptor->LADSPA_Plugin->Label, - x->instance_event_buffers[instance] - [x->instance_event_counts[instance]].data.note.channel); - - x->instance_event_counts[instance]++; - - ph_debug_post("Instance event count for instance %d of %d: %d\n", - instance + 1, x->n_instances, x->instance_event_counts[instance]); - - - } - - i = 0; - while(i < x->n_instances){ - if(x->instance_handles[i] && - x->descriptor->run_multiple_synths){ - x->descriptor->run_multiple_synths - (x->n_instances, x->instance_handles, - (unsigned long)N, x->instance_event_buffers, - &x->instance_event_counts[0]); - break; - } - else if (x->instance_handles[i] && - x->descriptor->run_synth){ - x->descriptor->run_synth(x->instance_handles[i], - (unsigned long)N, x->instance_event_buffers[i], - x->instance_event_counts[i]); - i++; - } - else if (x->instance_handles[i] && - x->descriptor->LADSPA_Plugin->run){ - x->descriptor->LADSPA_Plugin->run - (x->instance_handles[i], N); - i++; - } - } - - - for(i = 0; i < x->plugin_outs; i++) - memcpy(outputs[i], (t_float *)x->plugin_output_buffers[i], N * - sizeof(LADSPA_Data)); - - x->dsp_loop = false; - } - return w + (x->plugin_ins + x->plugin_outs + 3); -} - - -/* ======================================== */ - -void handle_pd_bang(ph *x) -{ - t_atom at[3]; - - at[0].a_type = A_FLOAT; - at[1].a_type = A_SYMBOL; - at[2].a_type = A_SYMBOL; - - if(x->plugin_label != NULL){ - at[0].a_w.w_float = x->n_instances; - at[1].a_w.w_symbol = gensym ((char *)x->plugin_label); - } - else{ - at[0].a_w.w_float = 0; - at[1].a_w.w_symbol = gensym ("plugin"); - } - at[2].a_w.w_symbol = gensym ("instances"); - outlet_anything (x->message_out, gensym ("running"), 3, at); -} - -void handle_pd_list(ph *x, t_symbol *s, int argc, t_atom *argv) -{ - char msg_type[TYPE_STRING_SIZE]; - int ev_type = 0; - atom_string(argv, msg_type, TYPE_STRING_SIZE); - int chan = (int)atom_getfloatarg(1, argc, argv) - 1; - int param = (int)atom_getfloatarg(2, argc, argv); - int val = (int)atom_getfloatarg(3, argc, argv); - int n_instances = x->n_instances; - - switch (msg_type[0]){ - case ASCII_n: ev_type = SND_SEQ_EVENT_NOTEON; - break; - case ASCII_c: ev_type = SND_SEQ_EVENT_CONTROLLER; - break; - case ASCII_p: ev_type = SND_SEQ_EVENT_PGMCHANGE; - break; - case ASCII_b: ev_type = SND_SEQ_EVENT_PITCHBEND; - break; - case ASCII_t: ev_type = SND_SEQ_EVENT_CHANPRESS; - break; - case ASCII_a: ev_type = SND_SEQ_EVENT_KEYPRESS; - break; - } - ph_debug_post("initial midi NOTE:, arg1 = %d, arg2 = %d, arg3 = %d, arg4 = %d",ev_type,chan,param,val); - - if(ev_type != 0) { - if(chan >= 0) { - ph_midibuf_add(x, ev_type, chan, param, val); - } else { - while(n_instances--) { - ph_midibuf_add(x, ev_type, n_instances, param, val); - } - } - } -} - -void handle_pd_dsp(ph *x, t_signal **sp) -{ - if(!x->n_instances){ - return; - } - - - t_int *dsp_vector, i, M; - - M = x->plugin_ins + x->plugin_outs + 2; - - dsp_vector = (t_int *) getbytes(M * sizeof(t_int)); - - dsp_vector[0] = (t_int)x; - dsp_vector[1] = (t_int)sp[0]->s_n; - - for(i = 2; i < M; i++) - dsp_vector[i] = (t_int)sp[i - 1]->s_vec; - - dsp_addv(ph_perform, M, dsp_vector); - -} - -void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv) -{ - if (!x->is_dssi) { - pd_error(x, "plugin is not a DSSI plugin, operation not supported"); - } - - char msg_type[TYPE_STRING_SIZE]; - char *debug; - char *filename; - char *filepath; - char *key; - char *value; - char *temp; - char mydir[MAXPDSTRING]; - int instance = -1; - int pathlen; - int toggle; - int fd; - int n_instances = x->n_instances; - int count; - int chan; - int maxpatches; - unsigned int i; - t_float val; - long filelength = 0; - unsigned char *raw_patch_data = NULL; - FILE *fp = NULL; - size_t filename_length, key_size, value_size; - dx7_patch_t patchbuf[DX7_BANK_SIZE]; - dx7_patch_t *firstpatch; - atom_string(argv, msg_type, TYPE_STRING_SIZE); - debug = NULL; - key = NULL; - value = NULL; - maxpatches = 128; - firstpatch = &patchbuf[0]; - val = 0; - - /*TODO: Temporary - at the moment we always load the first 32 patches to 0 */ - if(strcmp(msg_type, "configure")){ - instance = (int)atom_getfloatarg(2, argc, argv) - 1; - - if(!strcmp(msg_type, "load") && x->descriptor->configure){ - filename = argv[1].a_w.w_symbol->s_name; - pd_error(x, "loading patch: %s for instance %d", - filename, instance); - - if(!strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter") || - !strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter6")) { - - key = malloc(10 * sizeof(char)); /* holds "patchesN" */ - strcpy(key, "patches0"); - - /* TODO: duplicates code from load_plugin() */ - fd = canvas_open(x->x_canvas, filename, "", - mydir, &filename, MAXPDSTRING, 0); - - if(fd >= 0){ - filepath = mydir; - pathlen = strlen(mydir); - temp = &mydir[pathlen]; - sprintf(temp, "/%s", filename); - fp = fopen(filepath, "rb"); - } - else{ - pd_error(x, "unable to get file descriptor"); - } - - /*From dx7_voice_data by Sean Bolton */ - if(fp == NULL){ - pd_error(x, "unable to open patch file: %s", filename); - return; - } - if (fseek(fp, 0, SEEK_END) || - (filelength = ftell(fp)) == -1 || - fseek(fp, 0, SEEK_SET)) { - pd_error(x, "couldn't get length of patch file: %s", - filename); - fclose(fp); - return; - } - if (filelength == 0) { - pd_error(x, "patch file has zero length"); - fclose(fp); - return; - } else if (filelength > DX7_MAX_PATCH_SIZE) { - pd_error(x, "patch file is too large"); - fclose(fp); - return; - } - if (!(raw_patch_data = (unsigned char *)malloc(filelength))) { - pd_error(x, "couldn't allocate memory for raw patch file"); - fclose(fp); - return; - } - if (fread(raw_patch_data, 1, filelength, fp) - != (size_t)filelength) { - pd_error(x, "short read on patch file: %s", filename); - free(raw_patch_data); - fclose(fp); - return; - } - fclose(fp); - ph_debug_post("Patch file length is %ul", filelength); - - /* figure out what kind of file it is */ - filename_length = strlen(filename); - if (filename_length > 4 && - !strcmp(filename + filename_length - 4, ".dx7") && - filelength % DX7_VOICE_SIZE_PACKED == 0) { - /* It's a raw DX7 patch bank */ - ph_debug_post("Raw DX7 format patch bank passed"); - - count = filelength / DX7_VOICE_SIZE_PACKED; - count = count > maxpatches ? maxpatches : count; - - memcpy(firstpatch, raw_patch_data, count * - DX7_VOICE_SIZE_PACKED); - - } else if (filelength > 6 && - raw_patch_data[0] == 0xf0 && - raw_patch_data[1] == 0x43 && - /*This was used to fix some problem with Galaxy exports - possibly dump in worng format. It is not needed, but it did work, so in future, we may be able to support more formats not just DX7 */ - /* ((raw_patch_data[2] & 0xf0) == 0x00 || - raw_patch_data[2] == 0x7e) &&*/ - (raw_patch_data[2] & 0xf0) == 0x00 && - raw_patch_data[3] == 0x09 && - (raw_patch_data[4] == 0x10 || - raw_patch_data[4] == 0x20) && - /* 0x10 is actual, 0x20 matches typo in manual */ - raw_patch_data[5] == 0x00) { - /* It's a DX7 sys-ex 32 voice dump */ - - ph_debug_post("SYSEX header check passed"); - - - if (filelength != DX7_DUMP_SIZE_BULK || - raw_patch_data[DX7_DUMP_SIZE_BULK - 1] != 0xf7) { - pd_error(x, "badly formatted DX7 32 voice dump!"); - count = 0; - -#ifdef CHECKSUM_PATCH_FILES_ON_LOAD - } else if (dx7_bulk_dump_checksum(&raw_patch_data[6], - DX7_VOICE_SIZE_PACKED * 32) != - raw_patch_data[DX7_DUMP_SIZE_BULK - 2]) { - - pd_error(x, "DX7 32 voice dump with bad checksum!"); - count = 0; -#endif - - - } else { - - count = 32; - if (count > maxpatches) - count = maxpatches; - memcpy(firstpatch, raw_patch_data + 6, count * DX7_VOICE_SIZE_PACKED); - - } - } else { - - /* unsuccessful load */ - pd_error(x, "unknown patch bank file format!"); - count = 0; - - } - - free(raw_patch_data); - - if(count == 32) - value = encode_7in6((uint8_t *)&patchbuf[0].data[0], - count * DX7_VOICE_SIZE_PACKED); - - } - else if(!strcmp(x->descriptor->LADSPA_Plugin->Label, - "FluidSynth-DSSI")){ - key = malloc(6 * sizeof(char)); - strcpy(key, "load"); - value = filename; - } - else{ - pd_error(x, "%s patches are not supported", - x->descriptor->LADSPA_Plugin->Label); - } - } - - if(!strcmp(msg_type, "dir") && x->descriptor->configure){ - pathlen = strlen(argv[1].a_w.w_symbol->s_name) + 2; - x->project_dir = malloc((pathlen) * sizeof(char)); - atom_string(&argv[1], x->project_dir, pathlen); - pd_error(x, "project directory for instance %d has been set to: %s", instance, x->project_dir); - key = DSSI_PROJECT_DIRECTORY_KEY; - value = x->project_dir; - } else if (!strcmp(msg_type, "dir")) { - pd_error(x, "%s: %s %s: operation not supported", - CLASS_NAME_STR, - msg_type, - argv[1].a_w.w_symbol->s_name); - } - - if(!strcmp(msg_type, "show") || !strcmp(msg_type, "hide")){ - instance = (int)atom_getfloatarg(1, argc, argv) - 1; - if(!strcmp(msg_type, "show")) - toggle = 1; - else - toggle = 0; - - if(instance == -1){ - while(n_instances--) - ph_show(x, n_instances, toggle); - } - else - ph_show(x, instance, toggle); - } - - if(!strcmp(msg_type, "remap")) { - /* remap channel to instance */ - for(i = 0; i < x->n_instances && i < 128; i++){ - chan = (int)atom_getfloatarg(1 + i, argc, argv); - pd_error(x, "remapped MIDI channel %d to %d", 1+i, chan); - x->channel_map[i+1] = chan; - } - } - - } - - /*Use this to send arbitrary configure message to plugin */ - else if(!strcmp(msg_type, "configure")){ - key = - (char *)malloc(key_size = (strlen(argv[1].a_w.w_symbol->s_name) + 2) * sizeof(char)); - atom_string(&argv[1], key, key_size); - if(argc >= 3){ - if (argv[2].a_type == A_FLOAT){ - val = atom_getfloatarg(2, argc, argv); - value = (char *)malloc(TYPE_STRING_SIZE * - sizeof(char)); - sprintf(value, "%.2f", val); - } - else if(argv[2].a_type == A_SYMBOL){ - value = - (char *)malloc(value_size = - (strlen(argv[2].a_w.w_symbol->s_name) + 2) * - sizeof(char)); - atom_string(&argv[2], value, value_size); - } - - } - - if(argc == 4 && argv[3].a_type == A_FLOAT) - instance = atom_getfloatarg(3, argc, argv) - 1; - else if (n_instances) - instance = -1; - } - - if(key != NULL && value != NULL){ - - if(instance == -1){ - while(n_instances--){ - debug = ph_send_configure(x, key, value, n_instances); - ph_configure_buffer(x, key, value, n_instances); - } - } - /*TODO: Put some error checking in here to make sure instance is valid*/ - /* FIX: this is all a big hack (putting UI stuff in the host). Either - * hexter needs to expose these settings somehow (e.g. as configure - * key-value pairs), or we need a [hexter_ui] external/patch that - * mirrors the functionality of hexter_gtk */ - else{ - if(!strcmp(key, "pitch_bend_range")){ - x->instances[instance].perf_buffer[3] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "portamento_time")) { - x->instances[instance].perf_buffer[5] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "mod_wheel_sensitivity")) { - x->instances[instance].perf_buffer[9] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "mod_wheel_assign")) { - x->instances[instance].perf_buffer[10] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "foot_sensitivity")) { - x->instances[instance].perf_buffer[11] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "foot_assign")) { - x->instances[instance].perf_buffer[12] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "pressure_sensitivity")) { - x->instances[instance].perf_buffer[13] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "pressure_assign")) { - x->instances[instance].perf_buffer[14] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "breath_sensitivity")) { - x->instances[instance].perf_buffer[15] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else if (!strcmp(key, "breath_assign")) { - x->instances[instance].perf_buffer[16] = atoi(value); - char *p = encode_7in6(x->instances[instance].perf_buffer, - DX7_PERFORMANCE_SIZE); - debug = ph_send_configure(x, "performance", p, instance); - } else { - debug = ph_send_configure(x, key, value, instance); - } - ph_configure_buffer(x, key, value, instance); - } - } - ph_debug_post("The plugin returned %s", debug); - -} - -void handle_pd_control (ph *x, t_symbol* ctrl_name, t_float ctrl_value, - t_float instance) -/* Change the value of a named control port of the plug-in */ -{ - unsigned param = 0; - int i = instance - 1; - unsigned int n = x->n_instances; - - if (i > (int)x->n_instances || i < -1){ - pd_error(x, "control: invalid instance number %d", i); - return; - } - - ph_debug_post("Received LADSPA control data for instance %d", i); - - if (ctrl_name->s_name == NULL || strlen (ctrl_name->s_name) == 0) { - pd_error(x, "control messages must have a name and a value"); - return; - } - param = ph_get_param_num(x, ctrl_name->s_name); - if (param) { - if(i >= 0) { - ph_set_control_input_by_index (x, param - 1, ctrl_value, i); - } else if (i == -1) { - while(n--) { - ph_set_control_input_by_index (x, param - 1, ctrl_value, n); - } - } - } else if (i >= 0) { - ph_set_control_input_by_name (x, ctrl_name->s_name, - ctrl_value, i); - } else if (i == -1) { - while(n--) { - ph_set_control_input_by_name (x, ctrl_name->s_name, ctrl_value, n); - } - } -} - -void handle_pd_info (ph *x) -{ - unsigned int i, - ctrl_portno, - audio_portno; - t_atom argv[7]; - - ctrl_portno = audio_portno = 0; - - if (x->descriptor == NULL) - return; - - for(i = 0; i < x->descriptor->LADSPA_Plugin->PortCount; i++){ - memcpy(&argv[0], &x->port_info[i].type, - sizeof(t_atom)); - memcpy(&argv[1], &x->port_info[i].data_type, - sizeof(t_atom)); - memcpy(&argv[3], &x->port_info[i].name, - sizeof(t_atom)); - memcpy(&argv[4], &x->port_info[i].lower_bound, - sizeof(t_atom)); - memcpy(&argv[5], &x->port_info[i].upper_bound, - sizeof(t_atom)); - memcpy(&argv[6], &x->port_info[i].p_default, - sizeof(t_atom)); - argv[2].a_type = A_FLOAT; - if(!strcmp(argv[1].a_w.w_symbol->s_name, "control")) - argv[2].a_w.w_float = (t_float)++ctrl_portno; - - else if(!strcmp(argv[1].a_w.w_symbol->s_name, "audio")) - argv[2].a_w.w_float = (t_float)++audio_portno; - - outlet_anything (x->message_out, gensym ("port"), 7, argv); - } -} - -void handle_pd_reset(ph *x, t_float i) -{ - unsigned int n; - const LADSPA_Descriptor *ladspa; - - ladspa = x->descriptor->LADSPA_Plugin; - - for(n = 0; n < x->n_instances; n++) { - if ((int)i == -1 || n == (int)i) { - if (ladspa->deactivate && ladspa->activate){ - ladspa->deactivate(x->instance_handles[n]); - ladspa->activate(x->instance_handles[n]); - } - } - } -} - -void handle_pd_listplugins (ph *x) -{ - void* user_data[1]; - user_data[0] = x; - LADSPAPluginSearch(ph_ladspa_describe,(void*)user_data); -} - -void handle_pd_osc(ph *x, t_symbol *s, int argc, t_atom *argv) -{ - - unsigned int i; - const char *method; - char path[OSC_ADDR_MAX]; - ph_instance *instance; - - instance = NULL; - - atom_string(argv, path, TYPE_STRING_SIZE); - - if (strncmp(path, "/dssi/", 6)){ - handle_osc_debug(path); - } - - for (i = 0; i < x->n_instances; i++) { - instance = &x->instances[i]; - if (!strncmp(path + 6, instance->osc_url_path, - strlen(instance->osc_url_path))) { - break; - } - } - - if(instance == NULL) { - pd_error(x, "instance not found"); - return; - } - - if (!instance->osc_url_path){ - handle_osc_debug(path); - } - - method = path + 6 + strlen(instance->osc_url_path); - - if (*method != '/' || *(method + 1) == 0){ - handle_osc_debug(path); - } - - method++; - - switch(argc) { - case 2: - - if (!strcmp(method, "configure") && - argv[1].a_type == A_SYMBOL && - argv[2].a_type == A_SYMBOL) { - handle_osc_configure(x, &argv[1], i); - } else if (!strcmp(method, "control") && - argv[1].a_type == A_FLOAT && - argv[2].a_type == A_FLOAT) { - handle_osc_control(x, argv, i); - } else if (!strcmp(method, "program") && - argv[1].a_type == A_FLOAT && - argv[2].a_type == A_FLOAT) { - handle_osc_program(x, argv, i); - } - break; - - case 1: - if (!strcmp(method, "midi")) { - handle_osc_midi(x, argv, i); - } else if (!strcmp(method, "update") && - argv[1].a_type == A_SYMBOL) { - handle_osc_update(x, argv, i); - } - break; - case 0: - if (!strcmp(method, "exiting")) { - handle_osc_exiting(x, argv, i); - } - break; - default: - handle_osc_debug(path); - break; - } -} diff --git a/pluginhost~/src/handlers_pd.h b/pluginhost~/src/handlers_pd.h deleted file mode 100644 index ec934da..0000000 --- a/pluginhost~/src/handlers_pd.h +++ /dev/null @@ -1,43 +0,0 @@ -/* pluginhost~ - A plugin host for Pd - * - * Copyright (C) 2006 Jamie Bullock and others - * - * This file incorporates code from the following sources: - * - * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - * - * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. - * - * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 - * - * liblo (CPL license): Copyright (C) 2004 Steve Harris - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "m_pd.h" -#include "ph_common.h" - -void handle_pd_bang(ph *x); -void handle_pd_info(ph *x); -void handle_pd_listplugins(ph *x); -void handle_pd_dsp(ph *x, t_signal **sp); -void handle_pd_reset(ph *x, t_float i); -void handle_pd_list(ph *x, t_symbol *s, int argc, t_atom *argv); -void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv); -void handle_pd_control (ph *x, t_symbol* ctrl_name, t_float ctrl_value, - t_float instance); -void handle_pd_plug(ph *x, t_symbol *s, int argc, t_atom *argv); -void handle_pd_osc(ph *x, t_symbol *s, int argc, t_atom *argv); diff --git a/pluginhost~/src/jload.c b/pluginhost~/src/jload.c deleted file mode 100644 index 1672b91..0000000 --- a/pluginhost~/src/jload.c +++ /dev/null @@ -1,214 +0,0 @@ -/* load.c - - Free software by Richard W.E. Furse. Do with as you will. No - warranty. */ - -/* patched by Jarno Seppänen, jams@cs.tut.fi, for plugin~ */ - -/* patched by Jamie Bullock, jamie@postlude.co.uk, for dssi~ */ - -/*****************************************************************************/ - -#include -#include -#include -#include - -/*****************************************************************************/ - -#include "ladspa.h" -#include "jutils.h" - -/*****************************************************************************/ - -/* This function provides a wrapping of dlopen(). When the filename is - not an absolute path (i.e. does not begin with / character), this - routine will search the LADSPA_PATH for the file. */ -static void * -dlopenLADSPA(const char * pcFilename, int iFlag) { - - char * pcBuffer; - const char * pcEnd; - const char * pcLADSPAPath; - const char * pcStart; - int iEndsInSO; - int iNeedSlash; - size_t iFilenameLength; - void * pvResult; - char *pluginPath; - - - iFilenameLength = strlen(pcFilename); - pvResult = NULL; - - /* First we just try calling dlopen(). This works if the user knows - about dlopen() and has placed the file on the LD_LIBRARY path or - has used an absolute directory. */ - pvResult = dlopen(pcFilename, iFlag); - if (pvResult != NULL) - return pvResult; - - /* If the filename is not absolute then we wish to check along the - LADSPA_PATH path to see if we can find the file there. */ - if (pcFilename[0] != '/') { - - pcLADSPAPath = NULL; - - if(getenv("LADSPA_PATH") && getenv("DSSI_PATH")){ - pluginPath = malloc(sizeof(char) * - (strlen(getenv("LADSPA_PATH")) + 1) + - sizeof(char) * strlen(getenv("DSSI_PATH"))); - sprintf(pluginPath, "%s:%s", - getenv("LADSPA_PATH"), getenv("DSSI_PATH")); - pcLADSPAPath = pluginPath; - free(pluginPath); - } - if (pcLADSPAPath == NULL) { - fprintf(stderr, "Warning: no LADSPA_PATH and DSSI_PATH, assuming /usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi\n"); - pcLADSPAPath = - "/usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi"; - } - - if (pcLADSPAPath) { - - pcStart = pcLADSPAPath; - while (*pcStart != '\0') { - pcEnd = pcStart; - while (*pcEnd != ':' && *pcEnd != '\0') - pcEnd++; - - pcBuffer = malloc(iFilenameLength + 2 + (pcEnd - pcStart)); - if (pcEnd > pcStart) - strncpy(pcBuffer, pcStart, pcEnd - pcStart); - iNeedSlash = 0; - if (pcEnd > pcStart) - if (*(pcEnd - 1) != '/') { - iNeedSlash = 1; - pcBuffer[pcEnd - pcStart] = '/'; - } - strcpy(pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename); - - pvResult = dlopen(pcBuffer, iFlag); - - free (pcBuffer); - if (pvResult != NULL){ - return pvResult; - } - - pcStart = pcEnd; - if (*pcStart == ':') - pcStart++; - } - } else { - fputs ("warning: You haven't specified the LADSPA_PATH environment variable and didn't specify an absolute path to the plug-in.\n" - "Please set the LADSPA_PATH variable to point to your LADSPA plug-in directories (eg. \"export LADSPA_PATH=/usr/local/lib/ladspa\").\n", stderr); - } - } - - /* As a last ditch effort, check if filename does not end with - ".so". In this case, add this suffix and recurse. */ - iEndsInSO = 0; - if (iFilenameLength > 3) - iEndsInSO = (strcmp(pcFilename + iFilenameLength - 3, ".so") == 0); - if (!iEndsInSO) { - pcBuffer = malloc(iFilenameLength + 4); - strcpy(pcBuffer, pcFilename); - strcat(pcBuffer, ".so"); - pvResult = dlopenLADSPA(pcBuffer, iFlag); - } - - if (pvResult != NULL) - return pvResult; - - /* If nothing has worked, then at least we can make sure we set the - correct error message - and this should correspond to a call to - dlopen() with the actual filename requested. The dlopen() manual - page does not specify whether the first or last error message - will be kept when multiple calls are made to dlopen(). We've - covered the former case - now we can handle the latter by calling - dlopen() again here. */ - return dlopen(pcFilename, iFlag); -} - -/*****************************************************************************/ - -void * -loadLADSPAPluginLibrary(const char * pcPluginFilename) { - - void * pvPluginHandle; - - pvPluginHandle = dlopenLADSPA(pcPluginFilename, RTLD_NOW); - if (!pvPluginHandle) { - fprintf(stderr, - "Failed to load plugin \"%s\": %s\n", - pcPluginFilename, - dlerror()); -#if 0 - exit(1); -#else - return NULL; -#endif - } - - return pvPluginHandle; -} - -/*****************************************************************************/ - -void -unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary) { - dlclose(pvLADSPAPluginLibrary); -} - -/*****************************************************************************/ - -const LADSPA_Descriptor * -findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary, - const char * pcPluginLibraryFilename, - const char * pcPluginLabel) { - - const LADSPA_Descriptor * psDescriptor; - LADSPA_Descriptor_Function pfDescriptorFunction; - unsigned long lPluginIndex; - - dlerror(); - pfDescriptorFunction - = (LADSPA_Descriptor_Function)dlsym(pvLADSPAPluginLibrary, - "ladspa_descriptor"); - if (!pfDescriptorFunction) { - const char * pcError = dlerror(); - if (pcError) - fprintf(stderr, - "Unable to find ladspa_descriptor() function in plugin " - "library file \"%s\": %s.\n" - "Are you sure this is a LADSPA plugin file?\n", - pcPluginLibraryFilename, - pcError); -#if 0 - exit(1); -#else - return NULL; -#endif - } - - for (lPluginIndex = 0;; lPluginIndex++) { - psDescriptor = pfDescriptorFunction(lPluginIndex); - if (psDescriptor == NULL) { - fprintf(stderr, - "Unable to find label \"%s\" in plugin library file \"%s\".\n", - pcPluginLabel, - pcPluginLibraryFilename); -#if 0 - exit(1); -#else - return NULL; -#endif - } - if (strcmp(psDescriptor->Label, pcPluginLabel) == 0) - return psDescriptor; - } -} - -/*****************************************************************************/ - -/* EOF */ diff --git a/pluginhost~/src/jsearch.c b/pluginhost~/src/jsearch.c deleted file mode 100644 index 5d69b1b..0000000 --- a/pluginhost~/src/jsearch.c +++ /dev/null @@ -1,156 +0,0 @@ -/* search.c - - Free software by Richard W.E. Furse. Do with as you will. No - warranty. */ - -/* patched by Jarno Seppänen, jams@cs.tut.fi, for plugin~ */ - -/* patched by Jamie Bullock, jamie@postlude.co.uk, for dssi~ */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -/*****************************************************************************/ - -#include "dssi.h" -#include "jutils.h" - -/*****************************************************************************/ - -/* Search just the one directory. */ - static void -LADSPADirectoryPluginSearch (const char * pcDirectory, - LADSPAPluginSearchCallbackFunction fCallbackFunction, - void* user_data) -{ - char * pcFilename; - DIR * psDirectory; - DSSI_Descriptor_Function fDescriptorFunction; - long lDirLength; - long iNeedSlash; - struct dirent * psDirectoryEntry; - void * pvPluginHandle; - bool is_DSSI = false; - - lDirLength = strlen(pcDirectory); - if (!lDirLength) - return; - if (pcDirectory[lDirLength - 1] == '/') - iNeedSlash = 0; - else - iNeedSlash = 1; - - psDirectory = opendir(pcDirectory); - if (!psDirectory) - return; - - while (1) { - - psDirectoryEntry = readdir(psDirectory); - if (!psDirectoryEntry) { - closedir(psDirectory); - return; - } - - pcFilename = malloc(lDirLength - + strlen(psDirectoryEntry->d_name) - + 1 + iNeedSlash); - strcpy(pcFilename, pcDirectory); - if (iNeedSlash) - strcat(pcFilename, "/"); - strcat(pcFilename, psDirectoryEntry->d_name); - - pvPluginHandle = dlopen(pcFilename, RTLD_LAZY); - if (pvPluginHandle) { - /* This is a file and the file is a shared library! */ - - dlerror(); - if((fDescriptorFunction = - (DSSI_Descriptor_Function)dlsym(pvPluginHandle, - "ladspa_descriptor"))) { - is_DSSI = false; - } else if ((fDescriptorFunction = - (DSSI_Descriptor_Function)dlsym(pvPluginHandle, - "dssi_descriptor"))) { - is_DSSI = true; - } - - if (dlerror() == NULL && fDescriptorFunction) { - /* We've successfully found a ladspa_descriptor function. Pass - it to the callback function. */ - fCallbackFunction(pcFilename, - pvPluginHandle, - fDescriptorFunction, - user_data, - is_DSSI); - dlclose (pvPluginHandle); - } - else { - /* It was a library, but not a LADSPA one. Unload it. */ - dlclose(pcFilename); - } - } - } -} - -/*****************************************************************************/ - - void -LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction, - void* user_data) -{ - - char * pcBuffer; - const char * pcEnd; - const char * pcLADSPAPath; - char *pluginPath; - const char * pcStart; - - - pcLADSPAPath = NULL; - - if(getenv("LADSPA_PATH") && getenv("DSSI_PATH")){ - pluginPath = malloc(sizeof(char) * - (strlen(getenv("LADSPA_PATH")) + 1) + - sizeof(char) * strlen(getenv("DSSI_PATH"))); - sprintf(pluginPath, "%s:%s", - getenv("LADSPA_PATH"), getenv("DSSI_PATH")); - pcLADSPAPath = pluginPath; - free(pluginPath); - } - if (pcLADSPAPath == NULL) { - fprintf(stderr, "Warning: no LADSPA_PATH and DSSI_PATH, assuming /usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi\n"); - pcLADSPAPath = - "/usr/lib/ladspa:/usr/local/lib/ladspa:/usr/lib/dssi:/usr/local/lib/dssi"; - } - - pcStart = pcLADSPAPath; - while (*pcStart != '\0') { - pcEnd = pcStart; - while (*pcEnd != ':' && *pcEnd != '\0') - pcEnd++; - - pcBuffer = malloc(1 + pcEnd - pcStart); - if (pcEnd > pcStart) - strncpy(pcBuffer, pcStart, pcEnd - pcStart); - pcBuffer[pcEnd - pcStart] = '\0'; - - LADSPADirectoryPluginSearch(pcBuffer, fCallbackFunction, user_data); - - pcStart = pcEnd; - if (*pcStart == ':') - pcStart++; - } -} - - -/*****************************************************************************/ - -/* EOF */ diff --git a/pluginhost~/src/jutils.h b/pluginhost~/src/jutils.h deleted file mode 100644 index fdf718f..0000000 --- a/pluginhost~/src/jutils.h +++ /dev/null @@ -1,69 +0,0 @@ -/* utils.h - - Free software by Richard W.E. Furse. Do with as you will. No - warranty. */ - -/* patched by Jarno Seppänen, jams@cs.tut.fi, for plugin~ */ - -/* patched by Jamie Bullock, jamie@postlude.co.uk, for dssi~ */ - -#ifndef LADSPA_SDK_LOAD_PLUGIN_LIB -#define LADSPA_SDK_LOAD_PLUGIN_LIB - -/*****************************************************************************/ - -#include "dssi.h" - -/*****************************************************************************/ - -/* Functions in load.c: */ - -/* This function call takes a plugin library filename, searches for - the library along the LADSPA_PATH, loads it with dlopen() and - returns a plugin handle for use with findPluginDescriptor() or - unloadLADSPAPluginLibrary(). Errors are handled by writing a - message to stderr and calling exit(1). It is alright (although - inefficient) to call this more than once for the same file. */ -void * loadLADSPAPluginLibrary(const char * pcPluginFilename); - -/* This function unloads a LADSPA plugin library. */ -void unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary); - -/* This function locates a LADSPA plugin within a plugin library - loaded with loadLADSPAPluginLibrary(). Errors are handled by - writing a message to stderr and calling exit(1). Note that the - plugin library filename is only included to help provide - informative error messages. */ -const LADSPA_Descriptor * -findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary, - const char * pcPluginLibraryFilename, - const char * pcPluginLabel); - -/*****************************************************************************/ - -/* Functions in search.c: */ - -/* Callback function for use with LADSPAPluginSearch(). The callback - function passes the filename (full path), a plugin handle (dlopen() - style) and a LADSPA_DescriptorFunction (from which - LADSPA_Descriptors can be acquired). */ -typedef void LADSPAPluginSearchCallbackFunction -(const char * pcFullFilename, - void * pvPluginHandle, - DSSI_Descriptor_Function fDescriptorFunction, - void* user_data, - int is_DSSI); - -/* Search through the $(LADSPA_PATH) (or a default path) for any - LADSPA plugin libraries. Each plugin library is tested using - dlopen() and dlsym(,"ladspa_descriptor"). After loading each - library, the callback function is called to process it. This - function leaves items passed to the callback function open. */ -void LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction, - void* user_data); - -/*****************************************************************************/ - -#endif - -/* EOF */ diff --git a/pluginhost~/src/ph_common.c b/pluginhost~/src/ph_common.c deleted file mode 100644 index 2915b15..0000000 --- a/pluginhost~/src/ph_common.c +++ /dev/null @@ -1,1117 +0,0 @@ -/* pluginhost~ - A plugin host for Pd - * - * Copyright (C) 2006 Jamie Bullock and others - * - * This file incorporates code from the following sources: - * - * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - * - * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. - * - * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 - * - * liblo (CPL license): Copyright (C) 2004 Steve Harris - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include /* for exit() */ -#include /* for fork() */ -#include /* for kill() */ -#include /* for readdir() */ -#include /* for dlsym() */ -#include - -#include "dssi.h" - -#include "jutils.h" -#include "ph_common.h" - -#define DEBUG_STRING_SIZE 8192 - -/*From dx7_voice_data.c */ -uint8_t dx7_init_performance[DX7_PERFORMANCE_SIZE] = { 0, 0, 0, 2, 0, 0, 0, 0, - 0, 15, 1, 0, 4, 15, 2, 15, - 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static LADSPA_Data ph_get_port_default(ph *x, int port) -{ - LADSPA_Descriptor *plugin = (LADSPA_Descriptor *)x->descriptor->LADSPA_Plugin; - LADSPA_PortRangeHint hint = plugin->PortRangeHints[port]; - float lower = hint.LowerBound * - (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? x->sr : 1.0f); - float upper = hint.UpperBound * - (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? x->sr : 1.0f); - - if (!LADSPA_IS_HINT_HAS_DEFAULT(hint.HintDescriptor)) { - if (!LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) || - !LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) { - /* No hint, its not bounded, wild guess */ - return 0.0f; - } - - if (lower <= 0.0f && upper >= 0.0f) { - /* It spans 0.0, 0.0 is often a good guess */ - return 0.0f; - } - - /* No clues, return minimum */ - return lower; - } - - /* Try all the easy ones */ - - if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor)) { - return 0.0f; - } else if (LADSPA_IS_HINT_DEFAULT_1(hint.HintDescriptor)) { - return 1.0f; - } else if (LADSPA_IS_HINT_DEFAULT_100(hint.HintDescriptor)) { - return 100.0f; - } else if (LADSPA_IS_HINT_DEFAULT_440(hint.HintDescriptor)) { - return 440.0f; - } - - /* All the others require some bounds */ - - if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) { - if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor)) { - return lower; - } - } - if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) { - if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor)) { - return upper; - } - if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) { - if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) { - return lower * 0.75f + upper * 0.25f; - } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) { - return lower * 0.5f + upper * 0.5f; - } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) { - return lower * 0.25f + upper * 0.75f; - } - } - } - - /* fallback */ - return 0.0f; -} - - - -static void ph_set_port_info(ph *x) -{ - t_int i; - - for (i = 0; i < (t_int)x->descriptor->LADSPA_Plugin->PortCount; i++) { - - x->port_info[i].type.a_type = A_SYMBOL; - x->port_info[i].data_type.a_type = A_SYMBOL; - x->port_info[i].name.a_type = A_SYMBOL; - x->port_info[i].upper_bound.a_type = A_FLOAT; - x->port_info[i].lower_bound.a_type = A_FLOAT; - x->port_info[i].p_default.a_type = A_FLOAT; - - LADSPA_PortDescriptor pod = - x->descriptor->LADSPA_Plugin->PortDescriptors[i]; - ph_debug_post("Port %d: %s", i, x->descriptor->LADSPA_Plugin->PortNames[i]); - - if (LADSPA_IS_PORT_AUDIO(pod)) { - x->port_info[i].data_type.a_w.w_symbol = - gensym("audio"); - if (LADSPA_IS_PORT_INPUT(pod)){ - x->port_info[i].type.a_w.w_symbol = - gensym("in"); - ++x->plugin_ins; - } - else if (LADSPA_IS_PORT_OUTPUT(pod)){ - x->port_info[i].type.a_w.w_symbol = - gensym("out"); - ++x->plugin_outs; - } - } - else if (LADSPA_IS_PORT_CONTROL(pod)) { - x->port_info[i].data_type.a_w.w_symbol = - gensym("control"); - if (LADSPA_IS_PORT_INPUT(pod)){ - x->port_info[i].type.a_w.w_symbol = - gensym("in"); - ++x->plugin_control_ins; - } - else if (LADSPA_IS_PORT_OUTPUT(pod)){ - ++x->plugin_control_outs; - x->port_info[i].type.a_w.w_symbol = - gensym("out"); - } - } - if (LADSPA_IS_HINT_BOUNDED_BELOW( - x->descriptor->LADSPA_Plugin->PortRangeHints[i].HintDescriptor)) - x->port_info[i].lower_bound.a_w.w_float = - x->descriptor->LADSPA_Plugin-> - PortRangeHints[i].LowerBound; - else - x->port_info[i].lower_bound.a_w.w_float = 0; - - if (LADSPA_IS_HINT_BOUNDED_ABOVE( - x->descriptor->LADSPA_Plugin->PortRangeHints[i].HintDescriptor)) - x->port_info[i].upper_bound.a_w.w_float = - x->descriptor->LADSPA_Plugin-> - PortRangeHints[i].UpperBound; - else - x->port_info[i].lower_bound.a_w.w_float = 1; - - x->port_info[i].p_default.a_w.w_float = (float) - ph_get_port_default(x, i); - - x->port_info[i].name.a_w.w_symbol = - gensym ((char *) - x->descriptor->LADSPA_Plugin->PortNames[i]); - } - ph_debug_post("%d inputs, %d outputs, %d control inputs, %d control outs", x->plugin_ins, x->plugin_outs, x->plugin_control_ins, x->plugin_control_outs); - -} - -static void ph_assign_ports(ph *x) -{ - unsigned int i; - - ph_debug_post("%d instances", x->n_instances); - - - x->plugin_ins *= x->n_instances; - x->plugin_outs *= x->n_instances; - x->plugin_control_ins *= x->n_instances; - x->plugin_control_outs *= x->n_instances; - - ph_debug_post("%d plugin outs", x->plugin_outs); - - - x->plugin_input_buffers = - (float **)malloc(x->plugin_ins * sizeof(float *)); - x->plugin_output_buffers = - (float **)malloc(x->plugin_outs * sizeof(float *)); - x->plugin_control_input = - (float *)calloc(x->plugin_control_ins, sizeof(float)); - x->plugin_control_output = - (float *)calloc(x->plugin_control_outs, sizeof(float)); - for(i = 0; i < x->plugin_ins; i++) - x->plugin_input_buffers[i] = - (float *)calloc(x->blksize, sizeof(float)); - for(i = 0; i < x->plugin_outs; i++) - x->plugin_output_buffers[i] = - (float *)calloc(x->blksize, sizeof(float)); - x->instance_event_buffers = - (snd_seq_event_t **)malloc(x->n_instances * sizeof(snd_seq_event_t *)); - - x->instance_handles = (LADSPA_Handle *)malloc(x->n_instances * - sizeof(LADSPA_Handle)); - x->instance_event_counts = (unsigned long *)malloc(x->n_instances * - sizeof(unsigned long)); - - for(i = 0; i < x->n_instances; i++){ - x->instance_event_buffers[i] = (snd_seq_event_t *)malloc(EVENT_BUFSIZE * - sizeof(snd_seq_event_t)); - - x->instances[i].plugin_port_ctlin_numbers = - (int *)malloc(x->descriptor->LADSPA_Plugin->PortCount * - sizeof(int)); - } - - x->plugin_ctlin_port_numbers = - (unsigned long *)malloc(sizeof(unsigned long) * x->plugin_control_ins); - - ph_debug_post("Buffers assigned!"); - - -} - -static void ph_init_instance(ph *x, unsigned int i) -{ - - x->instances[i].plugin_pgm_count = 0; - x->instances[i].ui_needs_pgm_update = 0; - x->instances[i].ui_osc_control_path = NULL; - x->instances[i].ui_osc_configure_path = NULL; - x->instances[i].ui_osc_program_path = NULL; - x->instances[i].ui_osc_show_path = NULL; - x->instances[i].ui_osc_hide_path = NULL; - x->instances[i].ui_osc_quit_path = NULL; - x->instances[i].osc_url_path = NULL; - x->instances[i].current_bank = 0; - x->instances[i].current_pgm = 0; - x->instances[i].pending_pgm_change = -1; - x->instances[i].pending_bank_lsb = -1; - x->instances[i].pending_bank_msb = -1; - x->instances[i].ui_hidden = 1; - x->instances[i].ui_show = 0; - memcpy(x->instances[i].perf_buffer, &dx7_init_performance, DX7_PERFORMANCE_SIZE); - - //x->instances[i].plugin_port_ctlin_numbers = NULL; - x->instances[i].plugin_pgms = NULL; - - ph_debug_post("Instance %d initialized!", i); - -} - -static void ph_connect_ports(ph *x, unsigned int i) -{ - - unsigned int n; - - for(n = 0; n < x->descriptor->LADSPA_Plugin->PortCount; n++){ - ph_debug_post("PortCount: %d of %d", n, - x->descriptor->LADSPA_Plugin->PortCount); - - LADSPA_PortDescriptor pod = - x->descriptor->LADSPA_Plugin->PortDescriptors[n]; - - x->instances[i].plugin_port_ctlin_numbers[n] = -1; - - if (LADSPA_IS_PORT_AUDIO(pod)) { - if (LADSPA_IS_PORT_INPUT(pod)) { - x->descriptor->LADSPA_Plugin->connect_port - (x->instance_handles[i], n, - x->plugin_input_buffers[x->ports_in++]); - } - else if (LADSPA_IS_PORT_OUTPUT(pod)) { - x->descriptor->LADSPA_Plugin->connect_port - (x->instance_handles[i], n, - x->plugin_output_buffers[x->ports_out++]); - ph_debug_post("Audio Input port %d connected", x->ports_in); - ph_debug_post("Audio Output port %d connected", x->ports_out); - - } - } - else if (LADSPA_IS_PORT_CONTROL(pod)) { - if (LADSPA_IS_PORT_INPUT(pod)) { - x->plugin_ctlin_port_numbers[x->ports_control_in] = (unsigned long) i; - x->instances[i].plugin_port_ctlin_numbers[n] = - x->ports_control_in; - x->plugin_control_input[x->ports_control_in] = - (t_float) ph_get_port_default(x, n); - ph_debug_post("default for port %d, control_in, %d is %.2f", n, - x->ports_control_in, - x->plugin_control_input[x->ports_control_in]); - - - x->descriptor->LADSPA_Plugin->connect_port - (x->instance_handles[i], n, - &x->plugin_control_input[x->ports_control_in++]); - - } else if (LADSPA_IS_PORT_OUTPUT(pod)) { - x->descriptor->LADSPA_Plugin->connect_port - (x->instance_handles[i], n, - &x->plugin_control_output[x->ports_control_out++]); - } - ph_debug_post("control port %d connected", x->ports_control_in); - ph_debug_post("control port %d connected", x->ports_control_out); - - } - } -} - -static void ph_activate_plugin(ph *x, unsigned int i) -{ - - if(x->descriptor->LADSPA_Plugin->activate){ - ph_debug_post("trying to activate instance: %d", i); - - x->descriptor->LADSPA_Plugin->activate(x->instance_handles[i]); - } - ph_debug_post("plugin activated!"); - -} - -static void ph_deactivate_plugin(ph *x, unsigned int instance) -{ - - if(x->descriptor->LADSPA_Plugin->deactivate) { - x->descriptor->LADSPA_Plugin->deactivate(x->instance_handles[instance]); - } - ph_debug_post("plugin deactivated!"); - -} - -static void ph_cleanup_plugin(ph *x, unsigned int instance) -{ - if (x->descriptor->LADSPA_Plugin && - x->descriptor->LADSPA_Plugin->cleanup) { - x->descriptor->LADSPA_Plugin->cleanup - (x->instance_handles[instance]); - } -} - -static void ph_get_current_pgm(ph *x, unsigned int i) -{ - t_int argc = 3; - t_atom argv[argc]; - ph_instance *instance; - unsigned int pgm; - - instance = &x->instances[i]; - pgm = instance->current_pgm; - - SETFLOAT(argv, i); - SETFLOAT(argv+1, instance->plugin_pgms[pgm].Program); - SETSYMBOL(argv+2, gensym(instance->plugin_pgms[pgm].Name)); - outlet_anything(x->message_out, gensym ("program"), argc, argv); - -} - -static void ph_init_programs(ph *x, unsigned int i) -{ - ph_instance *instance = &x->instances[i]; - ph_debug_post("Setting up program data"); - ph_query_programs(x, i); - - if (x->descriptor->select_program && instance->plugin_pgm_count > 0) { - - /* select program at index 0 */ - unsigned long bank = instance->plugin_pgms[0].Bank; - instance->pending_bank_msb = bank / 128; - instance->pending_bank_lsb = bank % 128; - instance->pending_pgm_change = instance->plugin_pgms[0].Program; - instance->ui_needs_pgm_update = 1; - } -} - -/* TODO:OSC */ -#if 0 -static void ph_load_gui(ph *x, int instance) -{ - t_int err = 0; - char *gui_path; - struct dirent *dir_entry = NULL; - char *gui_base; - size_t baselen; - DIR *dp; - char *gui_str; - - gui_base = (char *)malloc((baselen = sizeof(char) * (strlen(x->plugin_full_path) - strlen(".so"))) + 1); - - strncpy(gui_base, x->plugin_full_path, baselen); - gui_base[baselen] = '\0'; - - /* don't use strndup - GNU only */ - /* gui_base = strndup(x->plugin_full_path, baselen);*/ - ph_debug_post("gui_base: %s", gui_base); - - - gui_str = (char *)malloc(sizeof(char) * (strlen("channel 00") + 1)); - sprintf (gui_str,"channel %02d", instance); - - ph_debug_post("GUI name string, %s", gui_str); - - - if(!(dp = opendir(gui_base))){ - post("pluginhost~: unable to find GUI in %s, continuing without...", gui_base); - return; - } - else { - while((dir_entry = readdir(dp))){ - if (dir_entry->d_name[0] == '.') continue; - if (strchr(dir_entry->d_name, '_')){ - if (strstr(dir_entry->d_name, "gtk") || - strstr(dir_entry->d_name, "qt") || - strstr(dir_entry->d_name, "text")) - break; - } - } - ph_debug_post("GUI filename: %s", dir_entry->d_name); - - } - - gui_path = (char *)malloc(sizeof(char) * (strlen(gui_base) + strlen("/") + - strlen(dir_entry->d_name) + 1)); - - sprintf(gui_path, "%s/%s", gui_base, dir_entry->d_name); - - free(gui_base); - ph_debug_post("gui_path: %s", gui_path); - - - /* osc_url_base was of the form: - * osc.udp://127.0.0.1:9997/dssi - */ - osc_url = (char *)malloc - (sizeof(char) * (strlen(x->osc_url_base) + - strlen(instance->osc_url_path) + 2)); - - sprintf(osc_url, "%s/%s", x->osc_url_base, - instance->osc_url_path); - post("pluginhost~: instance %d URL: %s",instance, osc_url); - ph_debug_post("Trying to open GUI!"); - - - instance->gui_pid = fork(); - if (instance->gui_pid == 0){ - err = execlp(gui_path, gui_path, osc_url, dir_entry->d_name, - x->descriptor->LADSPA_Plugin->Label, gui_str, NULL); - perror("exec failed"); - exit(1); /* terminates the process */ - } - - ph_debug_post("errorcode = %d", err); - - - free(gui_path); - free(osc_url); - free(gui_str); - if(dp){ - - ph_debug_post("directory handle closed = %d", closedir(dp)); - - } -} -#endif - -static t_int ph_configure_buffer_free(ph *x) -{ - ph_configure_pair *curr, *prev; - prev = curr = NULL; - - for(curr = x->configure_buffer_head; curr != NULL; curr = curr->next){ - if(prev != NULL) - free(prev); - free(curr->key); - free(curr->value); - prev = curr; - } - free(curr); - - return 0; -} - -static void ph_search_plugin_callback ( - const char* full_filename, - void* plugin_handle, - DSSI_Descriptor_Function descriptor_function, - void* user_data, - int is_dssi) -{ - DSSI_Descriptor* descriptor = NULL; - unsigned plug_index = 0; - - char** out_lib_name = (char**)(((void**)user_data)[0]); - char* name = (char*)(((void**)user_data)[1]); - - /* Stop searching when a first matching plugin is found */ - if (*out_lib_name == NULL) - { - ph_debug_post("pluginhost~: searching plugin \"%s\"...", full_filename); - - for(plug_index = 0;(is_dssi ? - (descriptor = - (DSSI_Descriptor *)descriptor_function(plug_index)) : - ((DSSI_Descriptor *)(descriptor = - ladspa_to_dssi((LADSPA_Descriptor *) - descriptor_function(plug_index)))->LADSPA_Plugin)) - != NULL; plug_index++){ - ph_debug_post("pluginhost~: label \"%s\"", descriptor->LADSPA_Plugin->Label); - - if (strcasecmp (name, descriptor->LADSPA_Plugin->Label) - == 0) - { - *out_lib_name = strdup (full_filename); - ph_debug_post("pluginhost~: found plugin \"%s\" in library \"%s\"", - name, full_filename); - - /* if(!is_dssi){ - free((DSSI_Descriptor *)descriptor); - descriptor = NULL; - }*/ - break; - } - /* if (descriptor != NULL){ - free((DSSI_Descriptor *)descriptor); - descriptor = NULL; - }*/ - } - } -} - -static const char* plugin_tilde_search_plugin_by_label (ph *x, - const char *name) -{ - char* lib_name = NULL; - void* user_data[2]; - - user_data[0] = (void*)(&lib_name); - user_data[1] = (void*)name; - ph_debug_post("search plugin by label: '%s'\n", name); - - - lib_name = NULL; - LADSPAPluginSearch (ph_search_plugin_callback, - (void*)user_data); - - /* The callback (allocates and) writes lib_name, if it finds the plugin */ - return lib_name; - -} - -static void osc_setup(ph *x, unsigned int i) -{ - ph_instance *instance = &x->instances[i]; - - if(i == 0){ - x->osc_port = OSC_PORT; - } - instance->osc_url_path = malloc(sizeof(char) * - (strlen(x->plugin_basename) + - strlen(x->descriptor->LADSPA_Plugin->Label) + - //strlen("chan00") + 3)); - 6 + 3)); - sprintf(instance->osc_url_path, "%s/%s/chan%02d", x->plugin_basename, - x->descriptor->LADSPA_Plugin->Label, i); - ph_debug_post("OSC Path is: %s", instance->osc_url_path); - -} - -/* ==================================== */ - -void ph_debug_post(const char *fmt, ...) -{ -#if DEBUG == 1 - unsigned int currpos; - char newfmt[DEBUG_STRING_SIZE]; - char result[DEBUG_STRING_SIZE]; - size_t fmt_length; - va_list args; - - fmt_length = strlen(fmt); - - sprintf(newfmt, "%s: ", PH_NAME); - strncat(newfmt, fmt, fmt_length); - currpos = strlen(PH_NAME) + 2 + fmt_length; - newfmt[currpos] = '\0'; - - va_start(args, fmt); - vsprintf(result, newfmt, args); - va_end(args); - - post(result); -#endif -} - -void ph_quit_plugin(ph *x) -{ - - unsigned int i; - t_atom argv[2]; - t_int argc; - ph_instance *instance; - - argc = 2; - - for(i = 0; i < x->n_instances; i++) { - instance = &x->instances[i]; - if(x->is_dssi){ - argc = 2; - if(instance->ui_osc_quit_path != NULL) { - SETSYMBOL(argv, gensym(instance->ui_osc_quit_path)); - SETSYMBOL(argv+1, gensym("")); - ph_instance_send_osc(x->message_out, instance, argc, argv); - } - } - ph_deactivate_plugin(x, i); - ph_cleanup_plugin(x, i); - } -} - -void ph_query_programs(ph *x, unsigned int i) -{ - unsigned int n; - ph_instance *instance = &x->instances[i]; - ph_debug_post("querying programs"); - - /* free old lot */ - if (instance->plugin_pgms != NULL) { - for (n = 0; n < instance->plugin_pgm_count; n++) { - free((void *)instance->plugin_pgms[n].Name); - } - free(instance->plugin_pgms); - instance->plugin_pgms = NULL; - instance->plugin_pgm_count = 0; - } - - instance->pending_bank_lsb = -1; - instance->pending_bank_msb = -1; - instance->pending_pgm_change = -1; - - if (x->descriptor->get_program && - x->descriptor->select_program) { - - /* Count the plugins first */ - for (n = 0; x->descriptor-> - get_program(x->instance_handles[i], n); ++n); - - if (n > 0) { - instance->plugin_pgm_count = n; - instance->plugin_pgms = malloc(n * sizeof(DSSI_Program_Descriptor)); - while (n > 0) { - const DSSI_Program_Descriptor *descriptor; - --n; - descriptor = x->descriptor->get_program( - x->instance_handles[i], n); - instance->plugin_pgms[n].Bank = descriptor->Bank; - instance->plugin_pgms[n].Program = descriptor->Program; - instance->plugin_pgms[n].Name = strdup(descriptor->Name); - ph_debug_post("program %d is MIDI bank %lu program %lu," - " named '%s'",i, - instance->plugin_pgms[n].Bank, - instance->plugin_pgms[n].Program, - instance->plugin_pgms[n].Name); - } - } else { - assert(instance->plugin_pgm_count == 0); - } - } -} - -void ph_program_change(ph *x, unsigned int i) -{ - /* jack-dssi-host queues program changes by using pending program change variables. In the audio callback, if a program change is received via MIDI it over writes the pending value (if any) set by the GUI. If unset, or processed the value will default back to -1. The following call to select_program is then made. I don't think it eventually needs to be done this way - i.e. do we need 'pending'? */ - ph_instance *instance; - t_int argc = 3; - t_atom argv[argc]; - - instance = &x->instances[i]; - - ph_debug_post("executing program change"); - - if (instance->pending_pgm_change >= 0){ - if (instance->pending_bank_lsb >= 0) { - if (instance->pending_bank_msb >= 0) { - instance->current_bank = - instance->pending_bank_lsb + 128 * instance->pending_bank_msb; - } else { - instance->current_bank = instance->pending_bank_lsb + - 128 * (instance->current_bank / 128); - } - } else if (instance->pending_bank_msb >= 0) { - instance->current_bank = - (instance->current_bank % 128) + 128 * instance->pending_bank_msb; - } - - instance->current_pgm = instance->pending_pgm_change; - - if (x->descriptor->select_program) { - x->descriptor->select_program(x->instance_handles[i], - instance->current_bank, instance->current_pgm); - } - if (instance->ui_needs_pgm_update){ - ph_debug_post("Updating GUI program"); - - /* TODO - this is a hack to make text ui work*/ - if(x->is_dssi){ - // FIX: need to check this because if we don't have a UI, - // update didn't get called - if (false) { - SETSYMBOL(argv, gensym(instance->ui_osc_program_path)); - SETFLOAT(argv+1, instance->current_bank); - SETFLOAT(argv+2, instance->current_pgm); - ph_instance_send_osc(x->message_out, instance, argc, argv); - } - } - - } - instance->ui_needs_pgm_update = 0; - instance->pending_pgm_change = -1; - instance->pending_bank_msb = -1; - instance->pending_bank_lsb = -1; - } - ph_get_current_pgm(x, i); -} - -char *ph_send_configure(ph *x, const char *key, const char *value, - unsigned int i) -{ - - char *debug; - - debug = x->descriptor->configure(x->instance_handles[i], key, value); - /* TODO:OSC */ - /* if(instance->ui_target != NULL && x->is_dssi) { - lo_send(instance->ui_target, - instance->ui_osc_configure_path, - "ss", key, value); - } - */ - ph_query_programs(x, i); - - return debug; -} - -void ph_instance_send_osc(t_outlet *outlet, ph_instance *instance, - t_int argc, t_atom *argv) -{ - - outlet_anything(outlet, gensym("connect"), UI_TARGET_ELEMS, - instance->ui_target); - outlet_anything(outlet, gensym("send"), argc, argv); - outlet_anything(outlet, gensym("disconnect"), 0, NULL); - -} - -void *ph_load_plugin(ph *x, t_int argc, t_atom *argv) -{ - char *plugin_basename = NULL, - *plugin_full_path = NULL, - *tmpstr, - *plugin_label, - plugin_dir[MAXPDSTRING]; - - ph_debug_post("argc = %d", argc); - - unsigned int i; - int stop; - int fd; - size_t pathlen; - - stop = 0; - - if (!argc){ - pd_error(x, "no arguments given, please supply a path"); - return x; - } - - char *argstr = strdup(argv[0].a_w.w_symbol->s_name); - - if(strstr(argstr, ":") != NULL){ - tmpstr = strtok(argstr, ":"); - plugin_full_path = strdup(tmpstr); - plugin_label = strtok(NULL, ":"); - // first part of the string is empty, i.e. ':mystring' - if (plugin_label == NULL) { - x->plugin_label = plugin_full_path; - plugin_full_path = NULL; - } else { - x->plugin_label = strdup(plugin_label); - } - } else { - x->plugin_label = strdup(argstr); - tmpstr = (char *)plugin_tilde_search_plugin_by_label(x, x->plugin_label); - if(tmpstr) { - plugin_full_path = strdup(tmpstr); - } - } - - free(argstr); - ph_debug_post("plugin path = %s", plugin_full_path); - ph_debug_post("plugin name = %s", x->plugin_label); - - if(plugin_full_path == NULL){ - pd_error(x, "can't get path to plugin"); - return x; - } - - x->plugin_full_path = (char *)plugin_full_path; - - /* search for it in the 'canvas' path, which - * includes the Pd search dirs and any 'extra' paths set with - * [declare] */ - fd = canvas_open(x->x_canvas, plugin_full_path, "", - plugin_dir, &plugin_basename, MAXPDSTRING, 0); - - if (fd >= 0) { - ph_debug_post("plugin directory is %s, filename is %s", - plugin_dir, plugin_basename); - - x->plugin_basename = strdup(plugin_basename); - pathlen = strlen(plugin_dir); - tmpstr = &plugin_dir[pathlen]; - sprintf(tmpstr, "/%s", plugin_basename); - tmpstr = plugin_dir; - x->plugin_handle = loadLADSPAPluginLibrary(tmpstr); - } else { - /* try to load as is: this will work if plugin_full_path is an - * absolute path, or the name of a library that is in DSSI_PATH - * or LADSPA_PATH environment variables */ - x->plugin_handle = loadLADSPAPluginLibrary(plugin_full_path); - } - - if (x->plugin_handle == NULL) { - error("pluginhost~: can't find plugin in Pd paths, " - "try using [declare] to specify the path."); - return x; - } - - tmpstr = strdup(plugin_full_path); - /* Don't bother working out the plugin name if we used canvas_open() - * to get the path */ - if(plugin_basename == NULL){ - if(!strstr(tmpstr, ".so")){ - pd_error(x, "invalid plugin path, must end in .so"); - return x; - } - plugin_basename = strtok((char *)tmpstr, "/"); - while(strstr(plugin_basename, ".so") == NULL) { - plugin_basename = strtok(NULL, "/"); - } - x->plugin_basename = strdup(plugin_basename); - ph_debug_post("plugin basename = %s", x->plugin_basename); - } - free(tmpstr); - if((x->desc_func = (DSSI_Descriptor_Function)dlsym(x->plugin_handle, - "dssi_descriptor"))){ - x->is_dssi = true; - x->descriptor = (DSSI_Descriptor *)x->desc_func(0); - } - else if((x->desc_func = - (DSSI_Descriptor_Function)dlsym(x->plugin_handle, - "ladspa_descriptor"))){ - x->is_dssi = false; - x->descriptor = ladspa_to_dssi((LADSPA_Descriptor *)x->desc_func(0)); - } - - if(argc >= 2) { - x->n_instances = (t_int)argv[1].a_w.w_float; - } else { - x->n_instances = 1; - } - - ph_debug_post("n_instances = %d", x->n_instances); - - x->instances = (ph_instance *)malloc(sizeof(ph_instance) * - x->n_instances); - - if(!x->descriptor){ - pd_error(x, "error: couldn't get plugin descriptor"); - return x; - } - - ph_debug_post("%s loaded successfully!", - x->descriptor->LADSPA_Plugin->Label); - - x->port_info = (ph_port_info *)malloc - (x->descriptor->LADSPA_Plugin->PortCount * - sizeof(ph_port_info)); - - ph_set_port_info(x); - ph_assign_ports(x); - - for(i = 0; i < x->n_instances; i++){ - x->instance_handles[i] = - x->descriptor->LADSPA_Plugin-> - instantiate(x->descriptor->LADSPA_Plugin, x->sr); - if (!x->instance_handles[i]){ - pd_error(x, "instantiation of instance %d failed", i); - stop = 1; - break; - } - } - - if(!stop){ - for(i = 0;i < x->n_instances; i++) - ph_init_instance(x, i); - for(i = 0;i < x->n_instances; i++) - ph_connect_ports(x, i); - for(i = 0;i < x->n_instances; i++) - ph_activate_plugin(x, i); - - if(x->is_dssi){ - for(i = 0;i < x->n_instances; i++) - osc_setup(x, i); -#if LOADGUI - for(i = 0;i < x->n_instances; i++) - ph_load_gui(x, i); -#endif - - for(i = 0;i < x->n_instances; i++) - ph_init_programs(x, i); - - for(i = 0; i < x->n_instances && i < 128; i++){ - x->channel_map[i] = i; - } - } - } - - x->message_out = outlet_new (&x->x_obj, gensym("control")); - - if(x->plugin_outs){ - x->outlets = (t_outlet **)getbytes(x->plugin_outs * sizeof(t_outlet *)); - for(i = 0;i < x->plugin_outs; i++) - x->outlets[i] = outlet_new(&x->x_obj, &s_signal); - } - else { - pd_error(x, "plugin has no outputs"); - } - if(x->plugin_ins){ - x->inlets = (t_inlet **)getbytes(x->plugin_ins * sizeof(t_inlet *)); - for(i = 0;i < x->plugin_ins; i++) { - x->inlets[i] = inlet_new(&x->x_obj, &x->x_obj.ob_pd, - &s_signal, &s_signal); - } - } - else { - pd_error(x, "plugin has no inputs"); - } - - x->dsp = true; - post("%s: %d instances of %s, ready.", PH_NAME, x->n_instances, - x->plugin_label); - - return (void *)x; -} - -void ph_init_plugin(ph *x) -{ - - x->port_info = NULL; - x->descriptor = NULL; - x->instance_event_counts = NULL; - x->instances = NULL; - x->instance_handles = NULL; - x->osc_url_base = NULL; - x->configure_buffer_head = NULL; - x->project_dir = NULL; - x->outlets = NULL; - x->inlets = NULL; - x->message_out = NULL; - x->plugin_handle = NULL; - x->plugin_full_path = NULL; - x->plugin_label = NULL; - x->plugin_basename = NULL; - x->plugin_control_input = NULL; - x->plugin_control_output = NULL; - x->plugin_input_buffers = NULL; - x->plugin_output_buffers = NULL; - x->plugin_ctlin_port_numbers = NULL; - x->plugin_ins = 0; - x->plugin_outs = 0; - x->plugin_control_ins = 0; - x->plugin_control_outs = 0; - x->is_dssi = 0; - x->n_instances = 0; - x->dsp = 0; - x->dsp_loop = 0; - x->ports_in = 0; - x->ports_out = 0; - x->ports_control_in = 0; - x->ports_control_out = 0; - x->buf_write_index = 0; - x->buf_read_index = 0; - -} - -void ph_free_plugin(ph *x) -{ - unsigned int i; - unsigned int n; - - if(x->plugin_label != NULL) { - free((char *)x->plugin_label); - } - - if(x->plugin_handle == NULL) { - return; - } - - free((LADSPA_Handle)x->instance_handles); - free(x->plugin_ctlin_port_numbers); - free((t_float *)x->plugin_input_buffers); - free(x->instance_event_counts); - free(x->plugin_control_input); - free(x->plugin_control_output); - - i = x->n_instances; - - while(i--){ - ph_instance *instance = &x->instances[i]; - - /* TODO:OSC */ - /* - if(instance->gui_pid){ - ph_debug_post("Killing GUI process PID = %d", instance->gui_pid); - - kill(instance->gui_pid, SIGINT); - } */ - if (instance->plugin_pgms) { - for (n = 0; n < instance->plugin_pgm_count; n++) { - free((void *)instance->plugin_pgms[n].Name); - } - free(instance->plugin_pgms); - instance->plugin_pgms = NULL; - instance->plugin_pgm_count = 0; - } - free(x->instance_event_buffers[i]); - if(x->is_dssi){ - free(instance->ui_osc_control_path); - free(instance->ui_osc_configure_path); - free(instance->ui_osc_program_path); - free(instance->ui_osc_show_path); - free(instance->ui_osc_hide_path); - free(instance->ui_osc_quit_path); - free(instance->osc_url_path); - } - free(instance->plugin_port_ctlin_numbers); - if(x->plugin_outs) { - free(x->plugin_output_buffers[i]); - } - } - if(x->is_dssi) { - if(x->project_dir != NULL) { - free(x->project_dir); - } - free(x->osc_url_base); - ph_configure_buffer_free(x); - } - free((snd_seq_event_t *)x->instance_event_buffers); - free(x->instances); - free((t_float *)x->plugin_output_buffers); - - if(x->plugin_ins){ - for(n = 0; n < x->plugin_ins; n++) { - inlet_free((t_inlet *)x->inlets[n]); - } - freebytes(x->inlets, x->plugin_ins * sizeof(t_inlet *)); - } - - if(x->plugin_outs){ - for(n = 0; n < x->plugin_outs; n++) { - outlet_free((t_outlet *)x->outlets[n]); - } - freebytes(x->outlets, x->plugin_outs * sizeof(t_outlet *)); - } - if(x->message_out) { - outlet_free(x->message_out); - } - if(x->plugin_basename) { - free(x->plugin_basename); - } - if(x->port_info) { - free(x->port_info); - } -} - -DSSI_Descriptor *ladspa_to_dssi(LADSPA_Descriptor *ladspaDesc) -{ - DSSI_Descriptor *dssiDesc; - dssiDesc = (DSSI_Descriptor *)calloc(1, sizeof(DSSI_Descriptor)); - ((DSSI_Descriptor *)dssiDesc)->DSSI_API_Version = 1; - ((DSSI_Descriptor *)dssiDesc)->LADSPA_Plugin = - (LADSPA_Descriptor *)ladspaDesc; - return (DSSI_Descriptor *)dssiDesc; -} diff --git a/pluginhost~/src/ph_common.h b/pluginhost~/src/ph_common.h deleted file mode 100644 index a3d57a9..0000000 --- a/pluginhost~/src/ph_common.h +++ /dev/null @@ -1,171 +0,0 @@ -/* pluginhost~ - A plugin host for Pd - * - * Copyright (C) 2006 Jamie Bullock and others - * - * This file incorporates code from the following sources: - * - * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - * - * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. - * - * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 - * - * liblo (CPL license): Copyright (C) 2004 Steve Harris - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include - -#include "m_pd.h" -#include "dssi.h" - -#define PH_NAME "pluginhost~" -#define PH_VERSION 0.997 -#define EVENT_BUFSIZE 1024 -#define OSC_PORT 9998 -#define UI_TARGET_ELEMS 2 - -/*From hexter_types.h by Sean Bolton */ -#define DX7_PERFORMANCE_SIZE 64 - -#define MIN(a,b) ((a)<(b)?(a):(b)) - -#ifndef HEADER_PH_COMMON - -typedef struct _ph_instance { - - unsigned int plugin_pgm_count; - bool ui_needs_pgm_update; - char *ui_osc_control_path; - char *ui_osc_configure_path; - char *ui_osc_program_path; - char *ui_osc_show_path; - char *ui_osc_hide_path; - char *ui_osc_quit_path; - char *osc_url_path; - long current_bank; - long current_pgm; - int pending_pgm_change; - int pending_bank_lsb; - int pending_bank_msb; - int ui_hidden; - int ui_show; - t_atom ui_target[UI_TARGET_ELEMS]; /* host, port */ - uint8_t perf_buffer[DX7_PERFORMANCE_SIZE]; - - - int *plugin_port_ctlin_numbers; /*not sure if this should go here?*/ - DSSI_Program_Descriptor *plugin_pgms; - -} ph_instance; - -typedef struct ph_configure_pair { - - struct ph_configure_pair *next; - unsigned int instance; - char *value; - char *key; - -} ph_configure_pair; - -typedef struct _port_info { - - t_atom lower_bound; - t_atom upper_bound; - t_atom data_type; - t_atom p_default; - t_atom type; - t_atom name; - -} ph_port_info; - -typedef struct _ph { - - t_object x_obj; /* gah, this has to be first element in the struct, WTF? */ - - int sr; - int blksize; - int time_ref; - int ports_in; - int ports_out; - int ports_control_in; - int ports_control_out; - int buf_write_index; - int buf_read_index; - - bool is_dssi; - bool dsp; - bool dsp_loop; - - char *plugin_basename; - char *plugin_label; - char *plugin_full_path; - char *project_dir; - void *plugin_handle; - char *osc_url_base; - - float f; - float sr_inv; - float **plugin_input_buffers; - float **plugin_output_buffers; - float *plugin_control_input; - float *plugin_control_output; - - unsigned int osc_port; - unsigned int n_instances; - unsigned int plugin_ins; - unsigned int plugin_outs; - unsigned int plugin_control_ins; - unsigned int plugin_control_outs; - unsigned long *instance_event_counts; - unsigned long *plugin_ctlin_port_numbers; - unsigned char channel_map[128]; - - DSSI_Descriptor_Function desc_func; - DSSI_Descriptor *descriptor; - LADSPA_Handle *instance_handles; - - t_inlet **inlets; - t_outlet **outlets; - t_outlet *message_out; - t_canvas *x_canvas; - - ph_port_info *port_info; - ph_instance *instances; - ph_configure_pair *configure_buffer_head; - - snd_seq_event_t **instance_event_buffers; - snd_seq_event_t midi_event_buf[EVENT_BUFSIZE]; - -} ph; - -void ph_debug_post(const char *fmt, ...); -void ph_quit_plugin(ph *x); -void ph_init_plugin(ph *x); -void ph_free_plugin(ph *x); -void ph_query_programs(ph *x, unsigned int i); -void ph_program_change(ph *x, unsigned int i); -void ph_instance_send_osc(t_outlet *outlet, ph_instance *instance, - t_int argc, t_atom *argv); -void *ph_load_plugin(ph *x, t_int argc, t_atom *argv); -char *ph_send_configure(ph *x, const char *key, const char *value, - unsigned int i); -DSSI_Descriptor *ladspa_to_dssi(LADSPA_Descriptor *ladspaDesc); - -#define HEADER_PH_COMMON -#endif - diff --git a/pluginhost~/src/pluginhost~.c b/pluginhost~/src/pluginhost~.c deleted file mode 100644 index 76faff1..0000000 --- a/pluginhost~/src/pluginhost~.c +++ /dev/null @@ -1,95 +0,0 @@ -/* pluginhost~ - A plugin host for Pd - * - * Copyright (C) 2006 Jamie Bullock and others - * - * This file incorporates code from the following sources: - * - * jack-dssi-host (BSD-style license): Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. - * - * Hexter (GPL license): Copyright (C) 2004 Sean Bolton and others. - * - * plugin~ (GPL license): Copyright (C) 2000 Jarno Seppänen, remIXed 2005 - * - * liblo (CPL license): Copyright (C) 2004 Steve Harris - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#include -#include - -#include "ph_common.h" -#include "handlers_pd.h" - -static t_class *ph_class; - -static void *ph_new(t_symbol *s, t_int argc, t_atom *argv) -{ - - ph *x = (ph *)pd_new(ph_class); - post("\n========================================\n" - "%s(): version %.2f\n========================================\n", - PH_NAME, PH_VERSION); - - ph_init_plugin(x); - - x->sr = (int)sys_getsr(); - x->sr_inv = 1 / (t_float)x->sr; - x->dsp = 0; - x->time_ref = (t_int)clock_getlogicaltime; - x->blksize = sys_getblksize(); - x->x_canvas = canvas_getcurrent(); - - return ph_load_plugin(x, argc, argv); - -} - -static void ph_free(ph *x) -{ - ph_quit_plugin(x); - ph_free_plugin(x); -} - -static void ph_sigchld_handler(int sig) -{ - wait(NULL); -} - -void pluginhost_tilde_setup(void) -{ - - ph_class = class_new(gensym("pluginhost~"), (t_newmethod)ph_new, - (t_method)ph_free, sizeof(ph), 0, A_GIMME, 0); - class_addlist(ph_class, handle_pd_list); - class_addbang(ph_class, handle_pd_bang); - class_addmethod(ph_class, (t_method)handle_pd_dsp, gensym("dsp"), 0); - class_addmethod (ph_class,(t_method)handle_pd_info, gensym ("info"), 0); - class_addmethod(ph_class, (t_method)handle_pd_dssi, - gensym("dssi"), A_GIMME, 0); - class_addmethod (ph_class,(t_method)handle_pd_control, - gensym ("control"),A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod (ph_class,(t_method)handle_pd_listplugins, - gensym ("listplugins"),0); - class_addmethod (ph_class,(t_method)handle_pd_reset, - gensym ("reset"), A_DEFFLOAT, 0); - class_addmethod (ph_class, (t_method)handle_pd_osc, - gensym("osc"), A_GIMME, 0); - class_sethelpsymbol(ph_class, gensym("pluginhost~-help")); - - CLASS_MAINSIGNALIN(ph_class, ph, f); - signal(SIGCHLD, ph_sigchld_handler); -} - -- cgit v1.2.1