aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dssi/doc/help-dssi.pd141
-rw-r--r--dssi/doc/output~.pd69
-rw-r--r--dssi/include/seq_event.h452
-rw-r--r--dssi/src/dssi~.c1740
-rw-r--r--dssi/src/dssi~.h57
5 files changed, 2459 insertions, 0 deletions
diff --git a/dssi/doc/help-dssi.pd b/dssi/doc/help-dssi.pd
new file mode 100644
index 0000000..821779f
--- /dev/null
+++ b/dssi/doc/help-dssi.pd
@@ -0,0 +1,141 @@
+#N canvas 65 172 1411 654 10;
+#X obj 1177 528 catch~ mix;
+#X text 602 15 dssi~ - a DSSI host for Pure Data ---------------------------------
+;
+#X obj 7 63 cnv 15 1400 300 empty empty dssi~_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 obj 345 295 dssi~ /usr/local/lib/dssi/hexter.so 2;
+#X msg 1214 136 show 2;
+#X obj 598 274 list;
+#X msg 1130 137 hide;
+#X msg 1171 136 show;
+#X msg 915 162 configure GLOBAL:polyphony 10;
+#X msg 72 256 n \$1;
+#X obj 110 256 r chan;
+#X msg 731 140 load TX-SYX/TFI2.SYX 2;
+#X msg 732 160 load TX-SYX/TFI1.SYX 1;
+#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 344 322 throw~ mix;
+#X obj 119 148 hsl 128 15 60 80 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 9200 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 6350 1;
+#X obj 598 254 r dssi1-config;
+#X obj 730 185 s dssi1-config;
+#X obj 916 184 s dssi1-config;
+#X obj 1129 186 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 msg 914 140 configure polyphony 10 2;
+#X obj 5 371 cnv 15 400 300 empty empty dssi~_instance_2 20 12 0 14
+-225280 -66577 0;
+#X obj 38 540 dssi~ /usr/lib/dssi/less_trivial_synth.so;
+#X msg 319 495 show;
+#X obj 321 519 list;
+#X msg 357 496 hide;
+#X obj 39 512 list prepend n 1;
+#X msg 40 435 80;
+#X obj 37 561 throw~ mix;
+#X obj 39 492 pack f f;
+#X msg 88 436 60;
+#X text 563 480 Usage: [dssi~ <path to plugin> <number of plugin instances>]
+;
+#X obj 474 122 loadbang;
+#X text 806 212 LAST ARGUMENT GIVES PLUGIN INSTANCE TO BE CONFIGURED
+NO LAST ARGUMENT=(ALL INSTANCES);
+#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 obj 39 461 makenote 100 1000;
+#X text 1126 98 --show/hide GUI--;
+#X obj 1175 551 dssi/output~;
+#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 connect 0 0 69 0;
+#X connect 0 0 69 1;
+#X connect 3 0 5 0;
+#X connect 4 0 3 0;
+#X connect 5 0 25 0;
+#X connect 6 0 31 0;
+#X connect 7 0 24 0;
+#X connect 8 0 4 0;
+#X connect 9 0 26 0;
+#X connect 9 1 26 0;
+#X connect 10 0 35 0;
+#X connect 11 0 9 1;
+#X connect 12 0 35 0;
+#X connect 13 0 35 0;
+#X connect 14 0 34 0;
+#X connect 15 0 19 1;
+#X connect 16 0 15 0;
+#X connect 17 0 33 0;
+#X connect 18 0 33 0;
+#X connect 19 0 9 0;
+#X connect 20 0 9 0;
+#X connect 21 0 19 0;
+#X connect 22 0 70 0;
+#X connect 23 0 70 0;
+#X connect 24 0 20 0;
+#X connect 25 0 9 0;
+#X connect 27 0 70 0;
+#X connect 28 1 70 0;
+#X connect 29 0 37 0;
+#X connect 30 0 7 0;
+#X connect 31 0 8 0;
+#X connect 32 0 11 0;
+#X connect 36 0 66 0;
+#X connect 37 0 20 1;
+#X connect 38 0 39 0;
+#X connect 39 0 25 1;
+#X connect 41 0 40 0;
+#X connect 43 0 62 0;
+#X connect 48 0 34 0;
+#X connect 50 0 56 0;
+#X connect 51 0 52 0;
+#X connect 52 0 50 1;
+#X connect 53 0 52 0;
+#X connect 54 0 50 0;
+#X connect 55 0 67 0;
+#X connect 57 0 54 0;
+#X connect 58 0 67 0;
+#X connect 60 0 6 0;
+#X connect 62 0 66 1;
+#X connect 66 0 9 0;
+#X connect 67 0 57 0;
+#X connect 67 1 57 1;
+#X connect 70 0 21 0;
+#X connect 70 1 21 1;
+#X connect 71 0 35 0;
+#X connect 72 0 35 0;
diff --git a/dssi/doc/output~.pd b/dssi/doc/output~.pd
new file mode 100644
index 0000000..4db0809
--- /dev/null
+++ b/dssi/doc/output~.pd
@@ -0,0 +1,69 @@
+#N canvas 0 0 757 675 12;
+#X obj 516 522 t b;
+#X obj 516 469 f;
+#X obj 516 547 f;
+#X msg 630 546 0;
+#X obj 516 499 moses 1;
+#X obj 630 518 t b f;
+#X obj 596 479 moses 1;
+#X obj 29 97 dbtorms;
+#X obj 85 170 inlet~;
+#X msg 278 300 \; pd dsp 1;
+#X obj 29 170 line~;
+#X obj 64 242 *~;
+#X obj 64 272 dac~;
+#X obj 29 127 pack 0 50;
+#X text 121 146 audio in;
+#X text 301 496 test if less than 1 -->;
+#X text 267 523 if true convert to bang -->;
+#X text 100 96 <-- convert from dB to linear units;
+#X floatatom 278 221 3 0 100 0 dB - -;
+#X obj 516 449 bng 15 250 50 0 empty empty mute -38 7 0 12 -262144
+-1 -1;
+#X text 118 126 <-- make a ramp to avoid clicks or zipper noise;
+#X obj 148 170 inlet~;
+#X obj 154 241 *~;
+#X text 502 399 MUTE logic:;
+#X obj 278 193 r \$0-master-lvl;
+#X obj 516 573 s \$0-master-lvl;
+#X obj 293 247 s \$0-master-out;
+#X obj 29 71 r \$0-master-out;
+#X obj 596 450 r \$0-master-out;
+#X text 60 10 Level control abstraction \, used in many of the Pd example
+patches. The level and mute controls show up on the parent \, calling
+patch.;
+#X text 229 549 previous nonzero master-lvl -->;
+#X text 301 453 recall previous;
+#X text 301 471 value of master-lvl -->;
+#X text 16 310 automatically start DSP -->;
+#X obj 85 192 hip~ 3;
+#X obj 147 192 hip~ 3;
+#X text 26 608 NOTE: This abstraction was written by Miller Puckette
+\, and is include with the PD examples as part of the 'standard' PD
+documentation. JB 23/05/05;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 25 0;
+#X connect 3 0 25 0;
+#X connect 4 0 0 0;
+#X connect 4 1 5 0;
+#X connect 5 0 3 0;
+#X connect 6 1 2 1;
+#X connect 7 0 13 0;
+#X connect 8 0 34 0;
+#X connect 10 0 22 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 13 0 10 0;
+#X connect 18 0 9 0;
+#X connect 18 0 26 0;
+#X connect 19 0 1 0;
+#X connect 21 0 35 0;
+#X connect 22 0 12 1;
+#X connect 24 0 18 0;
+#X connect 27 0 7 0;
+#X connect 28 0 1 1;
+#X connect 28 0 6 0;
+#X connect 34 0 11 1;
+#X connect 35 0 22 1;
+#X coords 0 0 1 1 65 55 1;
diff --git a/dssi/include/seq_event.h b/dssi/include/seq_event.h
new file mode 100644
index 0000000..6d59ca4
--- /dev/null
+++ b/dssi/include/seq_event.h
@@ -0,0 +1,452 @@
+/**
+ * \file include/seq_event.h
+ * \brief Application interface library for the ALSA driver
+ * \author Jaroslav Kysela <perex@suse.cz>
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \author Takashi Iwai <tiwai@suse.de>
+ * \date 1998-2001
+ *
+ * Application interface library for the ALSA driver
+ */
+/*
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ALSA_SEQ_EVENT_H
+#define __ALSA_SEQ_EVENT_H
+
+/**
+ * \defgroup SeqEvents Sequencer Event Definitions
+ * Sequencer Event Definitions
+ * \ingroup Sequencer
+ * \{
+ */
+
+/**
+ * Sequencer event data type
+ */
+typedef unsigned char snd_seq_event_type_t;
+
+/** Sequencer event type */
+enum snd_seq_event_type {
+ /** system status; event data type = #snd_seq_result_t */
+ SND_SEQ_EVENT_SYSTEM = 0,
+ /** returned result status; event data type = #snd_seq_result_t */
+ SND_SEQ_EVENT_RESULT,
+
+ /** note on and off with duration; event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_NOTE = 5,
+ /** note on; event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_NOTEON,
+ /** note off; event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_NOTEOFF,
+ /** key pressure change (aftertouch); event data type = #snd_seq_ev_note_t */
+ SND_SEQ_EVENT_KEYPRESS,
+
+ /** controller; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_CONTROLLER = 10,
+ /** program change; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_PGMCHANGE,
+ /** channel pressure; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_CHANPRESS,
+ /** pitchwheel; event data type = #snd_seq_ev_ctrl_t; data is from -8192 to 8191) */
+ SND_SEQ_EVENT_PITCHBEND,
+ /** 14 bit controller value; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_CONTROL14,
+ /** 14 bit NRPN; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_NONREGPARAM,
+ /** 14 bit RPN; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_REGPARAM,
+
+ /** SPP with LSB and MSB values; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_SONGPOS = 20,
+ /** Song Select with song ID number; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_SONGSEL,
+ /** midi time code quarter frame; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_QFRAME,
+ /** SMF Time Signature event; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_TIMESIGN,
+ /** SMF Key Signature event; event data type = #snd_seq_ev_ctrl_t */
+ SND_SEQ_EVENT_KEYSIGN,
+
+ /** MIDI Real Time Start message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_START = 30,
+ /** MIDI Real Time Continue message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_CONTINUE,
+ /** MIDI Real Time Stop message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_STOP,
+ /** Set tick queue position; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_SETPOS_TICK,
+ /** Set real-time queue position; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_SETPOS_TIME,
+ /** (SMF) Tempo event; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_TEMPO,
+ /** MIDI Real Time Clock message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_CLOCK,
+ /** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_TICK,
+ /** Queue timer skew; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_QUEUE_SKEW,
+ /** Sync position changed; event data type = #snd_seq_ev_queue_control_t */
+ SND_SEQ_EVENT_SYNC_POS,
+
+ /** Tune request; event data type = none */
+ SND_SEQ_EVENT_TUNE_REQUEST = 40,
+ /** Reset to power-on state; event data type = none */
+ SND_SEQ_EVENT_RESET,
+ /** Active sensing event; event data type = none */
+ SND_SEQ_EVENT_SENSING,
+
+ /** Echo-back event; event data type = any type */
+ SND_SEQ_EVENT_ECHO = 50,
+ /** OSS emulation raw event; event data type = any type */
+ SND_SEQ_EVENT_OSS,
+
+ /** New client has connected; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_CLIENT_START = 60,
+ /** Client has left the system; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_CLIENT_EXIT,
+ /** Client status/info has changed; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_CLIENT_CHANGE,
+ /** New port was created; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_PORT_START,
+ /** Port was deleted from system; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_PORT_EXIT,
+ /** Port status/info has changed; event data type = #snd_seq_addr_t */
+ SND_SEQ_EVENT_PORT_CHANGE,
+
+ /** Ports connected; event data type = #snd_seq_connect_t */
+ SND_SEQ_EVENT_PORT_SUBSCRIBED,
+ /** Ports disconnected; event data type = #snd_seq_connect_t */
+ SND_SEQ_EVENT_PORT_UNSUBSCRIBED,
+
+ /** Sample select; event data type = #snd_seq_ev_sample_control_t */
+ SND_SEQ_EVENT_SAMPLE = 70,
+ /** Sample cluster select; event data type = #snd_seq_ev_sample_control_t */
+ SND_SEQ_EVENT_SAMPLE_CLUSTER,
+ /** voice start */
+ SND_SEQ_EVENT_SAMPLE_START,
+ /** voice stop */
+ SND_SEQ_EVENT_SAMPLE_STOP,
+ /** playback frequency */
+ SND_SEQ_EVENT_SAMPLE_FREQ,
+ /** volume and balance */
+ SND_SEQ_EVENT_SAMPLE_VOLUME,
+ /** sample loop */
+ SND_SEQ_EVENT_SAMPLE_LOOP,
+ /** sample position */
+ SND_SEQ_EVENT_SAMPLE_POSITION,
+ /** private (hardware dependent) event */
+ SND_SEQ_EVENT_SAMPLE_PRIVATE1,
+
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR0 = 90,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR1,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR2,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR3,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR4,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR5,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR6,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR7,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR8,
+ /** user-defined event; event data type = any (fixed size) */
+ SND_SEQ_EVENT_USR9,
+
+ /** begin of instrument management */
+ SND_SEQ_EVENT_INSTR_BEGIN = 100,
+ /** end of instrument management */
+ SND_SEQ_EVENT_INSTR_END,
+ /** query instrument interface info */
+ SND_SEQ_EVENT_INSTR_INFO,
+ /** result of instrument interface info */
+ SND_SEQ_EVENT_INSTR_INFO_RESULT,
+ /** query instrument format info */
+ SND_SEQ_EVENT_INSTR_FINFO,
+ /** result of instrument format info */
+ SND_SEQ_EVENT_INSTR_FINFO_RESULT,
+ /** reset instrument instrument memory */
+ SND_SEQ_EVENT_INSTR_RESET,
+ /** get instrument interface status */
+ SND_SEQ_EVENT_INSTR_STATUS,
+ /** result of instrument interface status */
+ SND_SEQ_EVENT_INSTR_STATUS_RESULT,
+ /** put an instrument to port */
+ SND_SEQ_EVENT_INSTR_PUT,
+ /** get an instrument from port */
+ SND_SEQ_EVENT_INSTR_GET,
+ /** result of instrument query */
+ SND_SEQ_EVENT_INSTR_GET_RESULT,
+ /** free instrument(s) */
+ SND_SEQ_EVENT_INSTR_FREE,
+ /** get instrument list */
+ SND_SEQ_EVENT_INSTR_LIST,
+ /** result of instrument list */
+ SND_SEQ_EVENT_INSTR_LIST_RESULT,
+ /** set cluster parameters */
+ SND_SEQ_EVENT_INSTR_CLUSTER,
+ /** get cluster parameters */
+ SND_SEQ_EVENT_INSTR_CLUSTER_GET,
+ /** result of cluster parameters */
+ SND_SEQ_EVENT_INSTR_CLUSTER_RESULT,
+ /** instrument change */
+ SND_SEQ_EVENT_INSTR_CHANGE,
+
+ /** system exclusive data (variable length); event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_SYSEX = 130,
+ /** error event; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_BOUNCE,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR0 = 135,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR1,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR2,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR3,
+ /** reserved for user apps; event data type = #snd_seq_ev_ext_t */
+ SND_SEQ_EVENT_USR_VAR4,
+
+ /** NOP; ignored in any case */
+ SND_SEQ_EVENT_NONE = 255
+};
+
+
+/** Sequencer event address */
+typedef struct snd_seq_addr {
+ unsigned char client; /**< Client id */
+ unsigned char port; /**< Port id */
+} snd_seq_addr_t;
+
+/** Connection (subscription) between ports */
+typedef struct snd_seq_connect {
+ snd_seq_addr_t sender; /**< sender address */
+ snd_seq_addr_t dest; /**< destination address */
+} snd_seq_connect_t;
+
+
+/** Real-time data record */
+typedef struct snd_seq_real_time {
+ unsigned int tv_sec; /**< seconds */
+ unsigned int tv_nsec; /**< nanoseconds */
+} snd_seq_real_time_t;
+
+/** (MIDI) Tick-time data record */
+typedef unsigned int snd_seq_tick_time_t;
+
+/** unioned time stamp */
+typedef union snd_seq_timestamp {
+ snd_seq_tick_time_t tick; /**< tick-time */
+ struct snd_seq_real_time time; /**< real-time */
+} snd_seq_timestamp_t;
+
+
+/**
+ * Event mode flags
+ *
+ * NOTE: only 8 bits available!
+ */
+#define SND_SEQ_TIME_STAMP_TICK (0<<0) /**< timestamp in clock ticks */
+#define SND_SEQ_TIME_STAMP_REAL (1<<0) /**< timestamp in real time */
+#define SND_SEQ_TIME_STAMP_MASK (1<<0) /**< mask for timestamp bits */
+
+#define SND_SEQ_TIME_MODE_ABS (0<<1) /**< absolute timestamp */
+#define SND_SEQ_TIME_MODE_REL (1<<1) /**< relative to current time */
+#define SND_SEQ_TIME_MODE_MASK (1<<1) /**< mask for time mode bits */
+
+#define SND_SEQ_EVENT_LENGTH_FIXED (0<<2) /**< fixed event size */
+#define SND_SEQ_EVENT_LENGTH_VARIABLE (1<<2) /**< variable event size */
+#define SND_SEQ_EVENT_LENGTH_VARUSR (2<<2) /**< variable event size - user memory space */
+#define SND_SEQ_EVENT_LENGTH_MASK (3<<2) /**< mask for event length bits */
+
+#define SND_SEQ_PRIORITY_NORMAL (0<<4) /**< normal priority */
+#define SND_SEQ_PRIORITY_HIGH (1<<4) /**< event should be processed before others */
+#define SND_SEQ_PRIORITY_MASK (1<<4) /**< mask for priority bits */
+
+
+/** Note event */
+typedef struct snd_seq_ev_note {
+ unsigned char channel; /**< channel number */
+ unsigned char note; /**< note */
+ unsigned char velocity; /**< velocity */
+ unsigned char off_velocity; /**< note-off velocity; only for #SND_SEQ_EVENT_NOTE */
+ unsigned int duration; /**< duration until note-off; only for #SND_SEQ_EVENT_NOTE */
+} snd_seq_ev_note_t;
+
+/** Controller event */
+typedef struct snd_seq_ev_ctrl {
+ unsigned char channel; /**< channel number */
+ unsigned char unused[3]; /**< reserved */
+ unsigned int param; /**< control parameter */
+ signed int value; /**< control value */
+} snd_seq_ev_ctrl_t;
+
+/** generic set of bytes (12x8 bit) */
+typedef struct snd_seq_ev_raw8 {
+ unsigned char d[12]; /**< 8 bit value */
+} snd_seq_ev_raw8_t;
+
+/** generic set of integers (3x32 bit) */
+typedef struct snd_seq_ev_raw32 {
+ unsigned int d[3]; /**< 32 bit value */
+} snd_seq_ev_raw32_t;
+
+/** external stored data */
+typedef struct snd_seq_ev_ext {
+ unsigned int len; /**< length of data */
+ void *ptr; /**< pointer to data (note: can be 64-bit) */
+} __attribute__((packed)) snd_seq_ev_ext_t;
+
+/** Instrument cluster type */
+typedef unsigned int snd_seq_instr_cluster_t;
+
+/** Instrument type */
+typedef struct snd_seq_instr {
+ snd_seq_instr_cluster_t cluster; /**< cluster id */
+ unsigned int std; /**< instrument standard id; the upper byte means a private instrument (owner - client id) */
+ unsigned short bank; /**< instrument bank id */
+ unsigned short prg; /**< instrument program id */
+} snd_seq_instr_t;
+
+/** sample number */
+typedef struct snd_seq_ev_sample {
+ unsigned int std; /**< sample standard id */
+ unsigned short bank; /**< sample bank id */
+ unsigned short prg; /**< sample program id */
+} snd_seq_ev_sample_t;
+
+/** sample cluster */
+typedef struct snd_seq_ev_cluster {
+ snd_seq_instr_cluster_t cluster; /**< cluster id */
+} snd_seq_ev_cluster_t;
+
+/** sample position */
+typedef unsigned int snd_seq_position_t; /**< playback position (in samples) * 16 */
+
+/** sample stop mode */
+typedef enum snd_seq_stop_mode {
+ SND_SEQ_SAMPLE_STOP_IMMEDIATELY = 0, /**< terminate playing immediately */
+ SND_SEQ_SAMPLE_STOP_VENVELOPE = 1, /**< finish volume envelope */
+ SND_SEQ_SAMPLE_STOP_LOOP = 2 /**< terminate loop and finish wave */
+} snd_seq_stop_mode_t;
+
+/** sample frequency */
+typedef int snd_seq_frequency_t; /**< playback frequency in HZ * 16 */
+
+/** sample volume control; if any value is set to -1 == do not change */
+typedef struct snd_seq_ev_volume {
+ signed short volume; /**< range: 0-16383 */
+ signed short lr; /**< left-right balance; range: 0-16383 */
+ signed short fr; /**< front-rear balance; range: 0-16383 */
+ signed short du; /**< down-up balance; range: 0-16383 */
+} snd_seq_ev_volume_t;
+
+/** simple loop redefinition */
+typedef struct snd_seq_ev_loop {
+ unsigned int start; /**< loop start (in samples) * 16 */
+ unsigned int end; /**< loop end (in samples) * 16 */
+} snd_seq_ev_loop_t;
+
+/** Sample control events */
+typedef struct snd_seq_ev_sample_control {
+ unsigned char channel; /**< channel */
+ unsigned char unused[3]; /**< reserved */
+ union {
+ snd_seq_ev_sample_t sample; /**< sample number */
+ snd_seq_ev_cluster_t cluster; /**< cluster number */
+ snd_seq_position_t position; /**< position */
+ snd_seq_stop_mode_t stop_mode; /**< stop mode */
+ snd_seq_frequency_t frequency; /**< frequency */
+ snd_seq_ev_volume_t volume; /**< volume */
+ snd_seq_ev_loop_t loop; /**< loop control */
+ unsigned char raw8[8]; /**< raw 8-bit */
+ } param; /**< control parameters */
+} snd_seq_ev_sample_control_t;
+
+
+
+/** INSTR_BEGIN event */
+typedef struct snd_seq_ev_instr_begin {
+ int timeout; /**< zero = forever, otherwise timeout in ms */
+} snd_seq_ev_instr_begin_t;
+
+/** Result events */
+typedef struct snd_seq_result {
+ int event; /**< processed event type */
+ int result; /**< status */
+} snd_seq_result_t;
+
+/** Queue skew values */
+typedef struct snd_seq_queue_skew {
+ unsigned int value; /**< skew value */
+ unsigned int base; /**< skew base */
+} snd_seq_queue_skew_t;
+
+/** queue timer control */
+typedef struct snd_seq_ev_queue_control {
+ unsigned char queue; /**< affected queue */
+ unsigned char unused[3]; /**< reserved */
+ union {
+ signed int value; /**< affected value (e.g. tempo) */
+ snd_seq_timestamp_t time; /**< time */
+ unsigned int position; /**< sync position */
+ snd_seq_queue_skew_t skew; /**< queue skew */
+ unsigned int d32[2]; /**< any data */
+ unsigned char d8[8]; /**< any data */
+ } param; /**< data value union */
+} snd_seq_ev_queue_control_t;
+
+
+/** Sequencer event */
+typedef struct snd_seq_event {
+ snd_seq_event_type_t type; /**< event type */
+ unsigned char flags; /**< event flags */
+ unsigned char tag; /**< tag */
+
+ unsigned char queue; /**< schedule queue */
+ snd_seq_timestamp_t time; /**< schedule time */
+
+ snd_seq_addr_t source; /**< source address */
+ snd_seq_addr_t dest; /**< destination address */
+
+ union {
+ snd_seq_ev_note_t note; /**< note information */
+ snd_seq_ev_ctrl_t control; /**< MIDI control information */
+ snd_seq_ev_raw8_t raw8; /**< raw8 data */
+ snd_seq_ev_raw32_t raw32; /**< raw32 data */
+ snd_seq_ev_ext_t ext; /**< external data */
+ snd_seq_ev_queue_control_t queue; /**< queue control */
+ snd_seq_timestamp_t time; /**< timestamp */
+ snd_seq_addr_t addr; /**< address */
+ snd_seq_connect_t connect; /**< connect information */
+ snd_seq_result_t result; /**< operation result code */
+ snd_seq_ev_instr_begin_t instr_begin; /**< instrument */
+ snd_seq_ev_sample_control_t sample; /**< sample control */
+ } data; /**< event data... */
+} snd_seq_event_t;
+
+
+/** \} */
+
+#endif /* __ALSA_SEQ_EVENT_H */
+
diff --git a/dssi/src/dssi~.c b/dssi/src/dssi~.c
new file mode 100644
index 0000000..11736c3
--- /dev/null
+++ b/dssi/src/dssi~.c
@@ -0,0 +1,1740 @@
+/* dssi~ - A DSSI host for PD
+ *
+ * Copyright 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.
+ *
+ *
+ * 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.
+*/
+
+
+
+/* TODO:
+ 1. Fix memory allocation issues.
+ 2. Restore Trivial Synth compatibility, i.e. is GUI fails, don't crash. - DONE!
+ 3. Reomve alsa.h dependency - Included header file!
+ 4. Get Hexter/Fluidsynth working - DONE!
+ 5. Get LTS working (full functionality i.e Pitch Bend, Control etc.) - DONE!
+ 6. Do OSC/GUI - DONE!
+ 7. Multiple instances -DONE!
+ 8. If OSC is received from another source - update the GUI.
+ 9. Patch saving/loading. -DONE (for Hexter)!
+ 10. Make GUI close when app closes, or new plugin loaded. -DONE!
+ 11. Make ll-scope work.
+ 12. Fix note hangs. - DONE - this was due to precedence problems in the PD patch!
+ 13. Fix inability to run two instances of the dssi~ external. - DONE!
+ 14. Fix exiting handler -DONE!
+ 15. Fix GUI close when PD quit - don't leave defunct process
+ 16. Fix free() call if plugin isn't loaded successfully -DONE!
+ 17. Implement GUI show/hide. -DONE!
+ 18. Fix segfault if dssi~ recieves on MIDI channel it doesn't have an instance for -DONE!
+ 19. Fix program crash when patch load if audio running. -DONE!
+ 20. Make info logged to pd console more meaningful
+ 21. Add more error checking.
+ 22. Fix: global polyphony handling - DONE!
+ 23. Fix: config malloc bugs
+ 24. Fix: exit call instance deactivate function - DONE!
+ 25. Check DSSI spec conformity!
+ 26. FIX: Why does is incorrect patch name chown when program is changed from GUI? - DONE! - query_programs must be sent for each configure call
+ 27. FIX: Generic valgrind error - also in jack-dssi-host.
+ */
+
+
+#include "dssi~.h"
+
+
+
+static t_class *dssi_tilde_class;
+
+/*From dx7_voice_data.c by Sean Bolton */
+
+static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/*From dx7_voice.h by Sean Bolton */
+
+typedef struct _dx7_patch_t {
+ uint8_t data[128];
+} dx7_patch_t;
+
+typedef struct _dssi_instance {
+
+ long currentBank;
+ long currentProgram;
+ int pendingBankLSB;
+ int pendingBankMSB;
+ int pendingProgramChange;
+
+ int plugin_ProgramCount;
+ DSSI_Program_Descriptor *pluginPrograms;
+
+ lo_address uiTarget; /*osc stuff */
+ int ui_hidden;
+ int ui_show;
+ int uiNeedsProgramUpdate;
+ 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;
+
+ int *plugin_PortControlInNumbers; /*not sure if this should go here?*/
+
+ char *osc_url_path;
+ pid_t gui_pid;
+
+} t_dssi_instance;
+
+typedef struct _dssi_tilde {
+ t_object x_obj;
+ char *dll_path;/*abs path to plugin*/
+ void *dll_handle;
+ char *dir; /* project dircetory */
+ LADSPA_Handle *instanceHandles; /*was handle*/
+ t_dssi_instance *instances;
+ int n_instances;
+ unsigned long *instanceEventCounts;
+ snd_seq_event_t **instanceEventBuffers;
+
+snd_seq_event_t midiEventBuf[EVENT_BUFSIZE];
+/*static snd_seq_event_t **instanceEventBuffers;*/
+int bufWriteIndex, bufReadIndex;
+pthread_mutex_t midiEventBufferMutex;
+/*static pthread_mutex_t listHandlerMutex = PTHREAD_MUTEX_INITIALIZER;*/
+
+ DSSI_Descriptor_Function desc_func;
+ const DSSI_Descriptor *descriptor;
+
+ t_int ports_in, ports_out, ports_controlIn, ports_controlOut;
+ t_int plugin_ins;/* total audio input ports for plugin*/
+ t_int plugin_outs;/* total audio output ports plugin*/
+ t_int plugin_controlIns;/* total control input ports*/
+ t_int plugin_controlOuts;/* total control output ports */
+
+ unsigned long *plugin_ControlInPortNumbers; /*Array of input port numbers for the plugin */
+
+ t_float **plugin_InputBuffers, **plugin_OutputBuffers; /* arrays of arrays for buffering audio for each audio port */
+ t_float *plugin_ControlDataInput, *plugin_ControlDataOutput; /*arrays for control data for each port (1 item per 'run')*/
+ lo_server_thread osc_thread;
+ char *osc_url_base;
+ char *dll_name;
+
+ t_int time_ref; /*logical time reference */
+ t_int sr;
+ t_float sr_inv;
+ t_int blksize;
+ t_float f;
+
+ t_float **outlets;
+
+} t_dssi_tilde;
+
+static void dssi_load_gui(t_dssi_tilde *x, int instance);
+
+static int osc_message_handler(const char *path, const char *types,
+ lo_arg **argv, int argc, void *data, void *user_data);
+static LADSPA_Data get_port_default(t_dssi_tilde *x, int port);
+static void MIDIbuf(int type, int chan, int param, int val, t_dssi_tilde *x);
+
+
+
+/*static void init_MidiEventBuf(snd_seq_event_t *MidiEventBuf){
+ int i;
+ for(i = 0; i < EVENT_BUFSIZE; i++){
+ MidiEventBuf[i].*/
+
+
+/*
+ * 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;
+}
+
+
+
+
+static void dssi_load(char *dll_path, void **dll_handle){
+
+ *dll_handle = dlopen(dll_path, RTLD_NOW);
+ if (*dll_handle){
+ post("%s loaded successfully", dll_path);
+ }
+ else
+ post("Failed: %s", dlerror());
+
+}
+
+static void portInfo(t_dssi_tilde *x){
+ t_int i;
+ for (i = 0; i < (t_int)x->descriptor->LADSPA_Plugin->PortCount; i++) {
+ LADSPA_PortDescriptor pod =
+ x->descriptor->LADSPA_Plugin->PortDescriptors[i];
+#if DEBUG
+ post("Port %d: %s", i, x->descriptor->LADSPA_Plugin->PortNames[i]);
+#endif
+ if (LADSPA_IS_PORT_AUDIO(pod)) {
+ if (LADSPA_IS_PORT_INPUT(pod)) ++x->plugin_ins;
+ else if (LADSPA_IS_PORT_OUTPUT(pod)) ++x->plugin_outs;
+ }
+ else if (LADSPA_IS_PORT_CONTROL(pod)) {
+ if (LADSPA_IS_PORT_INPUT(pod)) ++x->plugin_controlIns;
+ else if (LADSPA_IS_PORT_OUTPUT(pod)) ++x->plugin_controlOuts;
+ }
+ }
+#if DEBUG
+post("%d inputs, %d outputs, %d control inputs, %d control outs", x->plugin_ins, x->plugin_outs, x->plugin_controlIns, x->plugin_controlOuts);
+#endif
+}
+
+static void dssi_assignPorts(t_dssi_tilde *x){
+ int i;
+
+#if DEBUG
+ post("%d instances", x->n_instances);
+#endif
+
+ x->plugin_ins *= x->n_instances;
+ x->plugin_outs *= x->n_instances;
+ x->plugin_controlIns *= x->n_instances;
+ x->plugin_controlOuts *= x->n_instances;
+
+#if DEBUG
+ post("%d plugin outs", x->plugin_outs);
+#endif
+
+ x->plugin_InputBuffers =
+ (float **)malloc(x->plugin_ins * sizeof(float *));
+ x->plugin_OutputBuffers =
+ (float **)malloc(x->plugin_outs * sizeof(float *));
+ x->plugin_ControlDataInput =
+ (float *)calloc(x->plugin_controlIns, sizeof(float));
+ x->plugin_ControlDataOutput =
+ (float *)calloc(x->plugin_controlOuts, sizeof(float));
+ for(i = 0; i < x->plugin_ins; i++)
+ x->plugin_InputBuffers[i] =
+ (float *)calloc(x->blksize, sizeof(float));
+ for(i = 0; i < x->plugin_outs; i++)
+ x->plugin_OutputBuffers[i] =
+ (float *)calloc(x->blksize, sizeof(float));
+ x->instanceEventBuffers =
+ (snd_seq_event_t **)malloc(x->n_instances * sizeof(snd_seq_event_t *));
+
+
+ x->instanceHandles = (LADSPA_Handle *)malloc(x->n_instances *
+ sizeof(LADSPA_Handle));
+ x->instanceEventCounts = (unsigned long *)malloc(x->n_instances *
+ sizeof(unsigned long));
+
+ for(i = 0; i < x->n_instances; i++){
+ x->instanceEventBuffers[i] = (snd_seq_event_t *)malloc(EVENT_BUFSIZE *
+ sizeof(snd_seq_event_t));
+
+ x->instances[i].plugin_PortControlInNumbers =
+ (int *)malloc(x->descriptor->LADSPA_Plugin->PortCount *
+ sizeof(int));/* hmmm... as we don't support instances of differing plugin types, we probably don't need to do this dynamically*/
+ }
+
+ x->plugin_ControlInPortNumbers =
+ (unsigned long *)malloc(sizeof(unsigned long) * x->plugin_controlIns);
+
+#if DEBUG
+ post("Buffers assigned!");
+#endif
+
+}
+
+static void dssi_init(t_dssi_tilde *x, t_int instance){
+
+ x->instances[instance].pluginPrograms = NULL;
+ x->instances[instance].currentBank = 0;
+ x->instances[instance].currentProgram = 0;
+ x->instances[instance].uiTarget = NULL;
+ x->instances[instance].ui_osc_control_path = NULL;
+ x->instances[instance].ui_osc_program_path = NULL;
+ x->instances[instance].ui_osc_show_path = NULL;
+ x->instances[instance].ui_osc_hide_path = NULL;
+ x->instances[instance].ui_osc_configure_path = NULL;
+ x->instances[instance].uiNeedsProgramUpdate = 0;
+ x->instances[instance].pendingProgramChange = -1;
+ x->instances[instance].pendingBankMSB = -1;
+ x->instances[instance].pendingBankLSB = -1;
+ x->instances[instance].ui_hidden = 1;
+ x->instances[instance].ui_show = 0;
+#if DEBUG
+ post("Instance %d initialized!", instance);
+#endif
+
+
+}
+
+static void dssi_connectPorts(t_dssi_tilde *x, t_int instance){
+
+ t_int i;
+
+ for(i = 0; i < (t_int)x->descriptor->LADSPA_Plugin->PortCount; i++){
+#if DEBUG
+ post("PortCount: %d of %d", i,
+ x->descriptor->LADSPA_Plugin->PortCount);
+#endif
+ LADSPA_PortDescriptor pod =
+ x->descriptor->LADSPA_Plugin->PortDescriptors[i];
+
+ x->instances[instance].plugin_PortControlInNumbers[i] = -1;
+
+ if (LADSPA_IS_PORT_AUDIO(pod)) {
+ if (LADSPA_IS_PORT_INPUT(pod)) {
+ x->descriptor->LADSPA_Plugin->connect_port
+ (x->instanceHandles[instance], i,
+ x->plugin_InputBuffers[x->ports_in++]);
+ }
+ else if (LADSPA_IS_PORT_OUTPUT(pod)) {
+ x->descriptor->LADSPA_Plugin->connect_port
+ (x->instanceHandles[instance], i,
+ x->plugin_OutputBuffers[x->ports_out++]);
+#if DEBUG
+ post("Outport port %d connected", x->ports_out);
+#endif
+ }
+ }
+ else if (LADSPA_IS_PORT_CONTROL(pod)) {
+ if (LADSPA_IS_PORT_INPUT(pod)) {
+ x->plugin_ControlInPortNumbers[x->ports_controlIn] = (unsigned long) i;
+ x->instances[instance].plugin_PortControlInNumbers[i] = x->ports_controlIn;
+ x->plugin_ControlDataInput[x->ports_controlIn] =
+ (t_float) get_port_default(x, i);
+#if DEBUG
+ post("default for port %d, controlIn, %d is %.2f",i,
+ x->ports_controlIn, x->plugin_ControlDataInput[x->ports_controlIn]);
+#endif
+
+ x->descriptor->LADSPA_Plugin->connect_port
+ (x->instanceHandles[instance], i,
+ &x->plugin_ControlDataInput[x->ports_controlIn++]);
+
+ } else if (LADSPA_IS_PORT_OUTPUT(pod)) {
+ x->descriptor->LADSPA_Plugin->connect_port
+ (x->instanceHandles[instance], i,
+ &x->plugin_ControlDataOutput[x->ports_controlOut++]);
+ }
+ }
+ }
+
+#if DEBUG
+post("ports connected!");
+#endif
+
+}
+
+static void dssi_activate(t_dssi_tilde *x, t_int instance){
+
+ x->descriptor->LADSPA_Plugin->activate(x->instanceHandles[instance]);
+#if DEBUG
+ post("plugin activated!");
+#endif
+}
+
+static void osc_error(int num, const char *msg, const char *where)
+{
+ post("osc error %d in path %s: %s\n",num, where, msg);
+}
+
+static void query_programs(t_dssi_tilde *x, t_int instance) {
+ int i;
+#if DEBUG
+post("querying programs");
+#endif
+ /* free old lot */
+ if (x->instances[instance].pluginPrograms) {
+ for (i = 0; i < x->instances[instance].plugin_ProgramCount; i++)
+ free((void *)x->instances[instance].pluginPrograms[i].Name);
+ x->instances[instance].pluginPrograms = NULL;
+ x->instances[instance].plugin_ProgramCount = 0;
+ }
+
+ x->instances[instance].pendingBankLSB = -1;
+ x->instances[instance].pendingBankMSB = -1;
+ x->instances[instance].pendingProgramChange = -1;
+
+ if (x->descriptor->get_program &&
+ x->descriptor->select_program) {
+
+ /* Count the plugins first */
+ for (i = 0; x->descriptor->
+ get_program(x->instanceHandles[instance], i); ++i);
+
+ if (i > 0) {
+ x->instances[instance].plugin_ProgramCount = i;
+ x->instances[instance].pluginPrograms =
+ (DSSI_Program_Descriptor *)malloc(i * sizeof(DSSI_Program_Descriptor));
+ while (i > 0) {
+ const DSSI_Program_Descriptor *descriptor;
+ --i;
+ descriptor = x->descriptor->
+ get_program(x->instanceHandles[instance], i);
+ x->instances[instance].pluginPrograms[i].Bank =
+ descriptor->Bank;
+ x->instances[instance].pluginPrograms[i].Program =
+ descriptor->Program;
+ x->instances[instance].pluginPrograms[i].Name =
+ strdup(descriptor->Name);
+#if DEBUG
+ post("program %d is MIDI bank %lu program %lu, named '%s'",i,
+ x->instances[instance].pluginPrograms[i].Bank,
+ x->instances[instance].pluginPrograms[i].Program,
+ x->instances[instance].pluginPrograms[i].Name);
+#endif
+ }
+ }
+ }
+}
+
+static LADSPA_Data get_port_default(t_dssi_tilde *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 int osc_debug_handler(const char *path, const char *types, lo_arg **argv,
+ int argc, void *data, t_dssi_tilde *x)
+{
+ int i;
+ printf("got unhandled OSC message:\npath: <%s>\n", path);
+ for (i=0; i<argc; i++) {
+ printf("arg %d '%c' ", i, types[i]);
+ lo_arg_pp(types[i], argv[i]);
+ printf("\n");
+ }
+ return 1;
+}
+
+static void dssi_ProgramChange(t_dssi_tilde *x, int instance){
+/* 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'? */
+#if DEBUG
+ post("executing program change");
+#endif
+ if (x->instances[instance].pendingProgramChange >= 0){
+ if (x->instances[instance].pendingBankLSB >= 0) {
+ if (x->instances[instance].pendingBankMSB >= 0) {
+ x->instances[instance].currentBank = x->instances[instance].pendingBankLSB + 128 * x->instances[instance].pendingBankMSB;
+ }
+ else {
+ x->instances[instance].currentBank = x->instances[instance].pendingBankLSB +
+ 128 * (x->instances[instance].currentBank / 128);
+ }
+ }
+ else if (x->instances[instance].pendingBankMSB >= 0) {
+ x->instances[instance].currentBank = (x->instances[instance].currentBank % 128) + 128 * x->instances[instance].pendingBankMSB;
+ }
+
+ x->instances[instance].currentProgram = x->instances[instance].pendingProgramChange;
+
+ if (x->descriptor->select_program) {
+ x->descriptor->select_program(x->instanceHandles[instance],
+ x->instances[instance].currentBank, x->instances[instance].currentProgram);
+ }
+ if (x->instances[instance].uiNeedsProgramUpdate){
+#if DEBUG
+ post("Updating GUI program");
+#endif
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_program_path, "ii",
+ x->instances[instance].currentBank,
+ x->instances[instance].currentProgram);
+ }
+ x->instances[instance].uiNeedsProgramUpdate = 0;
+ x->instances[instance].pendingProgramChange = -1;
+ x->instances[instance].pendingBankMSB = -1;
+ x->instances[instance].pendingBankLSB = -1;
+ }
+}
+
+static int osc_program_handler(t_dssi_tilde *x, lo_arg **argv, int instance)
+{
+ unsigned long bank = argv[0]->i;
+ unsigned long program = argv[1]->i;
+ int i;
+ int found = 0;
+
+#if DEBUG
+post("osc_program_hander active!");
+
+post("%d programs", x->instances[instance].plugin_ProgramCount);
+
+#endif
+ for (i = 0; i < x->instances[instance].plugin_ProgramCount; ++i) {
+ if (x->instances[instance].pluginPrograms[i].Bank == bank &&
+ x->instances[instance].pluginPrograms[i].Program == program) {
+ post("OSC: setting bank %u, program %u, name %s\n",
+ bank, program, x->instances[instance].pluginPrograms[i].Name);
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ printf(": OSC: UI requested unknown program: bank %d, program %u: sending to plugin anyway (plugin should ignore it)\n", (int)bank,(int)program);
+ }
+
+ x->instances[instance].pendingBankMSB = bank / 128;
+ x->instances[instance].pendingBankLSB = bank % 128;
+ x->instances[instance].pendingProgramChange = program;
+#if DEBUG
+ post("bank = %d, program = %d, BankMSB = %d BankLSB = %d", bank, program, x->instances[instance].pendingBankMSB, x->instances[instance].pendingBankLSB);
+#endif
+ dssi_ProgramChange(x, instance);
+
+ return 0;
+}
+
+
+static int osc_control_handler(t_dssi_tilde *x, lo_arg **argv, int instance)
+{
+ int port = argv[0]->i;
+ LADSPA_Data value = argv[1]->f;
+
+ x->plugin_ControlDataInput[x->instances[instance].plugin_PortControlInNumbers[port]] = value;
+#if DEBUG
+ post("OSC: port %d = %f", port, value);
+#endif
+
+ return 0;
+}
+
+static int osc_midi_handler(t_dssi_tilde *x, lo_arg **argv, t_int instance)
+{
+
+ int ev_type = 0, chan = 0;
+/* div_t divstruct; *//*division strucutre for integer division*/
+#if DEBUG
+ post("OSC: got midi request for"
+ "(%02x %02x %02x %02x)",
+ argv[0]->m[0], argv[0]->m[1], argv[0]->m[2], argv[0]->m[3]);
+#endif
+/* divstruct = div(argv[0]->m[1], 16);
+ chan = divstruct.rem + 1; */ /*Wrong! the GUI's all use channel 0 */
+ chan = instance;
+#if DEBUG
+ post("channel: %d", chan);
+#endif
+
+ if(argv[0]->m[1] <= 239){
+ if(argv[0]->m[1] >= 224)
+ ev_type = SND_SEQ_EVENT_PITCHBEND;
+ else if(argv[0]->m[1] >= 208)
+ ev_type = SND_SEQ_EVENT_CHANPRESS;
+ else if(argv[0]->m[1] >= 192)
+ ev_type = SND_SEQ_EVENT_PGMCHANGE;
+ else if(argv[0]->m[1] >= 176)
+ ev_type = SND_SEQ_EVENT_CONTROLLER;
+ else if(argv[0]->m[1] >= 160)
+ ev_type = SND_SEQ_EVENT_KEYPRESS;
+ else if(argv[0]->m[1] >= 144)
+ ev_type = SND_SEQ_EVENT_NOTEON;
+ else if(argv[0]->m[1] >= 128)
+ ev_type = SND_SEQ_EVENT_NOTEOFF;
+ }
+ if(ev_type != 0)
+ MIDIbuf(ev_type, chan, argv[0]->m[2], argv[0]->m[3], x);
+
+ return 0;
+}
+
+static int osc_configure_handler(t_dssi_tilde *x, lo_arg **argv, int instance)
+{
+ const char *key = (const char *)&argv[0]->s;
+ const char *value = (const char *)&argv[1]->s;
+ char *message;
+
+#if DEBUG
+ post("osc_configure_handler active!");
+#endif
+
+ if (x->descriptor->configure) {
+
+ if (!strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX,
+ strlen(DSSI_RESERVED_CONFIGURE_PREFIX))) {
+ fprintf(stderr, ": OSC: UI for plugin '' attempted to use reserved configure key \"%s\", ignoring\n", key);
+ return 0;
+ }
+
+ message = x->descriptor->configure(x->instanceHandles[instance], key, value);
+ if (message) {
+ printf(": on configure '%s', plugin '' returned error '%s'\n",
+ key, message);
+ free(message);
+ }
+
+ query_programs(x, instance);
+
+ }
+
+
+ return 0;
+}
+
+
+
+
+
+static int osc_exiting_handler(t_dssi_tilde *x, lo_arg **argv, int instance){
+
+#if DEBUG
+ post("exiting handler called: Freeing ui_osc");
+#endif
+ lo_address_free(x->instances[instance].uiTarget);
+ free(x->instances[instance].ui_osc_control_path);
+ free(x->instances[instance].ui_osc_configure_path);
+ free(x->instances[instance].ui_osc_hide_path);
+ free(x->instances[instance].ui_osc_program_path);
+ free(x->instances[instance].ui_osc_show_path);
+ x->instances[instance].uiTarget = NULL;
+ x->instances[instance].ui_osc_control_path = NULL;
+ x->instances[instance].ui_osc_configure_path = NULL;
+ x->instances[instance].ui_osc_hide_path = NULL;
+ x->instances[instance].ui_osc_program_path = NULL;
+ x->instances[instance].ui_osc_show_path = NULL;
+
+ x->instances[instance].ui_hidden = 1;
+
+ return 0;
+}
+
+static int osc_update_handler(t_dssi_tilde *x, lo_arg **argv, int instance)
+{
+ const char *url = (char *)&argv[0]->s;
+ const char *path;
+ t_int i;
+ char *host, *port;
+
+#if DEBUG
+ post("OSC: got update request from <%s>, instance %d", url, instance);
+#endif
+
+
+ if (x->instances[instance].uiTarget)
+ lo_address_free(x->instances[instance].uiTarget);
+ host = lo_url_get_hostname(url);
+ port = lo_url_get_port(url);
+ x->instances[instance].uiTarget = lo_address_new(host, port);
+ free(host);
+ free(port);
+
+ path = lo_url_get_path(url);
+
+ if (x->instances[instance].ui_osc_control_path)
+ free(x->instances[instance].ui_osc_control_path);
+ x->instances[instance].ui_osc_control_path =
+ (char *)malloc(strlen(path) + 10);
+ sprintf(x->instances[instance].ui_osc_control_path, "%s/control", path);
+
+ if (x->instances[instance].ui_osc_configure_path)
+ free(x->instances[instance].ui_osc_configure_path);
+ x->instances[instance].ui_osc_configure_path =
+ (char *)malloc(strlen(path) + 12);
+ sprintf(x->instances[instance].ui_osc_configure_path, "%s/configure", path);
+
+ if (x->instances[instance].ui_osc_program_path)
+ free(x->instances[instance].ui_osc_program_path);
+ x->instances[instance].ui_osc_program_path =
+ (char *)malloc(strlen(path) + 10);
+ sprintf(x->instances[instance].ui_osc_program_path, "%s/program", path);
+
+ if (x->instances[instance].ui_osc_show_path)
+ free(x->instances[instance].ui_osc_show_path);
+ x->instances[instance].ui_osc_show_path = (char *)malloc(strlen(path) + 10);
+ sprintf(x->instances[instance].ui_osc_show_path, "%s/show", path);
+
+ if (x->instances[instance].ui_osc_hide_path)
+ free(x->instances[instance].ui_osc_hide_path);
+ x->instances[instance].ui_osc_hide_path = (char *)malloc(strlen(path) + 10);
+ sprintf(x->instances[instance].ui_osc_hide_path, "%s/hide", path);
+
+ free((char *)path);
+
+ /* At this point a more substantial host might also call
+ * configure() on the UI to set any state that it had remembered
+ * for the plugin x. But we don't remember state for
+ * plugin xs (see our own configure() implementation in
+ * osc_configure_handler), and so we have nothing to send except
+ * the optional project directory. */
+
+ if (x->dir)
+ lo_send(x->instances[instance].uiTarget, x->instances[instance].ui_osc_configure_path, "ss",DSSI_PROJECT_DIRECTORY_KEY, x->dir);
+
+
+ /* Send current bank/program (-FIX- another race...) */
+ if (x->instances[instance].pendingProgramChange >= 0)
+ dssi_ProgramChange(x, instance);
+#if DEBUG
+ post("pendingProgramChange = %d", x->instances[instance].pendingProgramChange);
+#endif
+ if (x->instances[instance].pendingProgramChange < 0) {
+ unsigned long bank = x->instances[instance].currentBank;
+ unsigned long program = x->instances[instance].currentProgram;
+ x->instances[instance].uiNeedsProgramUpdate = 0;
+ if (x->instances[instance].uiTarget) {
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_program_path,
+ "ii", bank, program);
+ }
+ }
+
+ /* Send control ports */
+ for (i = 0; i < x->plugin_controlIns; i++) {
+ lo_send(x->instances[instance].uiTarget, x->instances[instance].ui_osc_control_path, "if",
+ x->plugin_ControlInPortNumbers[i], x->plugin_ControlDataInput[i]);
+#if DEBUG
+ post("Port: %d, Default value: %.2f", x->plugin_ControlInPortNumbers[i], x->plugin_ControlDataInput[i]);
+#endif
+ }
+
+/* Send 'show' */
+ if (x->instances[instance].ui_show) {
+ lo_send(x->instances[instance].uiTarget, x->instances[instance].ui_osc_show_path, "");
+ x->instances[instance].ui_hidden = 0;
+ x->instances[instance].ui_show = 0;
+ }
+
+
+
+ return 0;
+}
+
+static void dssi_osc_setup(t_dssi_tilde *x, int instance){
+
+ if(instance == 0){
+ x->osc_thread = lo_server_thread_new(NULL, osc_error);
+ char *osc_url_tmp;
+ osc_url_tmp = lo_server_thread_get_url(x->osc_thread);
+#if DEBUG
+ post("string length of osc_url_tmp:%d", strlen(osc_url_tmp));
+#endif
+ x->osc_url_base = (char *)malloc(sizeof(char)
+ * (strlen(osc_url_tmp) + strlen("dssi") + 1));
+ sprintf(x->osc_url_base, "%s%s", osc_url_tmp, "dssi");
+ free(osc_url_tmp);
+ lo_server_thread_add_method(x->osc_thread, NULL, NULL,
+ osc_message_handler, x);
+ lo_server_thread_start(x->osc_thread);
+ }
+ x->instances[instance].osc_url_path = (char *)malloc(sizeof(char) *
+ (strlen(x->dll_name) + strlen(x->descriptor->LADSPA_Plugin->Label) + strlen("chan00") + 3));
+ sprintf(x->instances[instance].osc_url_path, "%s/%s/chan%02d", x->dll_name,
+ x->descriptor->LADSPA_Plugin->Label, instance);
+#if DEBUG
+post("OSC Path is: %s", x->instances[instance].osc_url_path);
+ post("OSC thread started: %s", x->osc_url_base);
+#endif
+}
+
+static void dssi_programs(t_dssi_tilde *x, int instance){
+
+#if DEBUG
+ post("Setting up program data");
+#endif
+ query_programs(x, instance);
+ if (x->descriptor->select_program &&
+ x->instances[instance].plugin_ProgramCount > 0) {
+
+ /* select program at index 0 */
+ unsigned long bank =
+ x->instances[instance].pluginPrograms[0].Bank;
+ x->instances[instance].pendingBankMSB = bank / 128;
+ x->instances[instance].pendingBankLSB = bank % 128;
+ x->instances[instance].pendingProgramChange =
+ x->instances[instance].pluginPrograms[0].Program;
+ x->instances[instance].uiNeedsProgramUpdate = 1;
+ }
+}
+
+static void dssi_load_gui(t_dssi_tilde *x, int instance){
+ t_int err = 0;
+ char *osc_url;
+ 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->dll_path) - strlen(".so")));
+
+ strncpy(gui_base, x->dll_path, baselen);
+/* gui_base = strndup(x->dll_path, baselen);*/
+#if DEBUG
+post("gui_base: %s", gui_base);
+#endif
+
+ gui_str = (char *)malloc(sizeof(char) * (strlen("channel 00") + 1));
+ sprintf (gui_str,"channel %02d", instance);
+
+#if DEBUG
+ post("GUI name string, %s", gui_str);
+#endif
+
+ if(!(dp = opendir(gui_base))){
+ post("can't open %s, unable to find GUI", gui_base);
+ return;
+ }
+ else {
+ while((dir_entry = readdir(dp))){
+ if (dir_entry->d_name[0] == '.') continue;
+ break;
+ }
+#if DEBUG
+ post("GUI filename: %s", dir_entry->d_name);
+#endif
+
+ }
+
+ 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);
+#if DEBUG
+ post("gui_path: %s", gui_path);
+#endif
+
+ osc_url = (char *)malloc
+ (sizeof(char) * (strlen(x->osc_url_base) +
+ strlen(x->instances[instance].osc_url_path) + 2));
+
+
+
+
+
+/* char osc_url[1024];*/
+ sprintf(osc_url, "%s/%s", x->osc_url_base,
+ x->instances[instance].osc_url_path);
+ post("Instance %d OSC URL is: %s",instance, osc_url);
+#if DEBUG
+ post("Trying to open GUI!");
+#endif
+ x->instances[instance].gui_pid = fork();
+ if (x->instances[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 */
+ }
+
+#if DEBUG
+post("errorcode = %d", err);
+#endif
+
+ free(gui_path);
+ free(osc_url);
+ free(gui_str);
+ if(dp){
+
+#if DEBUG
+ post("directory handle closed = %d", closedir(dp));
+#endif
+ }
+}
+
+static void MIDIbuf(int type, int chan, int param, int val, t_dssi_tilde *x){
+
+
+ if(chan > x->n_instances - 1 || chan < 0){
+ post("Note discarded: MIDI data is destined for a channel that doesn't exist");
+ return;
+ }
+
+
+ t_int time_ref = x->time_ref;
+
+pthread_mutex_lock(&x->midiEventBufferMutex);
+
+ x->midiEventBuf[x->bufWriteIndex].time.time.tv_sec =
+ (t_int)(clock_gettimesince(time_ref) * .001);
+ x->midiEventBuf[x->bufWriteIndex].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->midiEventBuf[x->bufWriteIndex].type = type;
+ switch (type) {
+ case SND_SEQ_EVENT_NOTEON:
+ x->midiEventBuf[x->bufWriteIndex].data.note.channel = chan;
+ x->midiEventBuf[x->bufWriteIndex].data.note.note = param;
+ x->midiEventBuf[x->bufWriteIndex].data.note.velocity = val;
+ break;
+ case SND_SEQ_EVENT_NOTEOFF:
+ x->midiEventBuf[x->bufWriteIndex].data.note.channel = chan;
+ x->midiEventBuf[x->bufWriteIndex].data.note.note = param;
+ x->midiEventBuf[x->bufWriteIndex].data.note.velocity = val;
+ break;
+ case SND_SEQ_EVENT_CONTROLLER:
+ x->midiEventBuf[x->bufWriteIndex].data.control.channel = chan;
+ x->midiEventBuf[x->bufWriteIndex].data.control.param = param;
+ x->midiEventBuf[x->bufWriteIndex].data.control.value = val;
+ break;
+ case SND_SEQ_EVENT_PITCHBEND:
+ x->midiEventBuf[x->bufWriteIndex].data.control.channel = chan;
+ x->midiEventBuf[x->bufWriteIndex].data.control.param = 0;
+ x->midiEventBuf[x->bufWriteIndex].data.control.value = val;
+ break;
+ case SND_SEQ_EVENT_PGMCHANGE:
+ x->instances[chan].pendingBankMSB = (param - 1) / 128;
+ x->instances[chan].pendingBankLSB = (param - 1) % 128;
+ x->instances[chan].pendingProgramChange = val;
+ x->instances[chan].uiNeedsProgramUpdate = 1;
+#if DEBUG
+ post("pgm chabge received in buffer: MSB: %d, LSB %d, prog: %d",
+ x->instances[chan].pendingBankMSB, x->instances[chan].pendingBankLSB, val);
+#endif
+ dssi_ProgramChange(x, chan);
+ break;
+ }
+ }
+ else if (type == SND_SEQ_EVENT_NOTEON && val == 0) {
+ x->midiEventBuf[x->bufWriteIndex].type = SND_SEQ_EVENT_NOTEOFF;
+ x->midiEventBuf[x->bufWriteIndex].data.note.channel = chan;
+ x->midiEventBuf[x->bufWriteIndex].data.note.note = param;
+ x->midiEventBuf[x->bufWriteIndex].data.note.velocity = val;
+ }
+
+#if DEBUG
+ post("MIDI received in buffer: chan %d, param %d, val %d",
+ chan, param, val);
+#endif
+ x->bufWriteIndex = (x->bufWriteIndex + 1) % EVENT_BUFSIZE;
+ pthread_mutex_unlock(&x->midiEventBufferMutex); /**release mutex*/
+}
+
+static void dssi_show(t_dssi_tilde *x, t_int instance, t_int toggle){
+ if(x->instances[instance].uiTarget){
+ if (x->instances[instance].ui_hidden && toggle) {
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_show_path, "");
+ x->instances[instance].ui_hidden = 0;
+ }
+ else if (!x->instances[instance].ui_hidden && !toggle) {
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_hide_path, "");
+ x->instances[instance].ui_hidden = 1;
+ }
+ }
+ else if(toggle){
+ x->instances[instance].ui_show = 1;
+ dssi_load_gui(x, instance);
+ }
+ /* if(x->instances[instance].uiTarget){
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_show_path, "");
+ x->instances[instance].ui_hidden = 0;
+ }
+ }*/
+
+}
+
+
+static void dssi_list(t_dssi_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ char *msg_type;
+ int ev_type = 0;
+ msg_type = (char *)malloc(TYPE_STRING_SIZE);
+ 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);
+ 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;
+ }
+#if DEBUG
+ post("initial midi NOTE:, arg1 = %d, arg2 = %d, arg3 = %d, arg4 = %d",ev_type,chan,param,val);
+#endif
+ if(ev_type != 0){
+ MIDIbuf(ev_type, chan, param, val, x);
+ }
+ free(msg_type);
+}
+
+/* Method for list data through right inlet */
+/*FIX: rewrite at some point - this is bad*/
+static t_int dssi_config(t_dssi_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ char *msg_type, *debug, *filename, *key, *value;
+ msg_type = (char *)malloc(TYPE_STRING_SIZE);
+ int instance = -1, pathlen, toggle;
+ int n_instances = x->n_instances;
+ int count, maxpatches;
+ t_float val;
+ long filelength = 0;
+ unsigned char *raw_patch_data = NULL;
+ FILE *fp;
+ size_t filename_length;
+ dx7_patch_t *patchbuf, *firstpatch;
+ atom_string(argv, msg_type, TYPE_STRING_SIZE);
+ debug = NULL;
+ key = NULL;
+ value = NULL;
+ maxpatches = 128;
+ patchbuf = malloc(32 * sizeof(dx7_patch_t));
+ firstpatch = &patchbuf[0];
+ val = 0;
+
+
+ /*FIX: 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;
+ instance = (int)atom_getfloatarg(2, argc, argv) - 1;
+ post("loading patch: %s for instance %d", filename, instance);
+ if(instance == -1){
+ while(n_instances--)
+ debug =
+ x->descriptor->configure(
+ x->instanceHandles[n_instances], "bank", filename);
+
+ }
+ else{
+ debug = x->descriptor->configure(
+ x->instanceHandles[instance], "bank", filename);
+ dssi_programs(x, instance);
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_program_path,"ii", 0,0);
+ x->instances[instance].uiNeedsProgramUpdate = 0;
+ x->instances[instance].pendingProgramChange = -1;
+ x->instances[instance].pendingBankMSB = -1;
+ x->instances[instance].pendingBankLSB = -1;
+ }
+
+ }
+
+*/
+ if(!strcmp(msg_type, "load") && x->descriptor->configure){
+ filename = argv[1].a_w.w_symbol->s_name;
+ key = malloc(10 * sizeof(char)); /* holds "patchesN" */
+ strcpy(key, "patches0");
+ post("loading patch: %s for instance %d", filename, instance);
+ fp = fopen(filename, "rb");
+
+ /*From dx7_voice_data by Sean Bolton */
+ if(fp == NULL){
+ post("Unable to open patch file: %s", filename);
+ return 0;
+ }
+ if (fseek(fp, 0, SEEK_END) ||
+ (filelength = ftell(fp)) == -1 ||
+ fseek(fp, 0, SEEK_SET)) {
+ post("couldn't get length of patch file: %s",
+ filename);
+ fclose(fp);
+ return 0;
+ }
+ if (filelength == 0) {
+ post("patch file has zero length");
+ fclose(fp);
+ return 0;
+ } else if (filelength > 16384) {
+ post("patch file is too large");
+ fclose(fp);
+ return 0;
+ }
+ if (!(raw_patch_data = (unsigned char *)malloc(filelength))) {
+ post("couldn't allocate memory for raw patch file");
+ fclose(fp);
+ return 0;
+ }
+ if (fread(raw_patch_data, 1, filelength, fp)
+ != (size_t)filelength) {
+ post("short read on patch file: %s", filename);
+ free(raw_patch_data);
+ fclose(fp);
+ return 0;
+ }
+ fclose(fp);
+ /* At the moment we only support Hexter patches */
+ if(strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter"))
+ post("Sorry dssi~ only supports dx7 patches at the moment.");
+ else{
+ /* 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 */
+
+ count = filelength / DX7_VOICE_SIZE_PACKED;
+ if (count > maxpatches)
+ count = maxpatches;
+ memcpy(firstpatch, raw_patch_data, count *
+ DX7_VOICE_SIZE_PACKED);
+
+ } else if (filelength > 6 &&
+ raw_patch_data[0] == 0xf0 &&
+ raw_patch_data[1] == 0x43 &&
+ (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 */
+
+ if (filelength != DX7_DUMP_SIZE_BULK ||
+ raw_patch_data[DX7_DUMP_SIZE_BULK - 1] != 0xf7) {
+ post("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]) {
+
+ post("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 */
+ post("unknown patch bank file format!");
+ count = 0;
+
+ }
+
+ free(raw_patch_data);
+/* return count;*/
+
+ if(count == 32)
+ value = encode_7in6((uint8_t *)&patchbuf[0].data[0],
+ count * DX7_VOICE_SIZE_PACKED);
+ /* post("value = %s", value); */
+
+/*FIX: make this generic do key value pairs in one go at end of dssi_config after they have been determined */
+
+
+
+ }
+ }
+ /*FIX: tidy up */
+ if(!strcmp(msg_type, "dir") && x->descriptor->configure){
+ /* if(x->dir)
+ free(x->dir); *//*Should never happen */
+ pathlen = strlen(argv[1].a_w.w_symbol->s_name) + 2;
+ x->dir = malloc((pathlen) * sizeof(char));
+ atom_string(&argv[1], x->dir, pathlen);
+ /* instance = (int)atom_getfloatarg(2, argc, argv) - 1;*/
+ post("Project directory for instance %d has been set to: %s", instance, x->dir);
+ key = DSSI_PROJECT_DIRECTORY_KEY;
+ value = x->dir;
+ }
+ /* if(x->instances[instance].uiTarget)
+ post("uiTarget: %s",x->instances[instance].uiTarget);
+ if(x->instances[instance].ui_osc_configure_path)
+ post("osc_config_path: %s",x->instances[instance].ui_osc_configure_path);
+*//* lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_configure_path,
+ "ss", DSSI_PROJECT_DIRECTORY_KEY, path);
+*/
+
+
+ else if(!strcmp(msg_type, "dir"))
+ post("%s %s: operation not supported", 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--)
+ dssi_show(x, n_instances, toggle);
+ }
+ else
+ dssi_show(x, instance, toggle);
+ }
+ if(!strcmp(msg_type, "reset")){
+ instance = (int)atom_getfloatarg(1, argc, argv) - 1;
+ if (instance == -1){
+ for(instance = 0; instance < x->n_instances; instance++) {
+ if (x->descriptor->LADSPA_Plugin->deactivate &&
+ x->descriptor->LADSPA_Plugin->activate){
+ x->descriptor->LADSPA_Plugin->deactivate
+ (x->instanceHandles[instance]);
+ x->descriptor->LADSPA_Plugin->activate
+ (x->instanceHandles[instance]);
+ }
+ }
+ }
+ else if (x->descriptor->LADSPA_Plugin->deactivate &&
+ x->descriptor->LADSPA_Plugin->activate) {
+ x->descriptor->LADSPA_Plugin->deactivate
+ (x->instanceHandles[instance]);
+ x->descriptor->LADSPA_Plugin->activate
+ (x->instanceHandles[instance]);
+ }
+ }
+ }
+
+
+
+ /*Use this to send arbitrary configure message to plugin */
+ else if(!strcmp(msg_type, "configure")){
+ key =
+ malloc(strlen(argv[1].a_w.w_symbol->s_name) * sizeof(char));
+ atom_string(&argv[1], key, TYPE_STRING_SIZE);
+
+ if (argv[2].a_type == A_FLOAT){
+ val = atom_getfloatarg(2, argc, argv);
+ value = malloc(TYPE_STRING_SIZE * sizeof(char));
+ sprintf(value, "%.2f", val);
+ }
+ else if(argv[2].a_type == A_SYMBOL){
+ value =
+ malloc(strlen(argv[2].a_w.w_symbol->s_name) *
+ sizeof(char));
+ atom_string(&argv[2], value, TYPE_STRING_SIZE);
+ }
+ if(argv[3].a_type == A_FLOAT)
+ instance = atom_getfloatarg(3, argc, argv) - 1;
+ /* else if(argv[3].a_type == A_SYMBOL)
+ post("Argument 4 should be an integer!");
+ */
+ }
+
+ if(key != NULL && value != NULL){
+ if(instance == -1){
+ while(n_instances--){
+ debug =
+ x->descriptor->configure(
+ x->instanceHandles[n_instances],
+ key, value);
+ /*FIX - sort out 'pending' system so that new GUI's for instances get updated */
+ if(x->instances[n_instances].uiTarget != NULL){
+ /* if(!strcmp(msg_type, "load"))*/
+ lo_send(x->instances[n_instances].uiTarget, x->instances[n_instances].ui_osc_configure_path, "ss", key, value);
+ query_programs(x, n_instances);
+ /*FIX: better way to do this - OSC handler?*/
+ }
+ }
+ }
+ /*FIX: Put some error checking in here to make sure instance is valid*/
+ else{
+ debug =
+ x->descriptor->configure(
+ x->instanceHandles[instance],
+ key, value);
+ /* if(!strcmp(msg_type, "load"))*/
+ if(x->instances[n_instances].uiTarget != NULL)
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_configure_path,
+ "ss", key, value);
+ query_programs(x, instance);
+ }
+ }
+#if DEBUG
+ post("The plugin returned %s", debug);
+#endif
+/* if(debug != NULL)
+ free(debug);*/
+free(msg_type);
+free(patchbuf);
+free(value);
+
+if(key != NULL)
+ free(key);
+if(x->dir != NULL)
+ free(x->dir);
+return 0;
+
+}
+
+static void dssi_bang(t_dssi_tilde *x)
+{
+ post("Running instances of %s", x->descriptor->LADSPA_Plugin->Label);
+}
+
+static t_int *dssi_tilde_perform(t_int *w)
+{
+ int N = (int)(w[1]);
+ t_dssi_tilde *x = (t_dssi_tilde *)(w[2]);
+ int i, n, timediff, framediff, instance = 0;
+
+ /*FIX -hmmm do we need this */
+ if(x->n_instances){
+ for (i = 0; i < x->n_instances; i++)
+ x->instanceEventCounts[i] = 0;
+
+ /*Instances = (LADSPA_Handle *)malloc(sizeof(LADSPA_Handle));*/
+
+ for (;x->bufReadIndex != x->bufWriteIndex; x->bufReadIndex =
+ (x->bufReadIndex + 1) % EVENT_BUFSIZE) {
+
+ instance = x->midiEventBuf[x->bufReadIndex].data.note.channel;
+ /*This should never happen, but check anyway*/
+ if(instance > x->n_instances || instance < 0){
+ post("%s: discarding spurious MIDI data, for instance %d", x->descriptor->LADSPA_Plugin->Label, instance);
+#if DEBUG
+ post("n_instances = %d", x->n_instances);
+#endif
+ continue;
+ }
+
+ if (x->instanceEventCounts[instance] == EVENT_BUFSIZE){
+ post("MIDI overflow on channel %d", instance);
+ continue;
+ }
+
+ timediff = (t_int)(clock_gettimesince(x->time_ref) * 1000) -
+ x->midiEventBuf[x->bufReadIndex].time.time.tv_nsec;
+ framediff = (t_int)((t_float)timediff * .000001 / x->sr_inv);
+
+ if (framediff >= N || framediff < 0)
+ x->midiEventBuf[x->bufReadIndex].time.tick = 0;
+ else
+ x->midiEventBuf[x->bufReadIndex].time.tick = N - framediff - 1;
+
+ x->instanceEventBuffers[instance][x->instanceEventCounts[instance]]
+ = x->midiEventBuf[x->bufReadIndex];
+#if DEBUG
+post("%s, note received on channel %d", x->descriptor->LADSPA_Plugin->Label, x->instanceEventBuffers[instance][x->instanceEventCounts[instance]].data.note.channel);
+#endif
+ x->instanceEventCounts[instance]++;
+
+#if DEBUG
+ post("Instance event count for instance %d of %d: %d\n",
+ instance + 1, x->n_instances, x->instanceEventCounts[instance]);
+#endif
+
+ }
+
+ i = 0;
+ while(i < x->n_instances){
+ if(x->instanceHandles[i] &&
+ x->descriptor->run_multiple_synths){
+ x->descriptor->run_multiple_synths
+ (x->n_instances, x->instanceHandles,
+ (unsigned long)N, x->instanceEventBuffers,
+ &x->instanceEventCounts[0]);
+ break;
+ }
+ else if (x->instanceHandles[i]){
+ x->descriptor->run_synth(x->instanceHandles[i],
+ (unsigned long)N, x->instanceEventBuffers[i],
+ x->instanceEventCounts[i]);
+ i++;
+ }
+ }
+
+ for(i = 0; i < x->n_instances; i++){
+/* t_float *out = x->outlets[i];*/
+ for(n = 0; n < N; n++)
+ x->outlets[i][n] = x->plugin_OutputBuffers[i][n];
+/* x->outlets[i][n] = 1;*/
+ }
+ }
+ return (w+3);
+}
+
+static void dssi_tilde_dsp(t_dssi_tilde *x, t_signal **sp)
+{
+ /*FIX -hmmm what's the best way to do this? */
+ if(x->n_instances){
+ int n;
+ t_float **outlets = x->outlets;
+
+ for(n = 0; n < x->n_instances; n++)
+ *outlets++ = sp[n+1]->s_vec;
+ }
+ dsp_add(dssi_tilde_perform, 2, sp[0]->s_n, x);
+
+
+}
+
+static void *dssi_tilde_new(t_symbol *s, t_int argc, t_atom *argv){
+
+ t_dssi_tilde *x = (t_dssi_tilde *)pd_new(dssi_tilde_class);
+ post("dssi~ %.2f\n a DSSI host for Pure Data\n by Jamie Bullock\nIncluding Code from jack-dssi-host\n by Chris Cannam, Steve Harris and Sean Bolton", VERSION);
+
+ if (argc){
+ int i, stop = 0;
+
+
+ /*x->midiEventBufferMutex = PTHREAD_MUTEX_INITIALIZER;
+ */
+
+ pthread_mutex_init(&x->midiEventBufferMutex, NULL);
+
+ x->sr = (t_int)sys_getsr();
+ x->sr_inv = 1 / (t_float)x->sr;
+
+ x->dir = NULL;
+ x->bufWriteIndex = x->bufReadIndex = 0;
+
+ x->dll_name = (char *)malloc(sizeof(char) * 8);/* HARD CODED! */
+ sprintf(x->dll_name, "%s", "plugin"); /* for now - Fix! */
+
+ if(argc >= 2)
+ x->n_instances = (t_int)argv[1].a_w.w_float;
+ else
+ x->n_instances = 1;
+
+ x->instances = (t_dssi_instance *)malloc(sizeof(t_dssi_instance) *
+ x->n_instances);
+
+#if DEBUG
+ post("sr_inv = %.6f", x->sr_inv);
+#endif
+ x->time_ref = (t_int)clock_getlogicaltime;
+ x->blksize = sys_getblksize();
+ x->ports_in = x->ports_out = x->ports_controlIn = x->ports_controlOut = 0;
+
+ x->dll_path = argv[0].a_w.w_symbol->s_name;
+ dssi_load(x->dll_path, &x->dll_handle);
+ if (x->dll_handle){
+ x->desc_func = (DSSI_Descriptor_Function)dlsym(x->dll_handle,
+ "dssi_descriptor");
+ if(x->descriptor = x->desc_func(0)){
+#if DEBUG
+ post("%s loaded successfully!",
+ x->descriptor->LADSPA_Plugin->Label);
+#endif
+ portInfo(x);
+ dssi_assignPorts(x);
+ for(i = 0; i < x->n_instances; i++){
+ x->instanceHandles[i] = x->descriptor->LADSPA_Plugin->instantiate(x->descriptor->LADSPA_Plugin, x->sr);
+ if (!x->instanceHandles[i]){
+ post("instantiation of instance %d failed", i);
+ stop = 1;
+ break;
+ }
+ }
+ if(!stop){
+ for(i = 0;i < x->n_instances; i++)
+ dssi_init(x, i);
+ for(i = 0;i < x->n_instances; i++)
+ dssi_connectPorts(x, i); /* fix this */
+ for(i = 0;i < x->n_instances; i++)
+ dssi_osc_setup(x, i);
+ for(i = 0;i < x->n_instances; i++)
+ dssi_activate(x, i);
+ for(i = 0;i < x->n_instances; i++)
+ dssi_programs(x, i);
+#if LOADGUI
+ for(i = 0;i < x->n_instances; i++)
+ dssi_load_gui(x, i);
+#endif
+ for(i = 0;i < x->n_instances; i++)
+ outlet_new(&x->x_obj, &s_signal);
+
+ x->outlets = (t_float **)calloc(x->n_instances,
+ sizeof(t_float *));
+ }
+ }
+
+ /*Create right inlet for configuration messages */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,
+ &s_list, gensym("config"));
+ }
+
+ else
+ post("unknown error");
+ }
+ else
+ post("No arguments given, please supply a path");
+ return (void *)x;
+}
+
+static void dssi_free(t_dssi_tilde *x){
+
+t_int instance;
+ for(instance = 0; instance < x->n_instances; instance++) {
+ /* no -- see comment in osc_exiting_handler */
+ /* if (!instances[i].inactive) { */
+ if (x->descriptor->LADSPA_Plugin->deactivate) {
+ x->descriptor->LADSPA_Plugin->deactivate
+ (x->instanceHandles[instance]);
+ }
+ /* } */
+ if (x->descriptor->LADSPA_Plugin &&
+ x->descriptor->LADSPA_Plugin->cleanup) {
+ x->descriptor->LADSPA_Plugin->cleanup
+ (x->instanceHandles[instance]);
+ }
+ }
+
+
+#if DEBUG
+ post("Calling dssi_free");
+#endif
+ if(x->dll_handle){
+ instance = x->n_instances;
+ free((LADSPA_Handle)x->instanceHandles);
+ free(x->plugin_ControlInPortNumbers);
+ free((t_float *)x->plugin_InputBuffers);
+ free((t_float *)x->plugin_OutputBuffers);
+ free((snd_seq_event_t *)x->instanceEventBuffers);
+ free(x->instanceEventCounts);
+ free(x->plugin_ControlDataInput);
+ free(x->plugin_ControlDataOutput);
+
+ while(instance--){
+ if(x->instances[instance].gui_pid){
+#if DEBUG
+ post("Freeing GUI process PID = %d", x->instances[instance].gui_pid);
+#endif
+ kill(x->instances[instance].gui_pid, SIGKILL);
+ }
+ free(x->instances[instance].ui_osc_control_path);
+ free(x->instances[instance].ui_osc_configure_path);
+ free(x->instances[instance].ui_osc_program_path);
+ free(x->instances[instance].ui_osc_show_path);
+ free(x->instances[instance].ui_osc_hide_path);
+ free(x->instances[instance].osc_url_path);
+ free(x->instances[instance].plugin_PortControlInNumbers);
+ }
+ free((t_float *)x->outlets);
+ free(x->osc_url_base);
+ free(x->dll_name);
+ }
+}
+
+
+
+void dssi_tilde_setup(void) {
+
+ dssi_tilde_class = class_new(gensym("dssi~"), (t_newmethod)dssi_tilde_new,(t_method)dssi_free, sizeof(t_dssi_tilde), 0, A_GIMME, 0);
+ class_addlist(dssi_tilde_class, dssi_list);
+ class_addbang(dssi_tilde_class, dssi_bang);
+ class_addmethod(dssi_tilde_class, (t_method)dssi_tilde_dsp, gensym("dsp"), 0);
+ class_addmethod(dssi_tilde_class, (t_method)dssi_config,
+ gensym("config"), A_GIMME, 0);
+ class_sethelpsymbol(dssi_tilde_class, gensym("help-dssi"));
+ CLASS_MAINSIGNALIN(dssi_tilde_class, t_dssi_tilde,f);
+}
+
+static int osc_message_handler(const char *path, const char *types,
+ lo_arg **argv,int argc, void *data, void *user_data)
+{
+#if DEBUG
+ post("osc_message_handler active");
+#endif
+ int i, instance = 0;
+ const char *method;
+ char chantemp[2];
+ t_dssi_tilde *x = (t_dssi_tilde *)(user_data);
+
+ if (strncmp(path, "/dssi/", 6)){
+#if DEBUG
+ post("calling osc_debug_handler");
+#endif
+ return osc_debug_handler(path, types, argv, argc, data, x);
+ }
+ for (i = 0; i < x->n_instances; i++) {
+ if (!strncmp(path + 6, x->instances[i].osc_url_path,
+ strlen(x->instances[i].osc_url_path))) {
+ instance = i;
+ break;
+ }
+ }
+#if DEBUG
+ for(i = 0; i < argc; i++){
+ post("got osc request %c from instance %d, path: %s",
+ types[i],instance,path);
+ }
+#endif
+
+ if (!x->instances[instance].osc_url_path){
+#if DEBUG
+ post("calling osc_debug_handler");
+#endif
+ return osc_debug_handler(path, types, argv, argc, data, x);
+ }
+ method = path + 6 + strlen(x->instances[instance].osc_url_path);
+ if (*method != '/' || *(method + 1) == 0){
+#if DEBUG
+ post("calling osc_debug_handler");
+#endif
+ return osc_debug_handler(path, types, argv, argc, data, x);
+ }
+ method++;
+
+ if (!strcmp(method, "configure") && argc == 2 && !strcmp(types, "ss")) {
+
+#if DEBUG
+ post("calling osc_configure_handler");
+#endif
+ return osc_configure_handler(x, argv, instance);
+
+ } else if (!strcmp(method, "control") && argc == 2 && !strcmp(types, "if")) {
+#if DEBUG
+ post("calling osc_control_handler");
+#endif
+ return osc_control_handler(x, argv, instance);
+ }
+
+ else if (!strcmp(method, "midi") && argc == 1 && !strcmp(types, "m")) {
+
+#if DEBUG
+ post("calling osc_midi_handler");
+#endif
+ return osc_midi_handler(x, argv, instance);
+
+ } else if (!strcmp(method, "program") && argc == 2 && !strcmp(types, "ii")){
+#if DEBUG
+ post("calling osc_program_handler");
+#endif
+ return osc_program_handler(x, argv, instance);
+
+ } else if (!strcmp(method, "update") && argc == 1 && !strcmp(types, "s")){
+#if DEBUG
+ post("calling osc_update_handler");
+#endif
+ return osc_update_handler(x, argv, instance);
+
+
+ } else if (!strcmp(method, "exiting") && argc == 0) {
+
+ return osc_exiting_handler(x, argv, instance);
+ }
+
+ return osc_debug_handler(path, types, argv, argc, data, x);
+}
+
diff --git a/dssi/src/dssi~.h b/dssi/src/dssi~.h
new file mode 100644
index 0000000..8f82772
--- /dev/null
+++ b/dssi/src/dssi~.h
@@ -0,0 +1,57 @@
+/* dssi~ - A DSSI host for PD
+ *
+ * Copyright 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.
+ *
+ *
+ * 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 "dssi.h"
+#include <dlfcn.h>
+#include <lo/lo.h>
+#include <unistd.h>
+#include <stdio.h>
+#define __USE_GNU /* for strndup */
+#include <string.h>
+
+#include <stdlib.h> /*for exit()*/
+#include <sys/types.h> /* for fork() */
+#include <signal.h> /* for kill() */
+#include <dirent.h> /* for readdir() */
+
+#define DX7_VOICE_SIZE_PACKED 128 /*From hexter_types.h by Sean Bolton */
+#define DX7_DUMP_SIZE_BULK 4096+8
+
+
+#define VERSION 0.8
+#define EVENT_BUFSIZE 1024
+#define OSC_BASE_MAX 1024
+#define TYPE_STRING_SIZE 20 /* Max size of event type string (must be two more bytes than needed) */
+#define DIR_STRING_SIZE 1024 /* Max size of directory string */
+#define ASCII_n 110
+#define ASCII_p 112
+#define ASCII_c 99
+#define ASCII_b 98
+
+#define LOADGUI 1 /* FIX: depracate this */
+#define DEBUG 0
+