aboutsummaryrefslogtreecommitdiff
path: root/pluginhost~
diff options
context:
space:
mode:
authorJamie Bullock <postlude@users.sourceforge.net>2010-12-08 09:45:09 +0000
committerJamie Bullock <postlude@users.sourceforge.net>2010-12-08 09:45:09 +0000
commit5b43da5a8491e6bb577b9e508c55c9619a1a850f (patch)
tree737034c9ca1fd01a437991324a7eed00fe4ac0c7 /pluginhost~
parentdf7a797838f4941695f253cbb43b9cfe5464dba6 (diff)
- moved dssi to pluginhost~ in preparation for renaming
svn path=/trunk/externals/postlude/; revision=14575
Diffstat (limited to 'pluginhost~')
-rw-r--r--pluginhost~/README45
-rw-r--r--pluginhost~/RELEASE21
-rw-r--r--pluginhost~/doc/dssi-help.pd172
-rw-r--r--pluginhost~/doc/output~.pd69
-rw-r--r--pluginhost~/gpl.txt340
-rw-r--r--pluginhost~/include/alsa/seq_event.h452
-rw-r--r--pluginhost~/include/dssi.h426
-rw-r--r--pluginhost~/include/ladspa.h603
-rw-r--r--pluginhost~/lesser.txt504
-rwxr-xr-xpluginhost~/makefile66
-rw-r--r--pluginhost~/src/dssi~.c2537
-rw-r--r--pluginhost~/src/dssi~.h183
-rw-r--r--pluginhost~/src/jload.c214
-rw-r--r--pluginhost~/src/jsearch.c154
-rw-r--r--pluginhost~/src/jutils.h69
15 files changed, 5855 insertions, 0 deletions
diff --git a/pluginhost~/README b/pluginhost~/README
new file mode 100644
index 0000000..ab164e8
--- /dev/null
+++ b/pluginhost~/README
@@ -0,0 +1,45 @@
+dssi~ - a DSSI host for Pure Data
+=================================
+
+This directory (dssi) contains sourcecode and possibly binaries for a DSSI host for Pure Data. To find out more about DSSI visit http://dssi.sourceforge.net.
+
+The functionality of the external is demonstrated in in the help patch (dssi/doc/help-dssi.pd).
+
+
+
+Requirements
+------------
+
+To compile dssi~ the following are required;
+
+DSSI >= 0.9
+LADSPA SDK >= 1.x
+liblo >= 0.12
+alsa/seq_event.h - included
+pd headers >= 0.37
+
+The help patch requires:
+
+PD >= 0.39
+
+
+
+Installation
+------------
+
+From the same directory as the makefile type:
+
+make
+make install (as root)
+
+Once compiled the binary file and help file should be placed in directories that are included in Pure Data's search path.
+
+
+
+License
+-------
+
+All files included in the dssi/src/ directory, and all binary files (if included) are licensed under the GNU GPL Version 2 (see gpl.txt for details).
+
+All files included in the dssi/include/ directory are licensed under the GNU Lesser General Public License (see lesser.txt for details).
+
diff --git a/pluginhost~/RELEASE b/pluginhost~/RELEASE
new file mode 100644
index 0000000..948c9ea
--- /dev/null
+++ b/pluginhost~/RELEASE
@@ -0,0 +1,21 @@
+
+0.93
+
+- Fixed control in bug and a few others
+
+0.91
+
+-Fixed bugs created by adding LADSPA support
+
+0.89
+
+-Added support for LADSPA plugins mostly using code from plugin~
+-Reorganised inlet/outlet structure
+
+0.83
+
+-Added FluidSynth-DSSI patch load support (i.e. soundfonts)
+
+0.82
+
+-Added hexter6 patch load support
diff --git a/pluginhost~/doc/dssi-help.pd b/pluginhost~/doc/dssi-help.pd
new file mode 100644
index 0000000..b4e5ba3
--- /dev/null
+++ b/pluginhost~/doc/dssi-help.pd
@@ -0,0 +1,172 @@
+#N canvas 186 66 1411 654 10;
+#X obj 1268 524 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 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 6350 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 dssi~_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 1266 547 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 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: [dssi~ <[path to libary:plugin name] or [plugin
+name]> <number of plugin instances>];
+#X obj 229 291 dssi~ /usr/local/lib/dssi/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 7900 1;
+#X obj 378 582 dssi~ 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 6700 1;
+#X obj 491 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 6700 1;
+#X obj 511 394 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 6100 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 connect 0 0 49 0;
+#X connect 0 0 49 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 68 0;
+#X connect 12 0 68 0;
+#X connect 13 0 11 0;
+#X connect 14 0 50 0;
+#X connect 15 0 50 0;
+#X connect 16 0 12 0;
+#X connect 17 0 68 0;
+#X connect 19 0 50 0;
+#X connect 20 1 50 0;
+#X connect 21 0 29 0;
+#X connect 22 0 7 0;
+#X connect 23 0 8 0;
+#X connect 24 0 68 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 68 0;
+#X connect 50 0 13 0;
+#X connect 50 1 13 1;
+#X connect 51 0 27 0;
+#X connect 52 0 27 0;
+#X connect 56 0 68 0;
+#X connect 57 0 68 0;
+#X connect 58 0 25 0;
+#X connect 59 0 25 0;
+#X connect 60 0 26 0;
+#X connect 61 0 26 0;
+#X connect 62 0 27 0;
+#X connect 63 0 27 0;
+#X connect 64 0 27 0;
+#X connect 68 0 55 0;
+#X connect 68 1 18 0;
+#X connect 68 2 18 0;
+#X connect 69 0 68 0;
+#X connect 70 0 71 2;
+#X connect 71 0 66 0;
+#X connect 71 1 41 0;
+#X connect 71 2 41 0;
+#X connect 71 3 41 0;
+#X connect 71 4 41 0;
+#X connect 71 5 41 0;
+#X connect 71 6 41 0;
+#X connect 72 0 71 1;
+#X connect 72 1 71 3;
+#X connect 72 2 71 5;
+#X connect 72 3 71 7;
+#X connect 72 4 71 9;
+#X connect 72 5 71 11;
+#X connect 73 0 74 0;
+#X connect 74 0 72 0;
+#X connect 75 0 71 4;
+#X connect 76 0 71 6;
+#X connect 77 0 71 8;
+#X connect 78 0 71 10;
+#X connect 79 0 71 12;
+#X connect 82 0 71 0;
diff --git a/pluginhost~/doc/output~.pd b/pluginhost~/doc/output~.pd
new file mode 100644
index 0000000..4db0809
--- /dev/null
+++ b/pluginhost~/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/pluginhost~/gpl.txt b/pluginhost~/gpl.txt
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/pluginhost~/gpl.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/pluginhost~/include/alsa/seq_event.h b/pluginhost~/include/alsa/seq_event.h
new file mode 100644
index 0000000..6d59ca4
--- /dev/null
+++ b/pluginhost~/include/alsa/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/pluginhost~/include/dssi.h b/pluginhost~/include/dssi.h
new file mode 100644
index 0000000..dd0cd91
--- /dev/null
+++ b/pluginhost~/include/dssi.h
@@ -0,0 +1,426 @@
+/* -*- c-basic-offset: 4 -*- */
+
+/* dssi.h
+
+ DSSI version 0.9
+ Copyright (c) 2004 Chris Cannam, Steve Harris and Sean Bolton
+
+ 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 library 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 DSSI_INCLUDED
+#define DSSI_INCLUDED
+
+#include <ladspa.h>
+#include <alsa/seq_event.h>
+
+#define DSSI_VERSION "0.9"
+#define DSSI_VERSION_MAJOR 0
+#define DSSI_VERSION_MINOR 9
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ There is a need for an API that supports hosted MIDI soft synths
+ with GUIs in Linux audio applications. In time the GMPI initiative
+ should comprehensively address this need, but the requirement for
+ Linux applications to be able to support simple hosted synths is
+ here now, and GMPI is not. This proposal (the "DSSI Soft Synth
+ Interface" or DSSI, pronounced "dizzy") aims to provide a simple
+ solution in a way that we hope will prove complete and compelling
+ enough to support now, yet not so compelling as to supplant GMPI or
+ any other comprehensive future proposal.
+
+ For simplicity and familiarity, this API is based as far as
+ possible on existing work -- the LADSPA plugin API for control
+ values and audio processing, and the ALSA sequencer event types for
+ MIDI event communication. The GUI part of the proposal is quite
+ new, but may also be applicable retroactively to LADSPA plugins
+ that do not otherwise support this synth interface.
+*/
+
+typedef struct _DSSI_Program_Descriptor {
+
+ /** Bank number for this program. Note that DSSI does not support
+ MIDI-style separation of bank LSB and MSB values. There is no
+ restriction on the set of available banks: the numbers do not
+ need to be contiguous, there does not need to be a bank 0, etc. */
+ unsigned long Bank;
+
+ /** Program number (unique within its bank) for this program.
+ There is no restriction on the set of available programs: the
+ numbers do not need to be contiguous, there does not need to
+ be a program 0, etc. */
+ unsigned long Program;
+
+ /** Name of the program. */
+ const char * Name;
+
+} DSSI_Program_Descriptor;
+
+
+typedef struct _DSSI_Descriptor {
+
+ /**
+ * DSSI_API_Version
+ *
+ * This member indicates the DSSI API level used by this plugin.
+ * If we're lucky, this will never be needed. For now all plugins
+ * must set it to 1.
+ */
+ int DSSI_API_Version;
+
+ /**
+ * LADSPA_Plugin
+ *
+ * A DSSI synth plugin consists of a LADSPA plugin plus an
+ * additional framework for controlling program settings and
+ * transmitting MIDI events. A plugin must fully implement the
+ * LADSPA descriptor fields as well as the required LADSPA
+ * functions including instantiate() and (de)activate(). It
+ * should also implement run(), with the same behaviour as if
+ * run_synth() (below) were called with no synth events.
+ *
+ * In order to instantiate a synth the host calls the LADSPA
+ * instantiate function, passing in this LADSPA_Descriptor
+ * pointer. The returned LADSPA_Handle is used as the argument
+ * for the DSSI functions below as well as for the LADSPA ones.
+ */
+ const LADSPA_Descriptor *LADSPA_Plugin;
+
+ /**
+ * configure()
+ *
+ * This member is a function pointer that sends a piece of
+ * configuration data to the plugin. The key argument specifies
+ * some aspect of the synth's configuration that is to be changed,
+ * and the value argument specifies a new value for it. A plugin
+ * that does not require this facility at all may set this member
+ * to NULL.
+ *
+ * This call is intended to set some session-scoped aspect of a
+ * plugin's behaviour, for example to tell the plugin to load
+ * sample data from a particular file. The plugin should act
+ * immediately on the request. The call should return NULL on
+ * success, or an error string that may be shown to the user. The
+ * host will free the returned value after use if it is non-NULL.
+ *
+ * Calls to configure() are not automated as timed events.
+ * Instead, a host should remember the last value associated with
+ * each key passed to configure() during a given session for a
+ * given plugin instance, and should call configure() with the
+ * correct value for each key the next time it instantiates the
+ * "same" plugin instance, for example on reloading a project in
+ * which the plugin was used before. Plugins should note that a
+ * host may typically instantiate a plugin multiple times with the
+ * same configuration values, and should share data between
+ * instances where practical.
+ *
+ * Calling configure() completely invalidates the program and bank
+ * information last obtained from the plugin.
+ *
+ * Reserved and special key prefixes
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * The DSSI: prefix
+ * ----------------
+ * Configure keys starting with DSSI: are reserved for particular
+ * purposes documented in the DSSI specification. At the moment,
+ * there is one such key: DSSI:PROJECT_DIRECTORY. A host may call
+ * configure() passing this key and a directory path value. This
+ * indicates to the plugin and its UI that a directory at that
+ * path exists and may be used for project-local data. Plugins
+ * may wish to use the project directory as a fallback location
+ * when looking for other file data, or as a base for relative
+ * paths in other configuration values.
+ *
+ * The GLOBAL: prefix
+ * ------------------
+ * Configure keys starting with GLOBAL: may be used by the plugin
+ * and its UI for any purpose, but are treated specially by the
+ * host. When one of these keys is used in a configure OSC call
+ * from the plugin UI, the host makes the corresponding configure
+ * call (preserving the GLOBAL: prefix) not only to the target
+ * plugin but also to all other plugins in the same instance
+ * group, as well as their UIs. Note that if any instance
+ * returns non-NULL from configure to indicate error, the host
+ * may stop there (and the set of plugins on which configure has
+ * been called will thus depend on the host implementation).
+ * See also the configure OSC call documentation in RFC.txt.
+ */
+ char *(*configure)(LADSPA_Handle Instance,
+ const char *Key,
+ const char *Value);
+
+ #define DSSI_RESERVED_CONFIGURE_PREFIX "DSSI:"
+ #define DSSI_GLOBAL_CONFIGURE_PREFIX "GLOBAL:"
+ #define DSSI_PROJECT_DIRECTORY_KEY \
+ DSSI_RESERVED_CONFIGURE_PREFIX "PROJECT_DIRECTORY"
+
+ /**
+ * get_program()
+ *
+ * This member is a function pointer that provides a description
+ * of a program (named preset sound) available on this synth. A
+ * plugin that does not support programs at all should set this
+ * member to NULL.
+ *
+ * The Index argument is an index into the plugin's list of
+ * programs, not a program number as represented by the Program
+ * field of the DSSI_Program_Descriptor. (This distinction is
+ * needed to support synths that use non-contiguous program or
+ * bank numbers.)
+ *
+ * This function returns a DSSI_Program_Descriptor pointer that is
+ * guaranteed to be valid only until the next call to get_program,
+ * deactivate, or configure, on the same plugin instance. This
+ * function must return NULL if passed an Index argument out of
+ * range, so that the host can use it to query the number of
+ * programs as well as their properties.
+ */
+ const DSSI_Program_Descriptor *(*get_program)(LADSPA_Handle Instance,
+ unsigned long Index);
+
+ /**
+ * select_program()
+ *
+ * This member is a function pointer that selects a new program
+ * for this synth. The program change should take effect
+ * immediately at the start of the next run_synth() call. (This
+ * means that a host providing the capability of changing programs
+ * between any two notes on a track must vary the block size so as
+ * to place the program change at the right place. A host that
+ * wanted to avoid this would probably just instantiate a plugin
+ * for each program.)
+ *
+ * A plugin that does not support programs at all should set this
+ * member NULL. Plugins should ignore a select_program() call
+ * with an invalid bank or program.
+ *
+ * A plugin is not required to select any particular default
+ * program on activate(): it's the host's duty to set a program
+ * explicitly. The current program is invalidated by any call to
+ * configure().
+ *
+ * A plugin is permitted to re-write the values of its input
+ * control ports when select_program is called. The host should
+ * re-read the input control port values and update its own
+ * records appropriately. (This is the only circumstance in
+ * which a DSSI plugin is allowed to modify its own input ports.)
+ */
+ void (*select_program)(LADSPA_Handle Instance,
+ unsigned long Bank,
+ unsigned long Program);
+
+ /**
+ * get_midi_controller_for_port()
+ *
+ * This member is a function pointer that returns the MIDI
+ * controller number or NRPN that should be mapped to the given
+ * input control port. If the given port should not have any MIDI
+ * controller mapped to it, the function should return DSSI_NONE.
+ * The behaviour of this function is undefined if the given port
+ * number does not correspond to an input control port. A plugin
+ * that does not want MIDI controllers mapped to ports at all may
+ * set this member NULL.
+ *
+ * Correct values can be got using the macros DSSI_CC(num) and
+ * DSSI_NRPN(num) as appropriate, and values can be combined using
+ * bitwise OR: e.g. DSSI_CC(23) | DSSI_NRPN(1069) means the port
+ * should respond to CC #23 and NRPN #1069.
+ *
+ * The host is responsible for doing proper scaling from MIDI
+ * controller and NRPN value ranges to port ranges according to
+ * the plugin's LADSPA port hints. Hosts should not deliver
+ * through run_synth any MIDI controller events that have already
+ * been mapped to control port values.
+ *
+ * A plugin should not attempt to request mappings from
+ * controllers 0 or 32 (MIDI Bank Select MSB and LSB).
+ */
+ int (*get_midi_controller_for_port)(LADSPA_Handle Instance,
+ unsigned long Port);
+
+ /**
+ * run_synth()
+ *
+ * This member is a function pointer that runs a synth for a
+ * block. This is identical in function to the LADSPA run()
+ * function, except that it also supplies events to the synth.
+ *
+ * A plugin may provide this function, run_multiple_synths() (see
+ * below), both, or neither (if it is not in fact a synth). A
+ * plugin that does not provide this function must set this member
+ * to NULL. Authors of synth plugins are encouraged to provide
+ * this function if at all possible.
+ *
+ * The Events pointer points to a block of EventCount ALSA
+ * sequencer events, which is used to communicate MIDI and related
+ * events to the synth. Each event is timestamped relative to the
+ * start of the block, (mis)using the ALSA "tick time" field as a
+ * frame count. The host is responsible for ensuring that events
+ * with differing timestamps are already ordered by time.
+ *
+ * See also the notes on activation, port connection etc in
+ * ladpsa.h, in the context of the LADSPA run() function.
+ *
+ * Note Events
+ * ~~~~~~~~~~~
+ * There are two minor requirements aimed at making the plugin
+ * writer's life as simple as possible:
+ *
+ * 1. A host must never send events of type SND_SEQ_EVENT_NOTE.
+ * Notes should always be sent as separate SND_SEQ_EVENT_NOTE_ON
+ * and NOTE_OFF events. A plugin should discard any one-point
+ * NOTE events it sees.
+ *
+ * 2. A host must not attempt to switch notes off by sending
+ * zero-velocity NOTE_ON events. It should always send true
+ * NOTE_OFFs. It is the host's responsibility to remap events in
+ * cases where an external MIDI source has sent it zero-velocity
+ * NOTE_ONs.
+ *
+ * Bank and Program Events
+ * ~~~~~~~~~~~~~~~~~~~~~~~
+ * Hosts must map MIDI Bank Select MSB and LSB (0 and 32)
+ * controllers and MIDI Program Change events onto the banks and
+ * programs specified by the plugin, using the DSSI select_program
+ * call. No host should ever deliver a program change or bank
+ * select controller to a plugin via run_synth.
+ */
+ void (*run_synth)(LADSPA_Handle Instance,
+ unsigned long SampleCount,
+ snd_seq_event_t *Events,
+ unsigned long EventCount);
+
+ /**
+ * run_synth_adding()
+ *
+ * This member is a function pointer that runs an instance of a
+ * synth for a block, adding its outputs to the values already
+ * present at the output ports. This is provided for symmetry
+ * with LADSPA run_adding(), and is equally optional. A plugin
+ * that does not provide it must set this member to NULL.
+ */
+ void (*run_synth_adding)(LADSPA_Handle Instance,
+ unsigned long SampleCount,
+ snd_seq_event_t *Events,
+ unsigned long EventCount);
+
+ /**
+ * run_multiple_synths()
+ *
+ * This member is a function pointer that runs multiple synth
+ * instances for a block. This is very similar to run_synth(),
+ * except that Instances, Events, and EventCounts each point to
+ * arrays that hold the LADSPA handles, event buffers, and
+ * event counts for each of InstanceCount instances. That is,
+ * Instances points to an array of InstanceCount pointers to
+ * DSSI plugin instantiations, Events points to an array of
+ * pointers to each instantiation's respective event list, and
+ * EventCounts points to an array containing each instantiation's
+ * respective event count.
+ *
+ * A host using this function must guarantee that ALL active
+ * instances of the plugin are represented in each call to the
+ * function -- that is, a host may not call run_multiple_synths()
+ * for some instances of a given plugin and then call run_synth()
+ * as well for others. 'All .. instances of the plugin' means
+ * every instance sharing the same LADSPA label and shared object
+ * (*.so) file (rather than every instance sharing the same *.so).
+ * 'Active' means any instance for which activate() has been called
+ * but deactivate() has not.
+ *
+ * A plugin may provide this function, run_synths() (see above),
+ * both, or neither (if it not in fact a synth). A plugin that
+ * does not provide this function must set this member to NULL.
+ * Plugin authors implementing run_multiple_synths are strongly
+ * encouraged to implement run_synth as well if at all possible,
+ * to aid simplistic hosts, even where it would be less efficient
+ * to use it.
+ */
+ void (*run_multiple_synths)(unsigned long InstanceCount,
+ LADSPA_Handle *Instances,
+ unsigned long SampleCount,
+ snd_seq_event_t **Events,
+ unsigned long *EventCounts);
+
+ /**
+ * run_multiple_synths_adding()
+ *
+ * This member is a function pointer that runs multiple synth
+ * instances for a block, adding each synth's outputs to the
+ * values already present at the output ports. This is provided
+ * for symmetry with both the DSSI run_multiple_synths() and LADSPA
+ * run_adding() functions, and is equally optional. A plugin
+ * that does not provide it must set this member to NULL.
+ */
+ void (*run_multiple_synths_adding)(unsigned long InstanceCount,
+ LADSPA_Handle *Instances,
+ unsigned long SampleCount,
+ snd_seq_event_t **Events,
+ unsigned long *EventCounts);
+} DSSI_Descriptor;
+
+/**
+ * DSSI supports a plugin discovery method similar to that of LADSPA:
+ *
+ * - DSSI hosts may wish to locate DSSI plugin shared object files by
+ * searching the paths contained in the DSSI_PATH and LADSPA_PATH
+ * environment variables, if they are present. Both are expected
+ * to be colon-separated lists of directories to be searched (in
+ * order), and DSSI_PATH should be searched first if both variables
+ * are set.
+ *
+ * - Each shared object file containing DSSI plugins must include a
+ * function dssi_descriptor(), with the following function prototype
+ * and C-style linkage. Hosts may enumerate the plugin types
+ * available in the shared object file by repeatedly calling
+ * this function with successive Index values (beginning from 0),
+ * until a return value of NULL indicates no more plugin types are
+ * available. Each non-NULL return is the DSSI_Descriptor
+ * of a distinct plugin type.
+ */
+
+const DSSI_Descriptor *dssi_descriptor(unsigned long Index);
+
+typedef const DSSI_Descriptor *(*DSSI_Descriptor_Function)(unsigned long Index);
+
+/*
+ * Macros to specify particular MIDI controllers in return values from
+ * get_midi_controller_for_port()
+ */
+
+#define DSSI_CC_BITS 0x20000000
+#define DSSI_NRPN_BITS 0x40000000
+
+#define DSSI_NONE -1
+#define DSSI_CONTROLLER_IS_SET(n) (DSSI_NONE != (n))
+
+#define DSSI_CC(n) (DSSI_CC_BITS | (n))
+#define DSSI_IS_CC(n) (DSSI_CC_BITS & (n))
+#define DSSI_CC_NUMBER(n) ((n) & 0x7f)
+
+#define DSSI_NRPN(n) (DSSI_NRPN_BITS | ((n) << 7))
+#define DSSI_IS_NRPN(n) (DSSI_NRPN_BITS & (n))
+#define DSSI_NRPN_NUMBER(n) (((n) >> 7) & 0x3fff)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DSSI_INCLUDED */
diff --git a/pluginhost~/include/ladspa.h b/pluginhost~/include/ladspa.h
new file mode 100644
index 0000000..5c30a8a
--- /dev/null
+++ b/pluginhost~/include/ladspa.h
@@ -0,0 +1,603 @@
+/* ladspa.h
+
+ Linux Audio Developer's Simple Plugin API Version 1.1[LGPL].
+ Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis,
+ Stefan Westerfeld.
+
+ 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 library 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 LADSPA_INCLUDED
+#define LADSPA_INCLUDED
+
+#define LADSPA_VERSION "1.1"
+#define LADSPA_VERSION_MAJOR 1
+#define LADSPA_VERSION_MINOR 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+/* Overview:
+
+ There is a large number of synthesis packages in use or development
+ on the Linux platform at this time. This API (`The Linux Audio
+ Developer's Simple Plugin API') attempts to give programmers the
+ ability to write simple `plugin' audio processors in C/C++ and link
+ them dynamically (`plug') into a range of these packages (`hosts').
+ It should be possible for any host and any plugin to communicate
+ completely through this interface.
+
+ This API is deliberately short and simple. To achieve compatibility
+ with a range of promising Linux sound synthesis packages it
+ attempts to find the `greatest common divisor' in their logical
+ behaviour. Having said this, certain limiting decisions are
+ implicit, notably the use of a fixed type (LADSPA_Data) for all
+ data transfer and absence of a parameterised `initialisation'
+ phase. See below for the LADSPA_Data typedef.
+
+ Plugins are expected to distinguish between control and audio
+ data. Plugins have `ports' that are inputs or outputs for audio or
+ control data and each plugin is `run' for a `block' corresponding
+ to a short time interval measured in samples. Audio data is
+ communicated using arrays of LADSPA_Data, allowing a block of audio
+ to be processed by the plugin in a single pass. Control data is
+ communicated using single LADSPA_Data values. Control data has a
+ single value at the start of a call to the `run()' or `run_adding()'
+ function, and may be considered to remain this value for its
+ duration. The plugin may assume that all its input and output ports
+ have been connected to the relevant data location (see the
+ `connect_port()' function below) before it is asked to run.
+
+ Plugins will reside in shared object files suitable for dynamic
+ linking by dlopen() and family. The file will provide a number of
+ `plugin types' that can be used to instantiate actual plugins
+ (sometimes known as `plugin instances') that can be connected
+ together to perform tasks.
+
+ This API contains very limited error-handling. */
+
+/*****************************************************************************/
+
+/* Fundamental data type passed in and out of plugin. This data type
+ is used to communicate audio samples and control values. It is
+ assumed that the plugin will work sensibly given any numeric input
+ value although it may have a preferred range (see hints below).
+
+ For audio it is generally assumed that 1.0f is the `0dB' reference
+ amplitude and is a `normal' signal level. */
+
+typedef float LADSPA_Data;
+
+/*****************************************************************************/
+
+/* Special Plugin Properties:
+
+ Optional features of the plugin type are encapsulated in the
+ LADSPA_Properties type. This is assembled by ORing individual
+ properties together. */
+
+typedef int LADSPA_Properties;
+
+/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a
+ real-time dependency (e.g. listens to a MIDI device) and so its
+ output must not be cached or subject to significant latency. */
+#define LADSPA_PROPERTY_REALTIME 0x1
+
+/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin
+ may cease to work correctly if the host elects to use the same data
+ location for both input and output (see connect_port()). This
+ should be avoided as enabling this flag makes it impossible for
+ hosts to use the plugin to process audio `in-place.' */
+#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2
+
+/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin
+ is capable of running not only in a conventional host but also in a
+ `hard real-time' environment. To qualify for this the plugin must
+ satisfy all of the following:
+
+ (1) The plugin must not use malloc(), free() or other heap memory
+ management within its run() or run_adding() functions. All new
+ memory used in run() must be managed via the stack. These
+ restrictions only apply to the run() function.
+
+ (2) The plugin will not attempt to make use of any library
+ functions with the exceptions of functions in the ANSI standard C
+ and C maths libraries, which the host is expected to provide.
+
+ (3) The plugin will not access files, devices, pipes, sockets, IPC
+ or any other mechanism that might result in process or thread
+ blocking.
+
+ (4) The plugin will take an amount of time to execute a run() or
+ run_adding() call approximately of form (A+B*SampleCount) where A
+ and B depend on the machine and host in use. This amount of time
+ may not depend on input signals or plugin state. The host is left
+ the responsibility to perform timings to estimate upper bounds for
+ A and B. */
+#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4
+
+#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME)
+#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN)
+#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE)
+
+/*****************************************************************************/
+
+/* Plugin Ports:
+
+ Plugins have `ports' that are inputs or outputs for audio or
+ data. Ports can communicate arrays of LADSPA_Data (for audio
+ inputs/outputs) or single LADSPA_Data values (for control
+ input/outputs). This information is encapsulated in the
+ LADSPA_PortDescriptor type which is assembled by ORing individual
+ properties together.
+
+ Note that a port must be an input or an output port but not both
+ and that a port must be a control or audio port but not both. */
+
+typedef int LADSPA_PortDescriptor;
+
+/* Property LADSPA_PORT_INPUT indicates that the port is an input. */
+#define LADSPA_PORT_INPUT 0x1
+
+/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */
+#define LADSPA_PORT_OUTPUT 0x2
+
+/* Property LADSPA_PORT_CONTROL indicates that the port is a control
+ port. */
+#define LADSPA_PORT_CONTROL 0x4
+
+/* Property LADSPA_PORT_AUDIO indicates that the port is a audio
+ port. */
+#define LADSPA_PORT_AUDIO 0x8
+
+#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT)
+#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT)
+#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL)
+#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO)
+
+/*****************************************************************************/
+
+/* Plugin Port Range Hints:
+
+ The host may wish to provide a representation of data entering or
+ leaving a plugin (e.g. to generate a GUI automatically). To make
+ this more meaningful, the plugin should provide `hints' to the host
+ describing the usual values taken by the data.
+
+ Note that these are only hints. The host may ignore them and the
+ plugin must not assume that data supplied to it is meaningful. If
+ the plugin receives invalid input data it is expected to continue
+ to run without failure and, where possible, produce a sensible
+ output (e.g. a high-pass filter given a negative cutoff frequency
+ might switch to an all-pass mode).
+
+ Hints are meaningful for all input and output ports but hints for
+ input control ports are expected to be particularly useful.
+
+ More hint information is encapsulated in the
+ LADSPA_PortRangeHintDescriptor type which is assembled by ORing
+ individual hint types together. Hints may require further
+ LowerBound and UpperBound information.
+
+ All the hint information for a particular port is aggregated in the
+ LADSPA_PortRangeHint structure. */
+
+typedef int LADSPA_PortRangeHintDescriptor;
+
+/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field
+ of the LADSPA_PortRangeHint should be considered meaningful. The
+ value in this field should be considered the (inclusive) lower
+ bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
+ specified then the value of LowerBound should be multiplied by the
+ sample rate. */
+#define LADSPA_HINT_BOUNDED_BELOW 0x1
+
+/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field
+ of the LADSPA_PortRangeHint should be considered meaningful. The
+ value in this field should be considered the (inclusive) upper
+ bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also
+ specified then the value of UpperBound should be multiplied by the
+ sample rate. */
+#define LADSPA_HINT_BOUNDED_ABOVE 0x2
+
+/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be
+ considered a Boolean toggle. Data less than or equal to zero should
+ be considered `off' or `false,' and data above zero should be
+ considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in
+ conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or
+ LADSPA_HINT_DEFAULT_1. */
+#define LADSPA_HINT_TOGGLED 0x4
+
+/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified
+ should be interpreted as multiples of the sample rate. For
+ instance, a frequency range from 0Hz to the Nyquist frequency (half
+ the sample rate) could be requested by this hint in conjunction
+ with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
+ at all must support this hint to retain meaning. */
+#define LADSPA_HINT_SAMPLE_RATE 0x8
+
+/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the
+ user will find it more intuitive to view values using a logarithmic
+ scale. This is particularly useful for frequencies and gains. */
+#define LADSPA_HINT_LOGARITHMIC 0x10
+
+/* Hint LADSPA_HINT_INTEGER indicates that a user interface would
+ probably wish to provide a stepped control taking only integer
+ values. Any bounds set should be slightly wider than the actual
+ integer range required to avoid floating point rounding errors. For
+ instance, the integer set {0,1,2,3} might be described as [-0.1,
+ 3.1]. */
+#define LADSPA_HINT_INTEGER 0x20
+
+/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal'
+ value for the port that is sensible as a default. For instance,
+ this value is suitable for use as an initial value in a user
+ interface or as a value the host might assign to a control port
+ when the user has not provided one. Defaults are encoded using a
+ mask so only one default may be specified for a port. Some of the
+ hints make use of lower and upper bounds, in which case the
+ relevant bound or bounds must be available and
+ LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting
+ default must be rounded if LADSPA_HINT_INTEGER is present. Default
+ values were introduced in LADSPA v1.1. */
+#define LADSPA_HINT_DEFAULT_MASK 0x3C0
+
+/* This default values indicates that no default is provided. */
+#define LADSPA_HINT_DEFAULT_NONE 0x0
+
+/* This default hint indicates that the suggested lower bound for the
+ port should be used. */
+#define LADSPA_HINT_DEFAULT_MINIMUM 0x40
+
+/* This default hint indicates that a low value between the suggested
+ lower and upper bounds should be chosen. For ports with
+ LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 +
+ log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper
+ * 0.25). */
+#define LADSPA_HINT_DEFAULT_LOW 0x80
+
+/* This default hint indicates that a middle value between the
+ suggested lower and upper bounds should be chosen. For ports with
+ LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 +
+ log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper *
+ 0.5). */
+#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0
+
+/* This default hint indicates that a high value between the suggested
+ lower and upper bounds should be chosen. For ports with
+ LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 +
+ log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper
+ * 0.75). */
+#define LADSPA_HINT_DEFAULT_HIGH 0x100
+
+/* This default hint indicates that the suggested upper bound for the
+ port should be used. */
+#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140
+
+/* This default hint indicates that the number 0 should be used. Note
+ that this default may be used in conjunction with
+ LADSPA_HINT_TOGGLED. */
+#define LADSPA_HINT_DEFAULT_0 0x200
+
+/* This default hint indicates that the number 1 should be used. Note
+ that this default may be used in conjunction with
+ LADSPA_HINT_TOGGLED. */
+#define LADSPA_HINT_DEFAULT_1 0x240
+
+/* This default hint indicates that the number 100 should be used. */
+#define LADSPA_HINT_DEFAULT_100 0x280
+
+/* This default hint indicates that the Hz frequency of `concert A'
+ should be used. This will be 440 unless the host uses an unusual
+ tuning convention, in which case it may be within a few Hz. */
+#define LADSPA_HINT_DEFAULT_440 0x2C0
+
+#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW)
+#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE)
+#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED)
+#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE)
+#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC)
+#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER)
+
+#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK)
+#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_MINIMUM)
+#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_LOW)
+#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_MIDDLE)
+#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_HIGH)
+#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_MAXIMUM)
+#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_0)
+#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_1)
+#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_100)
+#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \
+ == LADSPA_HINT_DEFAULT_440)
+
+typedef struct _LADSPA_PortRangeHint {
+
+ /* Hints about the port. */
+ LADSPA_PortRangeHintDescriptor HintDescriptor;
+
+ /* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When
+ LADSPA_HINT_SAMPLE_RATE is also active then this value should be
+ multiplied by the relevant sample rate. */
+ LADSPA_Data LowerBound;
+
+ /* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When
+ LADSPA_HINT_SAMPLE_RATE is also active then this value should be
+ multiplied by the relevant sample rate. */
+ LADSPA_Data UpperBound;
+
+} LADSPA_PortRangeHint;
+
+/*****************************************************************************/
+
+/* Plugin Handles:
+
+ This plugin handle indicates a particular instance of the plugin
+ concerned. It is valid to compare this to NULL (0 for C++) but
+ otherwise the host should not attempt to interpret it. The plugin
+ may use it to reference internal instance data. */
+
+typedef void * LADSPA_Handle;
+
+/*****************************************************************************/
+
+/* Descriptor for a Type of Plugin:
+
+ This structure is used to describe a plugin type. It provides a
+ number of functions to examine the type, instantiate it, link it to
+ buffers and workspaces and to run it. */
+
+typedef struct _LADSPA_Descriptor {
+
+ /* This numeric identifier indicates the plugin type
+ uniquely. Plugin programmers may reserve ranges of IDs from a
+ central body to avoid clashes. Hosts may assume that IDs are
+ below 0x1000000. */
+ unsigned long UniqueID;
+
+ /* This identifier can be used as a unique, case-sensitive
+ identifier for the plugin type within the plugin file. Plugin
+ types should be identified by file and label rather than by index
+ or plugin name, which may be changed in new plugin
+ versions. Labels must not contain white-space characters. */
+ const char * Label;
+
+ /* This indicates a number of properties of the plugin. */
+ LADSPA_Properties Properties;
+
+ /* This member points to the null-terminated name of the plugin
+ (e.g. "Sine Oscillator"). */
+ const char * Name;
+
+ /* This member points to the null-terminated string indicating the
+ maker of the plugin. This can be an empty string but not NULL. */
+ const char * Maker;
+
+ /* This member points to the null-terminated string indicating any
+ copyright applying to the plugin. If no Copyright applies the
+ string "None" should be used. */
+ const char * Copyright;
+
+ /* This indicates the number of ports (input AND output) present on
+ the plugin. */
+ unsigned long PortCount;
+
+ /* This member indicates an array of port descriptors. Valid indices
+ vary from 0 to PortCount-1. */
+ const LADSPA_PortDescriptor * PortDescriptors;
+
+ /* This member indicates an array of null-terminated strings
+ describing ports (e.g. "Frequency (Hz)"). Valid indices vary from
+ 0 to PortCount-1. */
+ const char * const * PortNames;
+
+ /* This member indicates an array of range hints for each port (see
+ above). Valid indices vary from 0 to PortCount-1. */
+ const LADSPA_PortRangeHint * PortRangeHints;
+
+ /* This may be used by the plugin developer to pass any custom
+ implementation data into an instantiate call. It must not be used
+ or interpreted by the host. It is expected that most plugin
+ writers will not use this facility as LADSPA_Handle should be
+ used to hold instance data. */
+ void * ImplementationData;
+
+ /* This member is a function pointer that instantiates a plugin. A
+ handle is returned indicating the new plugin instance. The
+ instantiation function accepts a sample rate as a parameter. The
+ plugin descriptor from which this instantiate function was found
+ must also be passed. This function must return NULL if
+ instantiation fails.
+
+ Note that instance initialisation should generally occur in
+ activate() rather than here. */
+ LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor,
+ unsigned long SampleRate);
+
+ /* This member is a function pointer that connects a port on an
+ instantiated plugin to a memory location at which a block of data
+ for the port will be read/written. The data location is expected
+ to be an array of LADSPA_Data for audio ports or a single
+ LADSPA_Data value for control ports. Memory issues will be
+ managed by the host. The plugin must read/write the data at these
+ locations every time run() or run_adding() is called and the data
+ present at the time of this connection call should not be
+ considered meaningful.
+
+ connect_port() may be called more than once for a plugin instance
+ to allow the host to change the buffers that the plugin is
+ reading or writing. These calls may be made before or after
+ activate() or deactivate() calls.
+
+ connect_port() must be called at least once for each port before
+ run() or run_adding() is called. When working with blocks of
+ LADSPA_Data the plugin should pay careful attention to the block
+ size passed to the run function as the block allocated may only
+ just be large enough to contain the block of samples.
+
+ Plugin writers should be aware that the host may elect to use the
+ same buffer for more than one port and even use the same buffer
+ for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN).
+ However, overlapped buffers or use of a single buffer for both
+ audio and control data may result in unexpected behaviour. */
+ void (*connect_port)(LADSPA_Handle Instance,
+ unsigned long Port,
+ LADSPA_Data * DataLocation);
+
+ /* This member is a function pointer that initialises a plugin
+ instance and activates it for use. This is separated from
+ instantiate() to aid real-time support and so that hosts can
+ reinitialise a plugin instance by calling deactivate() and then
+ activate(). In this case the plugin instance must reset all state
+ information dependent on the history of the plugin instance
+ except for any data locations provided by connect_port() and any
+ gain set by set_run_adding_gain(). If there is nothing for
+ activate() to do then the plugin writer may provide a NULL rather
+ than an empty function.
+
+ When present, hosts must call this function once before run() (or
+ run_adding()) is called for the first time. This call should be
+ made as close to the run() call as possible and indicates to
+ real-time plugins that they are now live. Plugins should not rely
+ on a prompt call to run() after activate(). activate() may not be
+ called again unless deactivate() is called first. Note that
+ connect_port() may be called before or after a call to
+ activate(). */
+ void (*activate)(LADSPA_Handle Instance);
+
+ /* This method is a function pointer that runs an instance of a
+ plugin for a block. Two parameters are required: the first is a
+ handle to the particular instance to be run and the second
+ indicates the block size (in samples) for which the plugin
+ instance may run.
+
+ Note that if an activate() function exists then it must be called
+ before run() or run_adding(). If deactivate() is called for a
+ plugin instance then the plugin instance may not be reused until
+ activate() has been called again.
+
+ If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE
+ then there are various things that the plugin should not do
+ within the run() or run_adding() functions (see above). */
+ void (*run)(LADSPA_Handle Instance,
+ unsigned long SampleCount);
+
+ /* This method is a function pointer that runs an instance of a
+ plugin for a block. This has identical behaviour to run() except
+ in the way data is output from the plugin. When run() is used,
+ values are written directly to the memory areas associated with
+ the output ports. However when run_adding() is called, values
+ must be added to the values already present in the memory
+ areas. Furthermore, output values written must be scaled by the
+ current gain set by set_run_adding_gain() (see below) before
+ addition.
+
+ run_adding() is optional. When it is not provided by a plugin,
+ this function pointer must be set to NULL. When it is provided,
+ the function set_run_adding_gain() must be provided also. */
+ void (*run_adding)(LADSPA_Handle Instance,
+ unsigned long SampleCount);
+
+ /* This method is a function pointer that sets the output gain for
+ use when run_adding() is called (see above). If this function is
+ never called the gain is assumed to default to 1. Gain
+ information should be retained when activate() or deactivate()
+ are called.
+
+ This function should be provided by the plugin if and only if the
+ run_adding() function is provided. When it is absent this
+ function pointer must be set to NULL. */
+ void (*set_run_adding_gain)(LADSPA_Handle Instance,
+ LADSPA_Data Gain);
+
+ /* This is the counterpart to activate() (see above). If there is
+ nothing for deactivate() to do then the plugin writer may provide
+ a NULL rather than an empty function.
+
+ Hosts must deactivate all activated units after they have been
+ run() (or run_adding()) for the last time. This call should be
+ made as close to the last run() call as possible and indicates to
+ real-time plugins that they are no longer live. Plugins should
+ not rely on prompt deactivation. Note that connect_port() may be
+ called before or after a call to deactivate().
+
+ Deactivation is not similar to pausing as the plugin instance
+ will be reinitialised when activate() is called to reuse it. */
+ void (*deactivate)(LADSPA_Handle Instance);
+
+ /* Once an instance of a plugin has been finished with it can be
+ deleted using the following function. The instance handle passed
+ ceases to be valid after this call.
+
+ If activate() was called for a plugin instance then a
+ corresponding call to deactivate() must be made before cleanup()
+ is called. */
+ void (*cleanup)(LADSPA_Handle Instance);
+
+} LADSPA_Descriptor;
+
+/**********************************************************************/
+
+/* Accessing a Plugin: */
+
+/* The exact mechanism by which plugins are loaded is host-dependent,
+ however all most hosts will need to know is the name of shared
+ object file containing the plugin types. To allow multiple hosts to
+ share plugin types, hosts may wish to check for environment
+ variable LADSPA_PATH. If present, this should contain a
+ colon-separated path indicating directories that should be searched
+ (in order) when loading plugin types.
+
+ A plugin programmer must include a function called
+ "ladspa_descriptor" with the following function prototype within
+ the shared object file. This function will have C-style linkage (if
+ you are using C++ this is taken care of by the `extern "C"' clause
+ at the top of the file).
+
+ A host will find the plugin shared object file by one means or
+ another, find the ladspa_descriptor() function, call it, and
+ proceed from there.
+
+ Plugin types are accessed by index (not ID) using values from 0
+ upwards. Out of range indexes must result in this function
+ returning NULL, so the plugin count can be determined by checking
+ for the least index that results in NULL being returned. */
+
+const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index);
+
+/* Datatype corresponding to the ladspa_descriptor() function. */
+typedef const LADSPA_Descriptor *
+(*LADSPA_Descriptor_Function)(unsigned long Index);
+
+/**********************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LADSPA_INCLUDED */
+
+/* EOF */
diff --git a/pluginhost~/lesser.txt b/pluginhost~/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/pluginhost~/lesser.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 library 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/pluginhost~/makefile b/pluginhost~/makefile
new file mode 100755
index 0000000..6a87da9
--- /dev/null
+++ b/pluginhost~/makefile
@@ -0,0 +1,66 @@
+NAME=dssi~
+CSYM=dssi~
+
+LIBDIR=/usr/local/lib
+PDDIR=$(LIBDIR)/pd
+INSTALLPATH=$(PDDIR)/extra/
+ARCHITECTURE=i386
+DEBUG=0
+
+current: pd_linux
+
+
+# ----------------------- Linux -----------------------
+
+pd_linux: src/$(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+#LINUXCFLAGS = -DPD -O3 -fPIC -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+# Debug
+LINUXCFLAGS = -ggdb -g -DPD -O0 -fPIC -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch -DDEBUG=$(DEBUG)
+
+LINUXINCLUDE = -I/usr/include -I./include
+
+.c.pd_linux:
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -c src/jsearch.c
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -c src/jload.c
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -c src/dssi~.c
+ gcc --export-dynamic -shared -o $(NAME).pd_linux dssi~.o jload.o jsearch.o -lc -lm -llo
+# strip --strip-unneeded $(NAME).pd_linux
+ cp $(NAME).pd_linux ~/pd-externals/
+ rm -f *.o
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: src/$(NAME).pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -arch $(ARCHITECTURE) -O3 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch -L/usr/local/lib/ -DDEBUG=$(DEBUG)
+
+DARWININCLUDE = -I ./ -I ../src -I/usr/local/include/ -I ./include -I/usr/local/include/dssi/
+
+.c.pd_darwin:
+ $(CC) $(DARWINCFLAGS) $(DARWININCLUDE) -c src/jsearch.c
+ $(CC) $(DARWINCFLAGS) $(DARWININCLUDE) -c src/jload.c
+ $(CC) $(DARWINCFLAGS) $(DARWININCLUDE) -c src/dssi~.c
+ $(CC) -arch $(ARCHITECTURE) -bundle -undefined suppress -flat_namespace -llo -o $(NAME).pd_darwin dssi~.o jload.o jsearch.o
+ rm -f *.o
+
+# ----------------------- Generic -----------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
+
+install:
+ cp dssi~.pd_* $(INSTALLPATH)
+ install -d $(PDDIR)/doc/5.reference/dssi/
+ install -m 644 doc/*-help* $(PDDIR)/doc/5.reference/
+ install -m 644 doc/output~.pd $(PDDIR)/doc/5.reference/dssi/
diff --git a/pluginhost~/src/dssi~.c b/pluginhost~/src/dssi~.c
new file mode 100644
index 0000000..f195637
--- /dev/null
+++ b/pluginhost~/src/dssi~.c
@@ -0,0 +1,2537 @@
+/* dssi~ - A DSSI 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
+ *
+ *
+ * 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 <assert.h>
+
+#include "dssi~.h"
+#include "jutils.h"
+
+static t_class *dssi_tilde_class;
+
+/*From dx7_voice_data.c by Sean Bolton */
+
+static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/*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
+ */
+ static 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;
+}
+
+/*
+ * 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;
+}
+
+static 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;
+}
+/*
+ static void dssi_tilde_load_plugin(const char *dll_path, void **dll_handle){
+
+ *dll_handle = dlopen(dll_path, RTLD_NOW | RTLD_LOCAL);
+ if (*dll_handle){
+ post("%s loaded successfully", dll_path);
+ }
+ else
+ post("Failed: %s", dlerror());
+
+ }
+ */
+static void dssi_tilde_port_info(t_dssi_tilde *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];
+#if DEBUG
+ post("Port %d: %s", i, x->descriptor->LADSPA_Plugin->PortNames[i]);
+#endif
+ 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_controlIns;
+ }
+ else if (LADSPA_IS_PORT_OUTPUT(pod)){
+ ++x->plugin_controlOuts;
+ 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)
+ get_port_default(x, i);
+
+ x->port_info[i].name.a_w.w_symbol =
+ gensym ((char *)
+ x->descriptor->LADSPA_Plugin->PortNames[i]);
+ }
+#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_tilde_assign_ports(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_tilde_init_instance(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_quit_path = NULL;
+ x->instances[instance].ui_osc_configure_path = NULL;
+ x->instances[instance].uiNeedsProgramUpdate = 0;
+ x->instances[instance].pendingProgramChange = -1;
+ x->instances[instance].plugin_ProgramCount = 0;
+ x->instances[instance].pendingBankMSB = -1;
+ x->instances[instance].pendingBankLSB = -1;
+ x->instances[instance].ui_hidden = 1;
+ x->instances[instance].ui_show = 0;
+ x->instances[instance].gui_pid = 0;
+#if DEBUG
+ post("Instance %d initialized!", instance);
+#endif
+
+}
+
+static void dssi_tilde_connect_ports(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("Audio Input port %d connected", x->ports_in);
+ post("Audio Output 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("Control Input port %d connected", x->ports_controlIn);
+ post("Control Output port %d connected", x->ports_controlOut);
+#endif
+ }
+ }
+
+#if DEBUG
+ post("ports connected!");
+#endif
+
+}
+
+static void dssi_tilde_activate_plugin(t_dssi_tilde *x, t_int instance){
+
+ if(x->descriptor->LADSPA_Plugin->activate){
+#if DEBUG
+ post("trying to activate instance: %d", instance);
+#endif
+ x->descriptor->LADSPA_Plugin->activate(x->instanceHandles[instance]);
+ }
+#if DEBUG
+ post("plugin activated!");
+#endif
+}
+
+static void dssi_tilde_deactivate_plugin(t_dssi_tilde *x, t_float instance_f){
+
+ t_int instance = (t_int)instance_f;
+ if(x->descriptor->LADSPA_Plugin->deactivate)
+ x->descriptor->LADSPA_Plugin->deactivate(x->instanceHandles[instance]);
+#if DEBUG
+ post("plugin deactivated!");
+#endif
+}
+
+static void osc_error(int num, const char *msg, const char *where)
+{
+ post("dssi~: 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);
+ free((char *)x->instances[instance].pluginPrograms);
+ 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 */
+ /*FIX ?? */
+ 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
+ }
+ }
+ /* No - it should be 0 anyway - dssi_init */
+ /* else
+ x->instances[instance].plugin_ProgramCount = 0;
+ */ }
+}
+
+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 unsigned dssi_tilde_get_parm_number (t_dssi_tilde *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_controlIns) {
+ /* string ok and within range */
+ return (unsigned)num;
+ }
+ else {
+ /* number out of range */
+ return 0;
+ }
+}
+
+static void dssi_tilde_set_control_input_by_index (t_dssi_tilde *x,
+ signed ctrl_input_index,
+ float value,
+ t_int instance)
+{
+ long port, portno;
+
+ if (ctrl_input_index >= x->plugin_controlIns) {
+ post("dssi~: control port number %d is out of range [1, %d]",
+ ctrl_input_index + 1, x->plugin_controlIns);
+ return;
+ }
+
+#if DEBUG
+ post("ctrl input number = %d", ctrl_input_index);
+#endif
+
+
+ port = x->plugin_ControlInPortNumbers[ctrl_input_index];
+
+
+ /* FIX - temporary hack */
+ if(x->is_DSSI)
+ portno =
+ x->instances[instance].plugin_PortControlInNumbers[ctrl_input_index + 1];
+ else
+ portno =
+ x->instances[instance].plugin_PortControlInNumbers[ctrl_input_index];
+#if DEBUG
+ post("Global ctrl input number = %d", ctrl_input_index);
+ post("Global ctrl input value = %.2f", value);
+#endif
+
+
+
+
+ /* set the appropriate control port value */
+ x->plugin_ControlDataInput[portno] = value;
+
+ /* Update the UI if there is one */
+ if(x->is_DSSI){
+ if(x->instances[instance].uiTarget == NULL){
+#if DEBUG
+ post("dssi~: unable to send to NULL target");
+#endif
+ return;
+ }
+ if(x->instances[instance].ui_osc_control_path == NULL){
+#if DEBUG
+ post("dssi~: unable to send to NULL control path");
+#endif
+ return;
+ }
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_control_path, "if", port, value);
+ }
+
+
+}
+
+static void dssi_tilde_set_control_input_by_name (t_dssi_tilde *x,
+ const char* name,
+ float value,
+ t_int instance)
+{
+ unsigned port_index = 0;
+ unsigned ctrl_input_index = 0;
+ int found_port = 0; /* boolean */
+
+ if (name == NULL || strlen (name) == 0) {
+ post("dssi~: 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)
+ {
+ post("dssi~: plugin doesn't have a control input port named \"%s\"",
+ name);
+ return;
+ }
+
+ dssi_tilde_set_control_input_by_index (x, ctrl_input_index, value, instance);
+}
+
+static void dssi_tilde_control (t_dssi_tilde *x,
+ t_symbol* ctrl_name,
+ t_float ctrl_value,
+ t_float instance_f)
+/* Change the value of a named control port of the plug-in */
+{
+ unsigned parm_num = 0;
+ t_int instance = (t_int)instance_f - 1;
+ int n_instances = x->n_instances;
+
+ if (instance > x->n_instances || instance < -1){
+ post("dssi~: control: invalid instance number %d", instance);
+ return;
+ }
+
+#if DEBUG
+ post("Received LADSPA control data for instance %d", instance);
+#endif
+
+ if (ctrl_name->s_name == NULL || strlen (ctrl_name->s_name) == 0) {
+ post("dssi~: control messages must have a name and a value");
+ return;
+ }
+ parm_num = dssi_tilde_get_parm_number (x, ctrl_name->s_name);
+ if (parm_num) {
+ if(instance >= 0)
+ dssi_tilde_set_control_input_by_index (x, parm_num - 1,
+ ctrl_value, instance);
+ else if (instance == -1){
+ while(n_instances--)
+ dssi_tilde_set_control_input_by_index (x, parm_num - 1,
+ ctrl_value, n_instances);
+ }
+ }
+ else {
+ if(instance >= 0)
+ dssi_tilde_set_control_input_by_name (x, ctrl_name->s_name,
+ ctrl_value, instance);
+ else if (instance == -1){
+ while(n_instances--)
+ dssi_tilde_set_control_input_by_name (x,
+ ctrl_name->s_name, ctrl_value, n_instances);
+ }
+ }
+}
+
+static void dssi_tilde_info (t_dssi_tilde *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->control_outlet, gensym ("port"), 7, argv);
+ }
+}
+
+static void dssi_tilde_ladspa_description(t_dssi_tilde *x, t_atom *at,
+ DSSI_Descriptor *psDescriptor){
+ at[0].a_w.w_symbol =
+ gensym ((char*)psDescriptor->LADSPA_Plugin->Name);
+ outlet_anything (x->control_outlet, gensym ("name"), 1, at);
+ at[0].a_w.w_symbol =
+ gensym ((char*)psDescriptor->LADSPA_Plugin->Label);
+ outlet_anything (x->control_outlet, gensym ("label"), 1, at);
+ at[0].a_type = A_FLOAT;
+ at[0].a_w.w_float = psDescriptor->LADSPA_Plugin->UniqueID;
+ outlet_anything (x->control_outlet, 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->control_outlet, gensym ("maker"), 1, at);
+}
+
+static void dssi_tilde_ladspa_describe(const char * pcFullFilename,
+ void * pvPluginHandle,
+ DSSI_Descriptor_Function fDescriptorFunction,
+ void* user_data,
+ int is_DSSI) {
+
+ t_dssi_tilde *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->control_outlet, gensym ("library"), 1, at);
+
+ if(is_DSSI){
+#if DEBUG
+ post("DSSI plugin found by listinfo");
+#endif
+ for (lIndex = 0;
+ (psDescriptor = (DSSI_Descriptor *)
+ fDescriptorFunction(lIndex)) != NULL; lIndex++)
+ dssi_tilde_ladspa_description(x, &at[0], psDescriptor);
+ }
+
+ else if(!is_DSSI)
+ lIndex = 0;
+ do{
+ psDescriptor = ladspa_to_dssi((LADSPA_Descriptor *)fDescriptorFunction(lIndex++));
+ /* psDescriptor = (DSSI_Descriptor *)calloc(1,
+ sizeof(DSSI_Descriptor));
+ ((DSSI_Descriptor *)psDescriptor)->DSSI_API_Version = 1;
+ ((DSSI_Descriptor *)psDescriptor)->LADSPA_Plugin =
+ (LADSPA_Descriptor *)
+ fDescriptorFunction(lIndex++);
+ */
+ if(psDescriptor->LADSPA_Plugin != NULL){
+ dssi_tilde_ladspa_description(x, &at[0], psDescriptor);
+ free((DSSI_Descriptor *)psDescriptor);
+ }
+ else
+ break;
+ } while(1);
+ /* Not needed
+ dlclose(pvPluginHandle);
+ */
+}
+
+static void dssi_tilde_list_plugins (t_dssi_tilde *x) {
+ void* user_data[1];
+ user_data[0] = x;
+ LADSPAPluginSearch(dssi_tilde_ladspa_describe,(void*)user_data);
+}
+
+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_tilde_get_current_program(t_dssi_tilde *x, int instance){
+ int i;
+ t_atom argv[3];
+
+ argv[0].a_type = A_FLOAT;
+ argv[1].a_type = A_FLOAT;
+ argv[2].a_type = A_SYMBOL;
+ i = x->instances[instance].currentProgram;
+
+ argv[0].a_w.w_float = (t_float)instance;
+ argv[1].a_w.w_float = x->instances[instance].pluginPrograms[i].Program;
+ argv[2].a_w.w_symbol =
+ gensym ((char*)x->instances[instance].pluginPrograms[i].Name);
+ outlet_anything (x->control_outlet, gensym ("program"), 3, argv);
+
+}
+
+static void dssi_tilde_program_change(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
+ /* FIX - this is a hack to make text ui work*/
+ if(x->instances[instance].uiTarget)
+ 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;
+ }
+ dssi_tilde_get_current_program(x, instance);
+}
+
+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("dssi~: 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_tilde_program_change(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;
+#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
+ 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
+ if(x->instances[instance].uiTarget){
+ lo_address_free(x->instances[instance].uiTarget);
+ x->instances[instance].uiTarget = NULL;
+ }
+ 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);
+ free(x->instances[instance].ui_osc_quit_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_osc_quit_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;
+ t_dssi_configure_pair *p;
+
+ p = x->configure_buffer_head;
+
+#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_quit_path)
+ free(x->instances[instance].ui_osc_quit_path);
+ x->instances[instance].ui_osc_quit_path = (char *)malloc(strlen(path) + 10);
+ sprintf(x->instances[instance].ui_osc_quit_path, "%s/quit", 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);
+
+ while(p){
+ if(p->instance == instance)
+ dssi_tilde_send_configure(x, p->key,
+ p->value, instance);
+ p = p->next;
+ }
+
+ /* Send current bank/program (-FIX- another race...) */
+ if (x->instances[instance].pendingProgramChange >= 0)
+ dssi_tilde_program_change(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_tilde_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->plugin_basename) + strlen(x->descriptor->LADSPA_Plugin->Label) + strlen("chan00") + 3));
+ sprintf(x->instances[instance].osc_url_path, "%s/%s/chan%02d", x->plugin_basename,
+ 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_tilde_init_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_tilde_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->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);*/
+#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("dssi~: 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;
+ }
+ }
+#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("dssi~: instance %d URL: %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){
+ //pthread_mutex_init(&x->midiEventBufferMutex, NULL);
+ 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("dssi~: note discarded: MIDI data is destined for a channel that doesn't exist");
+ return;
+ }
+
+ t_int time_ref = x->time_ref;
+ t_int mapped;
+
+ pthread_mutex_lock(&x->midiEventBufferMutex);
+
+ mapped = x->channelMap[chan + 1] - 1;
+
+ 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 = mapped;
+ 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 = mapped;
+ 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 = mapped;
+ 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 = mapped;
+ x->midiEventBuf[x->bufWriteIndex].data.control.param = 0;
+ x->midiEventBuf[x->bufWriteIndex].data.control.value = val;
+ break;
+ case SND_SEQ_EVENT_CHANPRESS:
+ x->midiEventBuf[x->bufWriteIndex].data.control.channel = mapped;
+ x->midiEventBuf[x->bufWriteIndex].data.control.param = 0;
+ x->midiEventBuf[x->bufWriteIndex].data.control.value = val;
+ break;
+ case SND_SEQ_EVENT_KEYPRESS:
+ x->midiEventBuf[x->bufWriteIndex].data.note.channel = mapped;
+ x->midiEventBuf[x->bufWriteIndex].data.note.note = param;
+ x->midiEventBuf[x->bufWriteIndex].data.note.velocity = val;
+ break;
+ case SND_SEQ_EVENT_PGMCHANGE:
+ x->instances[mapped].pendingBankMSB = (param - 1) / 128;
+ x->instances[mapped].pendingBankLSB = (param - 1) % 128;
+ x->instances[mapped].pendingProgramChange = val;
+ x->instances[mapped].uiNeedsProgramUpdate = 1;
+#if DEBUG
+ post("pgm chabge received in buffer: MSB: %d, LSB %d, prog: %d",
+ x->instances[mapped].pendingBankMSB, x->instances[mapped].pendingBankLSB, val);
+#endif
+ dssi_tilde_program_change(x, mapped);
+ 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 = mapped;
+ 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, mapped to %d",
+ chan, param, val, mapped);
+#endif
+ x->bufWriteIndex = (x->bufWriteIndex + 1) % EVENT_BUFSIZE;
+ pthread_mutex_unlock(&x->midiEventBufferMutex); /**release mutex*/
+}
+
+static void dssi_tilde_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);
+ 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;
+ }
+#if DEBUG
+ post("initial midi NOTE:, arg1 = %d, arg2 = %d, arg3 = %d, arg4 = %d",ev_type,chan,param,val);
+#endif
+ if(ev_type != 0){
+ if(chan >= 0)
+ MIDIbuf(ev_type, chan, param, val, x);
+ else {
+ while(n_instances--)
+ MIDIbuf(ev_type, n_instances, param, val, x);
+ }
+ }
+ free(msg_type);
+}
+
+static char *dssi_tilde_send_configure(t_dssi_tilde *x, char *key,
+ char *value, t_int instance){
+
+ char *debug;
+
+ debug = x->descriptor->configure(
+ x->instanceHandles[instance],
+ key, value);
+ if(x->instances[instance].uiTarget != NULL && x->is_DSSI)
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_configure_path,
+ "ss", key, value);
+ query_programs(x, instance);
+
+ return debug;
+}
+
+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_tilde_load_gui(x, instance);
+
+ }
+}
+
+static t_int dssi_tilde_configure_buffer(t_dssi_tilde *x, char *key,
+ char *value, t_int instance){
+
+ /*#ifdef BLAH*/
+ t_dssi_configure_pair *current, *p;
+ t_int add_node;
+ add_node = 0;
+ current = x->configure_buffer_head;
+
+ while(current){
+ if(!strcmp(current->key, key) &&
+ current->instance == instance)
+ break;
+ current = current->next;
+ }
+ if(current)
+ free(current->value);
+ else {
+ current = (t_dssi_configure_pair *)malloc(sizeof
+ (t_dssi_configure_pair));
+ current->next = x->configure_buffer_head;
+ x->configure_buffer_head = current;
+ current->key = strdup(key);
+ current->instance = instance;
+ }
+ current->value = strdup(value);
+
+ p = x->configure_buffer_head;
+
+ /*FIX: eventually give ability to query this buffer (to outlet?) */
+#if DEBUG
+ while(p){
+ post("key: %s", p->key);
+ post("val: %s", p->value);
+ post("instance: %d", p->instance);
+ p = p->next;
+ }
+#endif
+ return 0;
+}
+
+static t_int dssi_tilde_configure_buffer_free(t_dssi_tilde *x){
+ t_dssi_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 dssi_tilde_plug (t_dssi_tilde *x, t_symbol* plug_name) {
+ plugin_tilde_ladspa_close_plugin(x);
+ x->plugin_library_filename = NULL;
+ x->plugin_library_filename = plugin_tilde_search_plugin_by_label (x, plug_name->s_name);
+ if (x->plugin_library_filename == NULL)
+ post("plugin~: plugin not found in any library");
+ if (plugin_tilde_open_plugin (x, plug_name->s_name, x->plugin_library_filename,(unsigned long)sys_getsr ()))
+ post("plugin~: Unable to open plugin");
+ }
+ */
+
+static t_int dssi_tilde_reset(t_dssi_tilde *x, t_float instance_f){
+
+ t_int instance = (t_int)instance_f - 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]);
+ }
+ return 0;
+}
+
+static void dssi_tilde_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)
+ {
+#if DEBUG
+ post("plugin~: searching plugin \"%s\"...", full_filename);
+#endif
+ 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++){
+#if DEBUG
+ post("plugin~: label \"%s\"", descriptor->LADSPA_Plugin->Label);
+#endif
+ if (strcasecmp (name, descriptor->LADSPA_Plugin->Label)
+ == 0)
+ {
+ *out_lib_name = strdup (full_filename);
+#if DEBUG
+ post("plugin~: found plugin \"%s\" in library \"%s\"",
+ name, full_filename);
+#endif
+ /* 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 (t_dssi_tilde *x,
+ const char *name)
+{
+ char* lib_name = NULL;
+ void* user_data[2];
+
+ user_data[0] = (void*)(&lib_name);
+ user_data[1] = (void*)name;
+#if DEBUG
+ post("search plugin by label: '%s'\n", name);
+#endif
+
+ lib_name = NULL;
+ LADSPAPluginSearch (dssi_tilde_search_plugin_callback,
+ (void*)user_data);
+
+ /* The callback (allocates and) writes lib_name, if it finds the plugin */
+ return lib_name;
+
+}
+
+static t_int dssi_tilde_dssi_methods(t_dssi_tilde *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (!x->is_DSSI) {
+ post("dssi~: plugin is not a DSSI plugin, operation not supported");
+ return 0;
+ }
+ char *msg_type,
+ *debug,
+ *filename,
+ *filepath,
+ *key,
+ *value,
+ *temp,
+ mydir[MAXPDSTRING];
+ int instance = -1,
+ pathlen,
+ toggle,
+ fd,
+ n_instances = x->n_instances,
+ count,
+ i,
+ chan,
+ maxpatches;
+ 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, *firstpatch;
+ msg_type = (char *)malloc(TYPE_STRING_SIZE);
+ 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;
+ post("dssi~: 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");
+
+ /* FIX: 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{
+ post("dssi~: unable to get file descriptor");
+ }
+
+ /*From dx7_voice_data by Sean Bolton */
+ if(fp == NULL){
+ post("dssi~: 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("dssi~: couldn't get length of patch file: %s",
+ filename);
+ fclose(fp);
+ return 0;
+ }
+ if (filelength == 0) {
+ post("dssi~: patch file has zero length");
+ fclose(fp);
+ return 0;
+ } else if (filelength > 16384) {
+ post("dssi~: patch file is too large");
+ fclose(fp);
+ return 0;
+ }
+ if (!(raw_patch_data = (unsigned char *)
+ malloc(filelength))) {
+ post(
+ "dssi~: couldn't allocate memory for raw patch file");
+ fclose(fp);
+ return 0;
+ }
+ if (fread(raw_patch_data, 1, filelength, fp)
+ != (size_t)filelength) {
+ post("dssi~: short read on patch file: %s", filename);
+ free(raw_patch_data);
+ fclose(fp);
+ return 0;
+ }
+ fclose(fp);
+#if DEBUG
+ post("Patch file length is %ul", filelength);
+#endif
+ /* 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 */
+
+#if DEBUG
+ post("Raw DX7 format patch bank passed");
+#endif
+ 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 &&
+ /*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 */
+
+#if DEBUG
+ post("SYSEX header check passed");
+#endif
+
+ if (filelength != DX7_DUMP_SIZE_BULK ||
+ raw_patch_data[DX7_DUMP_SIZE_BULK - 1] != 0xf7) {
+ post("dssi~: 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("dssi~: 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("dssi~: 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{
+ post("dssi~: %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);
+ post("dssi~: 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"))
+ post("dssi~: %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, "remap")) {
+ /* remap channel to instance */
+ for(i = 0; i < x->n_instances && i < 128; i++){
+ chan = (int)atom_getfloatarg(1 + i, argc, argv);
+ post("dssi~: remapped MIDI channel %d to %d", 1+i, chan);
+ x->channelMap[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 = dssi_tilde_send_configure(
+ x, key, value, n_instances);
+ dssi_tilde_configure_buffer(x, key, value, n_instances);
+ }
+ }
+ /*FIX: Put some error checking in here to make sure instance is valid*/
+ else{
+
+ debug = dssi_tilde_send_configure(x, key, value, instance);
+ dssi_tilde_configure_buffer(x, key, value, instance);
+ }
+ }
+#if DEBUG
+ post("The plugin returned %s", debug);
+#endif
+ free(msg_type);
+ free(patchbuf);
+
+ return 0;
+}
+
+static void dssi_tilde_bang(t_dssi_tilde *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->control_outlet, gensym ("running"), 3, at);
+}
+
+static t_int *dssi_tilde_perform(t_int *w)
+{
+ int N = (t_int)(w[2]);
+ t_dssi_tilde *x = (t_dssi_tilde *)(w[1]);
+ t_float **inputs = (t_float **)(&w[3]);
+ t_float **outputs = (t_float **)(&w[3] + x->plugin_ins);
+ int i, n, timediff, framediff, instance = 0;
+ /*See comment for dssi_tilde_plug_plugin */
+ if(x->dsp){
+ x->dsp_loop = 1;
+
+ for(i = 0; i < x->plugin_ins; i++)
+ memcpy(x->plugin_InputBuffers[i], inputs[i], N *
+ sizeof(LADSPA_Data));
+
+ for (i = 0; i < x->n_instances; i++)
+ x->instanceEventCounts[i] = 0;
+
+ 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(
+ "dssi~: %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("dssi~: 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->descriptor->run_synth(x->instanceHandles[i],
+ (unsigned long)N, x->instanceEventBuffers[i],
+ x->instanceEventCounts[i]);
+ i++;
+ }
+ else if (x->instanceHandles[i] &&
+ x->descriptor->LADSPA_Plugin->run){
+ x->descriptor->LADSPA_Plugin->run
+ (x->instanceHandles[i], N);
+ i++;
+ }
+ }
+
+
+ for(i = 0; i < x->plugin_outs; i++)
+ memcpy(outputs[i], (t_float *)x->plugin_OutputBuffers[i], N *
+ sizeof(LADSPA_Data));
+
+ /*
+ for(i = 0; i < x->plugin_outs; i++)
+ memcpy(x->outlets[i], (t_outlet *)x->plugin_OutputBuffers[i], N *
+ sizeof(LADSPA_Data));*/
+ x->dsp_loop = 0;
+ }
+ return w + (x->plugin_ins + x->plugin_outs + 3);
+}
+
+static void dssi_tilde_dsp(t_dssi_tilde *x, t_signal **sp)
+{
+ if(x->n_instances){
+
+
+ t_int *dsp_vector, i, N, 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(dssi_tilde_perform, M, dsp_vector);
+
+
+ /* int n, m;
+
+ t_float **outlets;
+ t_float **inlets;
+
+ for(n = 0, m = 1; n < x->plugin_ins; n++, m++)
+ inlets[n] = sp[m]->s_vec;
+ for(n = 0; n < x->plugin_outs; n++, ++m)
+ outlets[n] = sp[m]->s_vec;
+
+*/ /*
+
+ t_float **outlets = (t_float **)x->outlets;
+ t_float **inlets = (t_float **)x->inlets;
+
+ m = 1;
+
+ for(n = 0; n < x->plugin_ins; n++)
+ *inlets++ = sp[m++]->s_vec;
+ for(n = 0; n < x->plugin_outs; n++)
+ *outlets++ = sp[m++]->s_vec;
+ */ }
+ /* dsp_add(dssi_tilde_perform, 2, sp[0]->s_n, x); */
+
+}
+
+static void dssi_tilde_quit_plugin(t_dssi_tilde *x){
+
+ t_int i, instance;
+ for(instance = 0; instance < x->n_instances; instance++) {
+ if(x->instances[instance].uiTarget && x->is_DSSI){
+ lo_send(x->instances[instance].uiTarget,
+ x->instances[instance].ui_osc_quit_path, "");
+ lo_address_free(x->instances[instance].uiTarget);
+ x->instances[instance].uiTarget = NULL;
+ }
+ /* 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]);
+ }*/
+ dssi_tilde_deactivate_plugin(x, (t_float)instance);
+ /* } */
+ if (x->descriptor->LADSPA_Plugin &&
+ x->descriptor->LADSPA_Plugin->cleanup) {
+ x->descriptor->LADSPA_Plugin->cleanup
+ (x->instanceHandles[instance]);
+ }
+ }
+}
+
+static void dssi_tilde_free_plugin(t_dssi_tilde *x){
+
+ t_int i, instance;
+ if(x->plugin_label != NULL)
+ free((char *)x->plugin_label);
+ if(x->plugin_handle != NULL){
+ instance = x->n_instances;
+ free((LADSPA_Handle)x->instanceHandles);
+ free(x->plugin_ControlInPortNumbers);
+ free((t_float *)x->plugin_InputBuffers);
+ free(x->instanceEventCounts);
+ free(x->plugin_ControlDataInput);
+ free(x->plugin_ControlDataOutput);
+
+ while(instance--){
+
+ if(x->instances[instance].gui_pid){
+#if DEBUG
+ post("Killing GUI process PID = %d", x->instances[instance].gui_pid);
+#endif
+ kill(x->instances[instance].gui_pid, SIGINT);
+ }
+ if (x->instances[instance].pluginPrograms) {
+ for (i = 0; i <
+ x->instances[instance].plugin_ProgramCount; i++)
+ free((void *)
+ x->instances[instance].pluginPrograms[i].Name);
+ free((char *)x->instances[instance].pluginPrograms);
+ x->instances[instance].pluginPrograms = NULL;
+ x->instances[instance].plugin_ProgramCount = 0;
+ }
+ free(x->instanceEventBuffers[instance]);
+ if(x->is_DSSI){
+ 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].ui_osc_quit_path);
+ free(x->instances[instance].osc_url_path);
+ }
+ free(x->instances[instance].plugin_PortControlInNumbers);
+ if(x->plugin_outs)
+ free(x->plugin_OutputBuffers[instance]);
+ }
+ if(x->is_DSSI){
+ if(x->project_dir != NULL)
+ free(x->project_dir);
+ free(x->osc_url_base);
+ dssi_tilde_configure_buffer_free(x);
+ }
+ free((snd_seq_event_t *)x->instanceEventBuffers);
+ free(x->instances);
+ free((t_float *)x->plugin_OutputBuffers);
+
+ /*sleep(1);*/
+ if(x->plugin_ins){
+ for(i = 0; i < x->plugin_ins; i++)
+ inlet_free((t_inlet *)x->inlets[i]);
+ freebytes(x->inlets, x->plugin_ins * sizeof(t_inlet *));
+ }
+
+ if(x->plugin_outs){
+ for(i = 0; i < x->plugin_outs; i++)
+ outlet_free((t_outlet *)x->outlets[i]);
+ freebytes(x->outlets, x->plugin_outs * sizeof(t_outlet *));
+ }
+ if(x->control_outlet)
+ outlet_free(x->control_outlet);
+ if(x->plugin_basename)
+ free(x->plugin_basename);
+ if(x->port_info)
+ free(x->port_info);
+ }
+}
+
+static void dssi_tilde_init_plugin(t_dssi_tilde *x){
+
+ x->project_dir = NULL;
+ x->configure_buffer_head = NULL;
+ x->outlets = NULL;
+ x->inlets = NULL;
+ x->control_outlet = NULL;
+ x->plugin_handle = NULL;
+ x->plugin_full_path = NULL;
+ x->plugin_label = NULL;
+ x->plugin_basename = NULL;
+ x->osc_url_base = NULL;
+ x->plugin_ControlDataInput = x->plugin_ControlDataOutput = NULL;
+ x->plugin_InputBuffers = x->plugin_OutputBuffers = NULL;
+ x->plugin_ControlInPortNumbers = NULL;
+ x->port_info = NULL;
+ x->descriptor = NULL;
+ x->instanceEventCounts = NULL;
+ x->instances = NULL;
+ x->instanceHandles = NULL;
+ x->is_DSSI = 0;
+ x->n_instances = 0;
+ x->dsp = 0;
+ x->dsp_loop = 0;
+ x->plugin_ins = x->plugin_outs =
+ x->plugin_controlIns = x->plugin_controlOuts = 0;
+ x->ports_in = x->ports_out = x->ports_controlIn = x->ports_controlOut = 0;
+ x->bufWriteIndex = x->bufReadIndex = 0;
+
+}
+
+static void *dssi_tilde_load_plugin(t_dssi_tilde *x, t_int argc, t_atom *argv){
+ char *plugin_basename = NULL,
+ *plugin_full_path = NULL,
+ *tmpstr,
+ *plugin_label,
+ plugin_dir[MAXPDSTRING];
+
+#if DEBUG
+ post("argc = %d", argc);
+#endif
+ int i,
+ stop,
+ fd;
+ size_t pathlen;
+
+ stop = 0;
+
+ if (argc){
+ 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);
+#if DEBUG
+ post("plugin path = %s", plugin_full_path);
+ post("plugin name = %s", x->plugin_label);
+#endif
+
+ if(plugin_full_path != NULL){
+ /* First 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_full_path = (char *)plugin_full_path;
+ /* If that didn't work, 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) {
+#if DEBUG
+ post("plugin directory is %s, filename is %s",
+ plugin_dir, plugin_basename);
+#endif
+ 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 {
+ x->plugin_handle = loadLADSPAPluginLibrary(plugin_full_path);
+ }
+
+ if (x->plugin_handle == NULL)
+ error("dssi~: can't find plugin in Pd paths, "
+ "try using [declare] to specify the path.");
+
+ }
+
+ if (x->plugin_handle != NULL){
+ 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")){
+ plugin_basename = strtok((char *)tmpstr, "/");
+ while(strstr(plugin_basename, ".so") == NULL)
+ plugin_basename = strtok(NULL, "/");
+ x->plugin_basename = strdup(plugin_basename);
+#if DEBUG
+ post("plugin basename = %s", x->plugin_basename);
+#endif
+ }
+ else{
+ post("dssi~: invalid plugin path, must end in .so");
+ return (void *) x;
+ }
+ }
+ free(tmpstr);
+ if(x->desc_func = (DSSI_Descriptor_Function)dlsym(x->plugin_handle, "dssi_descriptor")){
+ x->is_DSSI = 1;
+ 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 = 0;
+ 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;
+
+
+#if DEBUG
+ post("n_instances = %d", x->n_instances);
+#endif
+ x->instances = (t_dssi_instance *)malloc(sizeof(t_dssi_instance) *
+ x->n_instances);
+
+ if(x->descriptor){
+#if DEBUG
+ post("%s loaded successfully!",
+ x->descriptor->LADSPA_Plugin->Label);
+#endif
+
+ /*allocate memory for port_info*/
+
+ x->port_info = (t_port_info *)malloc
+ (x->descriptor->LADSPA_Plugin->PortCount *
+ sizeof(t_port_info));
+
+ dssi_tilde_port_info(x);
+ dssi_tilde_assign_ports(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("dssi~: instantiation of instance %d failed", i);
+ stop = 1;
+ break;
+ }
+ }
+ if(!stop){
+ for(i = 0;i < x->n_instances; i++)
+ dssi_tilde_init_instance(x, i);
+ for(i = 0;i < x->n_instances; i++)
+ dssi_tilde_connect_ports(x, i);
+ for(i = 0;i < x->n_instances; i++)
+ dssi_tilde_activate_plugin(x, i);
+
+ if(x->is_DSSI){
+ for(i = 0;i < x->n_instances; i++)
+ dssi_tilde_osc_setup(x, i);
+#if LOADGUI
+ for(i = 0;i < x->n_instances; i++)
+ dssi_tilde_load_gui(x, i);
+#endif
+ for(i = 0;i < x->n_instances; i++)
+ dssi_tilde_init_programs(x, i);
+
+ for(i = 0; i < x->n_instances && i < 128; i++){
+ x->channelMap[i] = i;
+ }
+ }
+ }
+ }
+ }
+ else
+ post("dssi~: error: plugin not loaded");
+ }
+ else
+ post("dssi~: no arguments given, please supply a path");
+
+ x->control_outlet =
+ outlet_new (&x->x_obj, gensym("control"));
+
+ if (x->plugin_handle != NULL){
+ 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);
+ /* x->outlets =
+ (t_float **)calloc(x->plugin_outs,
+ sizeof(t_float *));
+ */
+ }
+ else
+ post("dssi~: error: 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);
+ /* x->inlets =
+ (t_float **)calloc(x->plugin_ins,
+ sizeof(t_float *));
+ */
+ }
+ else
+ post("dssi~: error: plugin has no inputs");
+
+ x->dsp = 1;
+ post("dssi~: %d instances of %s, ready.", x->n_instances,
+ x->plugin_label);
+ }
+ else
+ post("dssi~: error: no plugin handle");
+
+ return (void *)x;
+}
+
+
+/* This method is currently buggy. PD's inlet/outlet handling seems buggy if you try to create ins/outs on the fly. Needs further investigation ...*/
+static void dssi_tilde_plug_plugin(t_dssi_tilde *x, t_symbol *s, int argc, t_atom *argv){
+
+ x->dsp = 0;
+ dssi_tilde_quit_plugin(x);
+ while(1){
+ if(!x->dsp_loop){
+ dssi_tilde_free_plugin(x);
+ break;
+ }
+ }
+ dssi_tilde_init_plugin(x);
+ dssi_tilde_load_plugin(x, argc, argv);
+}
+
+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("\n========================================\ndssi~: DSSI/LADSPA host - version %.2f\n========================================\n", VERSION);
+
+ dssi_tilde_init_plugin(x);
+
+ x->sr = (t_int)sys_getsr();
+ x->sr_inv = 1 / (t_float)x->sr;
+ x->time_ref = (t_int)clock_getlogicaltime;
+ x->blksize = sys_getblksize();
+ x->dsp = 0;
+ x->x_canvas = canvas_getcurrent();
+
+ pthread_mutex_init(&x->midiEventBufferMutex, NULL);
+ return dssi_tilde_load_plugin(x, argc, argv);
+
+}
+
+static void dssi_tilde_free(t_dssi_tilde *x){
+
+#if DEBUG
+ post("Calling dssi_tilde_free");
+#endif
+
+ dssi_tilde_quit_plugin(x);
+ dssi_tilde_free_plugin(x);
+
+}
+
+static void dssi_tilde_sigchld_handler(int sig) {
+ wait(NULL);
+}
+
+void dssi_tilde_setup(void) {
+
+ dssi_tilde_class = class_new(gensym("dssi~"), (t_newmethod)dssi_tilde_new,
+ (t_method)dssi_tilde_free, sizeof(t_dssi_tilde), 0, A_GIMME, 0);
+ class_addlist(dssi_tilde_class, dssi_tilde_list);
+ class_addbang(dssi_tilde_class, dssi_tilde_bang);
+ class_addmethod(dssi_tilde_class,
+ (t_method)dssi_tilde_dsp, gensym("dsp"), 0);
+ class_addmethod(dssi_tilde_class, (t_method)dssi_tilde_dssi_methods,
+ gensym("dssi"), A_GIMME, 0);
+ class_addmethod (dssi_tilde_class,(t_method)dssi_tilde_control,
+ gensym ("control"),A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod (dssi_tilde_class,(t_method)dssi_tilde_info,
+ gensym ("info"),0);
+ class_addmethod (dssi_tilde_class,(t_method)dssi_tilde_list_plugins,
+ gensym ("listplugins"),0);
+ class_addmethod (dssi_tilde_class,(t_method)dssi_tilde_reset,
+ gensym ("reset"), A_DEFFLOAT, 0);
+ class_addmethod (dssi_tilde_class,(t_method)dssi_tilde_plug_plugin,
+ gensym ("plug"),A_GIMME,0);
+ /* class_addmethod (dssi_tilde_class,(t_method)dssi_tilde_activate_plugin,
+ gensym ("activate"),A_DEFFLOAT - 1,0);
+ class_addmethod (dssi_tilde_class,(t_method)dssi_tilde_deactivate_plugin,
+ gensym ("deactivate"),A_DEFFLOAT - 1,0);*/
+ class_sethelpsymbol(dssi_tilde_class, gensym("dssi-help"));
+ CLASS_MAINSIGNALIN(dssi_tilde_class, t_dssi_tilde, f);
+ signal(SIGCHLD, dssi_tilde_sigchld_handler);
+}
+
+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/pluginhost~/src/dssi~.h b/pluginhost~/src/dssi~.h
new file mode 100644
index 0000000..6aadb85
--- /dev/null
+++ b/pluginhost~/src/dssi~.h
@@ -0,0 +1,183 @@
+/* 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>
+#include <string.h>
+#include <stdlib.h> /*for exit()*/
+#include <sys/types.h> /* for fork() */
+#include <signal.h> /* for kill() */
+#include <sys/wait.h> /* for wait() */
+#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.99
+#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 ASCII_t 116
+#define ASCII_a 97
+
+#define LOADGUI 0 /* FIX: depracate this */
+#ifdef DEBUG
+#define CHECKSUM_PATCH_FILES_ON_LOAD 1
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+
+/*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;
+ char *ui_osc_quit_path;
+
+ int *plugin_PortControlInNumbers; /*not sure if this should go here?*/
+
+ char *osc_url_path;
+ pid_t gui_pid;
+
+} t_dssi_instance;
+
+struct dssi_configure_pair {
+ t_int instance;
+ char *key,
+ *value;
+ struct dssi_configure_pair *next;
+};
+
+typedef struct dssi_configure_pair t_dssi_configure_pair;
+
+typedef struct _port_info {
+ t_atom type,
+ data_type,
+ name,
+ lower_bound,
+ upper_bound,
+ p_default;
+} t_port_info;
+
+typedef struct _dssi_tilde {
+ t_object x_obj;
+ t_int is_DSSI;
+ char *plugin_label;
+ char *plugin_full_path; /*absolute path to plugin */
+ t_canvas *x_canvas; /* pointer to the canvas the object is instantiated on */
+ void *plugin_handle;
+ char *project_dir; /* project dircetory */
+ LADSPA_Handle *instanceHandles; /*was handle*/
+ t_dssi_instance *instances;
+ int n_instances;
+ unsigned long *instanceEventCounts;
+ unsigned char channelMap[128];
+ 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;
+ DSSI_Descriptor *descriptor;
+
+ t_port_info *port_info;
+
+ 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 *plugin_basename;
+
+ t_int time_ref; /*logical time reference */
+ t_int sr;
+ t_float sr_inv;
+ t_int blksize;
+ t_float f;
+
+ t_outlet **outlets;
+ t_inlet **inlets;
+ t_outlet *control_outlet;
+
+ t_dssi_configure_pair *configure_buffer_head;
+
+ t_int dsp; /* boolean dsp setting */
+ t_int dsp_loop;
+
+} t_dssi_tilde;
+
+static char *dssi_tilde_send_configure(t_dssi_tilde *x, char *key,
+ char *value, t_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);
+
+
diff --git a/pluginhost~/src/jload.c b/pluginhost~/src/jload.c
new file mode 100644
index 0000000..1672b91
--- /dev/null
+++ b/pluginhost~/src/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 <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*****************************************************************************/
+
+#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
new file mode 100644
index 0000000..593c6f5
--- /dev/null
+++ b/pluginhost~/src/jsearch.c
@@ -0,0 +1,154 @@
+/* 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 <dirent.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*****************************************************************************/
+
+#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;
+ int is_DSSI = 0;
+
+ 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 = 0;
+
+ else if(fDescriptorFunction = (DSSI_Descriptor_Function)dlsym(pvPluginHandle,
+ "dssi_descriptor"))
+ is_DSSI = 1;
+
+ 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
new file mode 100644
index 0000000..fdf718f
--- /dev/null
+++ b/pluginhost~/src/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 */