From e7001842641982a2698f759aa8014aacda6ce568 Mon Sep 17 00:00:00 2001 From: "Kjetil S. Matheussen" Date: Thu, 8 Jan 2004 14:55:24 +0000 Subject: First commit of k_vst~, k_guile and k_cext svn path=/trunk/externals/k_vst~/; revision=1253 --- Makefile | 38 +++ README | 26 ++ abyss.pd | 12 + config.h | 63 +++++ help-k_vst~.pd | 25 ++ help2-k_vst~.pd | 77 ++++++ k_vst~.c | 812 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugin~.h | 189 +++++++++++++ plugin~_ladspa.h | 108 ++++++++ plugin~_vst.c | 571 ++++++++++++++++++++++++++++++++++++++ plugin~_vst.h | 108 ++++++++ version.h | 28 ++ vstutils.h | 50 ++++ 13 files changed, 2107 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 abyss.pd create mode 100644 config.h create mode 100644 help-k_vst~.pd create mode 100644 help2-k_vst~.pd create mode 100644 k_vst~.c create mode 100644 plugin~.h create mode 100644 plugin~_ladspa.h create mode 100644 plugin~_vst.c create mode 100644 plugin~_vst.h create mode 100644 version.h create mode 100644 vstutils.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..08b004d --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ + + + +NAME=k_vst~ +CSYM=k_vst_tilde + +current: pd_linux + + +# ----------------------- LINUX i386 ----------------------- + +pd_linux: $(NAME).pd_linux + +.SUFFIXES: .pd_linux + +LINUXCFLAGS = -DPD -DUNIX -DICECAST -O2 -funroll-loops -fomit-frame-pointer \ + -Wall -W -Wno-shadow -Wstrict-prototypes \ + -Wno-unused -Wno-parentheses -Wno-switch #-Werror + +LINUXINCLUDEPATH=../../src +LINUXINCLUDE = -I$(LINUXINCLUDEPATH) -I../../vstserver/include + +.c.pd_linux: + cc $(LINUXCFLAGS) $(LINUXINCLUDE) -I/site/include/wine -c $(NAME).c -I../include -DPLUGIN_TILDE_USE_VST -DPLUGIN_DEBUG -DPLUGIN_TILDE_VERBOSE + cc $(LINUXCFLAGS) $(LINUXINCLUDE) -I/site/include/wine -c plugin~_vst.c -I../include -DPLUGIN_TILDE_USE_VST -DPLUGIN_DEBUG -DPLUGIN_TILDE_VERBOSE + + ld -export_dynamic k_vst~.o plugin~_vst.o -shared -o $(NAME).pd_linux -lc -lm -L/usr/local/lib -L../../vstserver -lvst + strip --strip-unneeded $*.pd_linux + rm -f $*.o ../$*.pd_linux + ln -s k_vst~/$*.pd_linux .. + +# ---------------------------------------------------------- + +install: + cp help-*.pd ../../doc/5.reference + +clean: + rm -f *.o *.pd_* so_locations diff --git a/README b/README new file mode 100644 index 0000000..40c167d --- /dev/null +++ b/README @@ -0,0 +1,26 @@ + +0.2.5 -> 0.2.6 +-Code to allow space in dll names added. Code made by Thomas Charbonnel. + Also updated the help2 patch to use space in dll name. + +0.2.4 -> 0.2.5 +-New midicommands: "ctl", "pitchbend", "aftertouch", "prg", "noteon" + and "noteoff". Code made by Thomas Charbonnel +-Made a better help patch. + +0.2.3 -> 0.2.4 +- Added support for VST effect/synth programs; these may now be changed with + the 'program' message and a program number. (added by acb) + See the help2 example patch. + +V0.2.1 -> 0.2.3: +-Added simple noteon and noteoff messages for vst instruments. + See help5-k_vst~.pd. + +Changes from v0.2.1 -> 0.2.2: +-Added opengui and closegui commands. + + +See comment in the top of the file k_vst~ and the +file org/README. + diff --git a/abyss.pd b/abyss.pd new file mode 100644 index 0000000..8ea4026 --- /dev/null +++ b/abyss.pd @@ -0,0 +1,12 @@ +#N canvas 262 30 450 300 10; +#X obj 131 111 k_vst~ abyss; +#X msg 59 59 print; +#X msg 131 68 opengui; +#X obj 197 68 adc~; +#X obj 172 147 dac~; +#X connect 0 1 4 0; +#X connect 0 2 4 1; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 3 0 0 1; +#X connect 3 1 0 2; diff --git a/config.h b/config.h new file mode 100644 index 0000000..96c2f17 --- /dev/null +++ b/config.h @@ -0,0 +1,63 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: config.h,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* plug-in architecture config */ + +#if 0 +#ifdef __linux__ /* FIXME? */ +#define PLUGIN_TILDE_USE_LADSPA 1 +#else +#define PLUGIN_TILDE_USE_LADSPA 0 +#endif +#ifdef WIN32 +#define PLUGIN_TILDE_USE_VST 1 +#else +#define PLUGIN_TILDE_USE_VST 0 +#endif +#endif + + /* make sure something was selected */ +#if (PLUGIN_TILDE_USE_LADSPA == 0) && (PLUGIN_TILDE_USE_VST == 0) +#error Either PLUGIN_TILDE_USE_LADSPA or PLUGIN_TILDE_USE_VST must be positive +#endif + +/* print debug information */ +#define PLUGIN_TILDE_DEBUG 0 + +/* print "useful" information */ +#define PLUGIN_TILDE_VERBOSE 0 + +/* force out-of-place processing */ +#define PLUGIN_TILDE_FORCE_OUTOFPLACE 0 + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CONFIG_H__ */ +/* EOF */ diff --git a/help-k_vst~.pd b/help-k_vst~.pd new file mode 100644 index 0000000..eb57407 --- /dev/null +++ b/help-k_vst~.pd @@ -0,0 +1,25 @@ +#N canvas 55 404 825 453 10; +#X msg 20 138 aftertouch ; +#X msg 23 99 pitchbend ; +#X msg 22 177 prg ; +#X msg 19 221 noteon ; +#X msg 24 59 ctl ; +#X obj 20 254 noteoff ; +#X text 25 20 Midi commands:; +#X text 25 35 --------------; +#X text 280 25 GUI commands; +#X text 281 38 -------------; +#X msg 291 72 opengui; +#X msg 293 111 closegui; +#X text 495 17 Control value commands; +#X msg 493 107 control / ; +#X msg 493 62 control ; +#X text 287 184 Misc. commands; +#X text 286 198 ---------------; +#X msg 288 226 reset; +#X msg 289 260 print; +#X text 492 202 -----------------; +#X msg 497 223 program ; +#X msg 497 262 programname ; +#X text 490 185 Program commands; +#X obj 234 376 k_vst~ an_effect_or_softsynth.dll; diff --git a/help2-k_vst~.pd b/help2-k_vst~.pd new file mode 100644 index 0000000..585e5e4 --- /dev/null +++ b/help2-k_vst~.pd @@ -0,0 +1,77 @@ +#N canvas 531 498 450 300 10; +#X text 281 30 mda_JX10 is available from http://www.mda-vst.com/; +#X msg 118 152 print; +#X msg 24 155 program \$1; +#X floatatom 26 120 5 0 63; +#X obj 242 250 dac~; +#X obj 178 70 bng 15 250 50 0 empty empty empty 0 -6 0 8 -233017 -233017 +-1; +#N canvas 0 0 559 288 playscale 0; +#X obj 60 42 inlet; +#X obj 63 258 outlet; +#X text 122 41 <- bang here; +#X text 127 264 <- noteon/noteoff events go here; +#X msg 65 172 noteoff 48; +#X obj 79 100 delay 400; +#X obj 154 100 delay 800; +#X obj 234 100 delay 1200; +#X msg 148 172 noteoff 52; +#X msg 234 172 noteoff 55; +#X msg 33 201 noteon 48 100; +#X msg 135 201 noteon 52 100; +#X msg 239 201 noteon 55 100; +#X obj 312 100 delay 1600; +#X obj 395 100 delay 2000; +#X msg 339 201 noteon 59 100; +#X msg 325 172 noteoff 59; +#X msg 442 201 noteon 60 100; +#X msg 413 172 noteoff 60; +#X obj 132 126 delay 760; +#X obj 63 126 delay 360; +#X obj 210 126 delay 1160; +#X obj 298 127 delay 1560; +#X text 532 270 acb; +#X connect 0 0 10 0; +#X connect 0 0 6 0; +#X connect 0 0 7 0; +#X connect 0 0 13 0; +#X connect 0 0 14 0; +#X connect 0 0 19 0; +#X connect 0 0 5 0; +#X connect 0 0 20 0; +#X connect 0 0 21 0; +#X connect 0 0 22 0; +#X connect 4 0 1 0; +#X connect 5 0 11 0; +#X connect 6 0 12 0; +#X connect 7 0 15 0; +#X connect 8 0 1 0; +#X connect 9 0 1 0; +#X connect 10 0 1 0; +#X connect 11 0 1 0; +#X connect 12 0 1 0; +#X connect 13 0 17 0; +#X connect 14 0 18 0; +#X connect 15 0 1 0; +#X connect 16 0 1 0; +#X connect 17 0 1 0; +#X connect 18 0 1 0; +#X connect 19 0 8 0; +#X connect 20 0 4 0; +#X connect 21 0 9 0; +#X connect 22 0 16 0; +#X restore 179 105 pd playscale; +#X msg 70 196 reset; +#X text 64 72 Click to hear->; +#X msg 316 106 \; pd dsp 1; +#X msg 315 150 \; pd dsp 0; +#X text 31 35 Select preset below | | | V; +#X obj 155 188 k_vst~ mda JX10; +#X connect 1 0 12 0; +#X connect 2 0 12 0; +#X connect 3 0 2 0; +#X connect 5 0 6 0; +#X connect 6 0 12 0; +#X connect 7 0 12 0; +#X connect 12 1 4 0; +#X connect 12 2 4 1; diff --git a/k_vst~.c b/k_vst~.c new file mode 100644 index 0000000..0353ef5 --- /dev/null +++ b/k_vst~.c @@ -0,0 +1,812 @@ +/* + + k_vst~, a Pd tilde object for hosting VST plug-ins. + + This is really just the plugin~ source made by Jarno Seppänen, + but with a few lines changed (very few that is) to make it + work with vst-plugins using the vstlib. + + The name was changed from plugin~ to k_vst~ to avoid nameclash + with the plugin~ object running ladspa plugins. + + This object is for i386 non-windows (ie. linux/freebsd) only. + + Copyright (C) 2002 Kjetil S. Matheussen / Notam, + k.s.matheussen@notam02.no + + VST program change code made by Andrew C. Bulhak (acb at dev.null.org) + + MIDI code by Thomas Charbonnel . + + Code to allow space in dll names also made by Thomas Charbonnel . + + +------------------ + + plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: k_vst~.c,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" + +#include +#include +#include +#include + +#include "plugin~.h" +#include "plugin~_ladspa.h" +#include "plugin~_vst.h" +#include "version.h" + +#define AEFFECTX_H_LINUXWORKAROUND +#include "vst/aeffectx.h" + +#if PLUGIN_TILDE_USE_LADSPA +#define PLUGIN_TILDE_BRAND "LADSPA" +#endif +#if PLUGIN_TILDE_USE_VST +#define PLUGIN_TILDE_BRAND "VST" +#endif + +static t_class* plugin_tilde_class = NULL; + + +static char valid_channel (float ch) { + if (ch < 1.) { + return 0; + } else if (ch > 16.) { + return 15; + } else { + return (char)(ch-1); + } +} + +static void send_midi_to_plugin ( + Pd_Plugin_Tilde* x, + char data0, + char data1, + char data2 + ) +{ + struct VstMidiEvent das_event; + struct VstMidiEvent *pevent=&das_event; + + struct VstEvents events; + + pevent->type = kVstMidiType; + pevent->byteSize = 24; + pevent->deltaFrames = 0; + pevent->flags = 0; + pevent->detune = 0; + pevent->noteLength = 0; + pevent->noteOffset = 0; + pevent->reserved1 = 0; + pevent->reserved2 = 0; + pevent->noteOffVelocity = 0; + pevent->midiData[0] = data0; + pevent->midiData[1] = data1; + pevent->midiData[2] = data2; + pevent->midiData[3] = 0; + + + events.numEvents = 1; + events.reserved = 0; + events.events[0]=(VstEvent*)pevent; + + x->plugin.vst.instance->dispatcher( + x->plugin.vst.instance, + effProcessEvents, 0, 0, &events, 0.0f + ); + +} + +static void plugin_tilde_ctl ( + Pd_Plugin_Tilde* x, + t_float ctlnum, + t_float ctlval, + t_float ctlchan + ) +{ + send_midi_to_plugin(x, 0xb0 | valid_channel(ctlchan), (char)ctlnum, (char)ctlval); +} + +static void plugin_tilde_pitchbend ( + Pd_Plugin_Tilde* x, + t_float pitchvalue, + t_float pitchchan + ) +{ + send_midi_to_plugin(x, 0xe0 | valid_channel(pitchchan), (((int)pitchvalue)>>7) & 127, (int)pitchvalue & 127); +} + +static void plugin_tilde_aftertouch ( + Pd_Plugin_Tilde* x, + t_float atvalue, + t_float atchan + ) +{ + send_midi_to_plugin(x, 0xa0 | valid_channel(atchan), (char)atvalue, 0); +} + + + +static void plugin_tilde_prg ( + Pd_Plugin_Tilde* x, + t_float prgnum, + t_float prgchan + ) +{ + send_midi_to_plugin(x, 0xc0 | valid_channel(prgchan), (char)prgnum, 0); +} + + + +static void plugin_tilde_noteon ( + Pd_Plugin_Tilde* x, + t_float notenum, + t_float notevel, + t_float notechan + ) +{ + send_midi_to_plugin(x, 0x90 | valid_channel(notechan), (char)notenum, (char)notevel); +} + +static void plugin_tilde_noteoff( + Pd_Plugin_Tilde* x, + t_float notenum, + t_float notechan + ) +{ + send_midi_to_plugin(x, 0x90 | valid_channel(notechan), (char)notenum, 0); +} + + +void +k_vst_tilde_setup (void) +{ + /* Make a new Pd class with 2 string creation parameters */ + plugin_tilde_class = class_new (gensym ("k_vst~"), + (t_newmethod)plugin_tilde_new, + (t_method)plugin_tilde_free, + sizeof (Pd_Plugin_Tilde), + 0, + A_GIMME, 0); + assert (plugin_tilde_class != NULL); + + /* Let's be explicit in not converting the signals in any way */ + assert (sizeof (float) == sizeof (t_float)); +#if PLUGIN_TILDE_USE_LADSPA + assert (sizeof (float) == sizeof (LADSPA_Data)); +#endif + + /* Set the callback for DSP events; this is a standard Pd message */ + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_dsp, + gensym ("dsp"), + 0); + + /* Set the callback for "control" messages in the first inlet; + this is a message of our own for changing LADSPA control + ports/VST parameters */ + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_ctl, + gensym ("ctl"), + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_pitchbend, + gensym ("pitchbend"), + A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_aftertouch, + gensym ("aftertouch"), + A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_prg, + gensym ("prg"), + A_DEFFLOAT, A_DEFFLOAT, 0); + + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_noteon, + gensym ("noteon"), + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_noteoff, + gensym ("noteoff"), + A_DEFFLOAT, A_DEFFLOAT, 0); + + /* Set the callback for "control" messages in the first inlet; + this is a message of our own for changing LADSPA control + ports/VST parameters */ + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_control, + gensym ("control"), + A_DEFSYM, A_DEFFLOAT, 0); + + /* Register a callback for "print" messages in the first inlet; + this is a message for printing information on the plug-in */ + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_print, + gensym ("print"), + 0); + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_opengui, + gensym ("opengui"), + 0); + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_closegui, + gensym ("closegui"), + 0); + + /* Register a callback for "reset" messages in the first inlet; + this is a message for resetting plug-in state */ + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_reset, + gensym ("reset"), + 0); + + /* Register a callback for setting the program */ + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_program, + gensym ("program"), + A_DEFFLOAT, 0); + + class_addmethod (plugin_tilde_class, + (t_method)plugin_tilde_programname, + gensym ("programname"), + A_DEFSYM, 0); + + /* We have to make a "null" callback for signal input to the first + inlet or otherwise Pd'll gracefully fuck the inlets up */ + class_addmethod (plugin_tilde_class, + nullfn, + gensym ("signal"), + 0); +} + +static void* +plugin_tilde_new (t_symbol* s_name, int argc, t_atom *argv) +{ + char buf[255]; + char name[255]; + int z; + int offset = 0; + Pd_Plugin_Tilde* x = NULL; + unsigned i = 0; + + /* Allocate object struct */ + x = (Pd_Plugin_Tilde*)pd_new (plugin_tilde_class); + assert (x != NULL); + + /* Initialize object struct */ + x->plugin_library = NULL; + x->plugin_library_filename = NULL; + x->num_audio_inputs = 0; + x->num_audio_outputs = 0; + x->num_control_inputs = 0; + x->num_control_outputs = 0; + x->audio_inlets = NULL; + x->audio_outlets = NULL; + x->control_outlet = NULL; + x->dsp_vec = NULL; + x->dsp_vec_length = 0; + + for (z = 0; z < argc; z++) { + atom_string(&argv[z], buf, 255); + if (z == 0) + { + snprintf(&name[offset], 255, "%s", buf); + offset += strnlen(buf, 255); + } else { + if (255-offset > 0) { + snprintf(&name[offset], 255-offset, " %s", buf); + offset += strnlen(buf, 255); + } + } + } + + /* Construct the clock */ + x->x_clock = clock_new (x, (t_method)plugin_tilde_tick); + assert (x->x_clock != NULL); + +#if PLUGIN_TILDE_USE_LADSPA + assert (&name[0] != NULL); + if (&name[0] == NULL || strlen (&name[0]) == 0) { + /* Search for the plugin library */ + x->plugin_library_filename = plugin_tilde_search_plugin (x, &name[0]); + if (x->plugin_library_filename == NULL) { + error ("plugin~: " PLUGIN_TILDE_BRAND " plugin not found in any library"); + goto PLUGIN_TILDE_NEW_RETURN_NULL; + } + } + else { + /* Search in the given plugin library */ + x->plugin_library_filename = strdup (&name[0]); + } +#endif /* PLUGIN_TILDE_USE_LADSPA */ +#if PLUGIN_TILDE_USE_VST + /* Remember plugin library filename */ + x->plugin_library_filename = strdup (&name[0]); +#endif /* PLUGIN_TILDE_USE_VST */ + + /* Load LADSPA/VST plugin */ + if (plugin_tilde_open_plugin (x, + &name[0], + x->plugin_library_filename, + (unsigned long)sys_getsr ())) { + error ("plugin~: Unable to open " PLUGIN_TILDE_BRAND " plugin"); + goto PLUGIN_TILDE_NEW_RETURN_NULL; + } + + /* Start the clock (used for plug-in GUI update) */ + plugin_tilde_tick (x); + + /* Create in- and outlet(s) */ + + /* Allocate memory for in- and outlet pointers */ + x->audio_inlets = (t_inlet**)calloc (x->num_audio_inputs, sizeof (t_inlet*)); + x->audio_outlets = (t_outlet**)calloc (x->num_audio_outputs, sizeof (t_outlet*)); + assert (x->audio_inlets != NULL && x->audio_outlets != NULL); + + /* The first inlet is always there (needn't be created), and is + used for control messages. Now, create the rest of the + inlets for audio signal input. */ + for (i = 0; i < x->num_audio_inputs; i++) { + x->audio_inlets[i] = inlet_new (&x->x_obj, + &x->x_obj.ob_pd, + gensym ("signal"), + gensym ("signal")); + } + + /* We use the first outlet always for LADSPA/VST parameter control + messages */ + x->control_outlet = outlet_new (&x->x_obj, gensym ("control")); + + /* The rest of the outlets are used for audio signal output */ + for (i = 0; i < x->num_audio_outputs; i++) { + x->audio_outlets[i] = outlet_new (&x->x_obj, gensym ("signal")); + } + + /* Allocate memory for DSP parameters */ + x->dsp_vec_length = x->num_audio_inputs + x->num_audio_outputs + 2; + x->dsp_vec = (t_int*)calloc (x->dsp_vec_length, sizeof (t_int)); + assert (x->dsp_vec != NULL); + + return x; + + /* erroneous returns */ + PLUGIN_TILDE_NEW_RETURN_NULL: + if (x->plugin_library_filename != NULL) { + free ((void*)x->plugin_library_filename); + x->plugin_library_filename = NULL; + } + if (x->x_clock != NULL) { + clock_free (x->x_clock); + x->x_clock = NULL; + } + return NULL; /* Indicate error to Pd */ +} + +static void +plugin_tilde_free (Pd_Plugin_Tilde* x) +{ + unsigned i = 0; + + /* precondition(s) */ + assert (x != NULL); + + /* Stop and destruct the clock */ + clock_unset (x->x_clock); + clock_free (x->x_clock); + x->x_clock = NULL; + + /* Unload LADSPA/VST plugin */ + plugin_tilde_close_plugin (x); + + /* Free DSP parameter memory */ + if (x->dsp_vec != NULL) { + free (x->dsp_vec); + x->dsp_vec = NULL; + x->dsp_vec_length = 0; + } + + /* Destroy inlets */ + if (x->audio_inlets != NULL) { + for (i = 0; i < x->num_audio_inputs; i++) { + inlet_free (x->audio_inlets[i]); + } + free (x->audio_inlets); + x->audio_inlets = NULL; + } + + /* Destroy outlets */ + if (x->control_outlet != NULL) { + outlet_free (x->control_outlet); + x->control_outlet = NULL; + } + if (x->audio_outlets != NULL) { + for (i = 0; i < x->num_audio_outputs; i++) { + outlet_free (x->audio_outlets[i]); + } + free (x->audio_outlets); + x->audio_outlets = NULL; + } + + + if (x->plugin_library_filename != NULL) { + free ((void*)x->plugin_library_filename); + x->plugin_library_filename = NULL; + } + +} + +static void +plugin_tilde_tick (Pd_Plugin_Tilde* x) +{ + /* precondition(s) */ + assert (x != NULL); + + /* Issue a GUI update (FIXME should use separate GUI thread) */ + plugin_tilde_update_gui (x); + + /* Schedule next update */ + clock_delay (x->x_clock, 100); /* FIXME period OK? */ +} + +static void +plugin_tilde_dsp (Pd_Plugin_Tilde* x, t_signal** sp) +{ + unsigned i = 0; + unsigned long num_samples; + + num_samples = sp[0]->s_n; + + /* Pack vector of parameters for DSP routine */ + x->dsp_vec[0] = (t_int)x; + x->dsp_vec[1] = (t_int)num_samples; + /* Inputs are before outputs; ignore the first "null" input */ + for (i = 2; i < x->dsp_vec_length; i++) { + x->dsp_vec[i] = (t_int)(sp[i - 1]->s_vec); + } + + /* Connect audio ports with buffers (this is only done when DSP + processing begins) */ + plugin_tilde_connect_audio (x, + (float**)(&x->dsp_vec[2]), + (float**)(&x->dsp_vec[2 + x->num_audio_inputs]), + num_samples); + + /* add DSP routine to Pd's DSP chain */ + dsp_addv (plugin_tilde_perform, x->dsp_vec_length, x->dsp_vec); +} + +static t_int* +plugin_tilde_perform (t_int* w) +{ + unsigned i = 0; + Pd_Plugin_Tilde* x = NULL; + t_float** audio_inputs = NULL; + t_float** audio_outputs = NULL; + int num_samples = 0; + + /* precondition(s) */ + assert (w != NULL); + + /* Unpack DSP parameter vector */ + x = (Pd_Plugin_Tilde*)(w[1]); + num_samples = (int)(w[2]); + audio_inputs = (t_float**)(&w[3]); + audio_outputs = (t_float**)(&w[3 + x->num_audio_inputs]); + + /* Call the LADSPA/VST plugin */ + plugin_tilde_apply_plugin (x); + + return w + (x->dsp_vec_length + 1); +} + +void +plugin_tilde_emit_control_output (Pd_Plugin_Tilde* x, + const char* name, + float new_value) +{ + /* Construct and outlet a "control" message with two Pd atoms */ + t_atom anything_atoms[2]; + anything_atoms[0].a_type = A_SYMBOL; + anything_atoms[0].a_w.w_symbol = gensym ((char*)name); + anything_atoms[1].a_type = A_FLOAT; + anything_atoms[1].a_w.w_float = new_value; + outlet_anything (x->control_outlet, gensym ("control"), 2, anything_atoms); +} + +static void +plugin_tilde_control (Pd_Plugin_Tilde* x, + t_symbol* ctrl_name, + t_float ctrl_value) + /* Change the value of a named control port of the plug-in */ +{ + unsigned parm_num = 0; + + /* precondition(s) */ + assert (x != NULL); + /* FIXME we assert that the plug-in is already properly opened */ + if (ctrl_name->s_name == NULL || strlen (ctrl_name->s_name) == 0) { + error ("plugin~: control messages must have a name and a value"); + return; + } + if (ctrl_name->s_name[0]=='/'){ + parm_num = atoi(ctrl_name->s_name+1); + }else{ + parm_num = plugin_tilde_get_parm_number (x, ctrl_name->s_name); + } + if (parm_num) { + plugin_tilde_set_control_input_by_index (x, parm_num - 1, ctrl_value); + } + else { + plugin_tilde_set_control_input_by_name (x, ctrl_name->s_name, ctrl_value); + } +} + +static void plugin_tilde_opengui (Pd_Plugin_Tilde* x){ +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_open_editor(x); +#endif +} + +static void plugin_tilde_closegui (Pd_Plugin_Tilde* x){ +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_close_editor(x); +#endif +} + +static void +plugin_tilde_print (Pd_Plugin_Tilde* x) + /* Print plug-in name, port names and other information */ + +/* +stereo_amp: "Stereo amplifier"; control 1 in/0 out; audio 2 in/2 out +Control inputs: +Control outputs: +Audio inputs: +Audio outputs: + */ +{ + /* precondition(s) */ + assert (x != NULL); + +#if 1 + printf("This is k_vst~ version %s. Made by Kjetil S. Matheussen, but ~99.9 percent based on code\n",PLUGIN_TILDE_VERSION); + printf("written by Jarno Seppänen.\n\n"); +#else + printf ("This is plugin~ version %s -- NO WARRANTY -- Copyright (C) 2000 Jarno Seppänen\n", + PLUGIN_TILDE_VERSION); +#endif +#if PLUGIN_TILDE_USE_LADSPA + plugin_tilde_ladspa_print (x); +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_print (x); +#endif +} + +static void +plugin_tilde_reset (Pd_Plugin_Tilde* x) +{ + /* precondition(s) */ + assert (x != NULL); +#if PLUGIN_TILDE_USE_LADSPA + plugin_tilde_ladspa_reset (x); +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_reset (x); +#endif +} + +static unsigned +plugin_tilde_get_parm_number (Pd_Plugin_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; + + assert (x != 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->num_control_inputs) { + /* string ok and within range */ + return (unsigned)num; + } + else { + /* number out of range */ + return 0; + } +} + +static const char* +plugin_tilde_search_plugin (Pd_Plugin_Tilde* x, + const char* name) +{ +#if PLUGIN_TILDE_USE_LADSPA + return plugin_tilde_ladspa_search_plugin (x, name); +#endif +#if PLUGIN_TILDE_USE_VST + return plugin_tilde_vst_search_plugin (x, name); +#endif +} + +static int +plugin_tilde_open_plugin (Pd_Plugin_Tilde* x, + const char* name, + const char* lib_name, + unsigned long sample_rate) +{ + int ret = 0; + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~: open_plugin (x, \"%s\", \"%s\", %ld);", + name, lib_name, sample_rate); +#endif + +#if PLUGIN_TILDE_USE_LADSPA + ret = plugin_tilde_ladspa_open_plugin (x, name, lib_name, sample_rate); +#endif +#if PLUGIN_TILDE_USE_VST + ret = plugin_tilde_vst_open_plugin (x, name, lib_name, sample_rate); +#endif + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~: plugin active"); +#endif + +#if PLUGIN_TILDE_VERBOSE + plugin_tilde_print (x); +#endif + return ret; +} + +static void +plugin_tilde_close_plugin (Pd_Plugin_Tilde* x) +{ +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~: close_plugin (x)"); +#endif + +#if PLUGIN_TILDE_USE_LADSPA + plugin_tilde_ladspa_close_plugin (x); +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_close_plugin (x); +#endif + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~: destructed plugin successfully"); +#endif +} + +static void +plugin_tilde_apply_plugin (Pd_Plugin_Tilde* x) +{ +#if PLUGIN_TILDE_USE_LADSPA + plugin_tilde_ladspa_apply_plugin (x); +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_apply_plugin (x); +#endif +} + +static void +plugin_tilde_connect_audio (Pd_Plugin_Tilde* x, + float** audio_inputs, + float** audio_outputs, + unsigned long num_samples) +{ +#if PLUGIN_TILDE_USE_LADSPA + plugin_tilde_ladspa_connect_audio (x, audio_inputs, audio_outputs, + num_samples); +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_connect_audio (x, audio_inputs, audio_outputs, + num_samples); +#endif +} + +static void +plugin_tilde_set_control_input_by_name (Pd_Plugin_Tilde* x, + const char* name, + float value) +{ +#if PLUGIN_TILDE_USE_LADSPA + plugin_tilde_ladspa_set_control_input_by_name (x, name, value); +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_set_control_input_by_name (x, name, value); +#endif +} + +static void +plugin_tilde_set_control_input_by_index (Pd_Plugin_Tilde* x, + unsigned index_, + float value) +/* plugin~.c:535: warning: declaration of `index' shadows global declaration */ +{ +#if PLUGIN_TILDE_USE_LADSPA + plugin_tilde_ladspa_set_control_input_by_index (x, index_, value); +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_set_control_input_by_index (x, index_, value); +#endif +} + +static void +plugin_tilde_update_gui (Pd_Plugin_Tilde* x) +{ +#if PLUGIN_TILDE_USE_LADSPA + /* FIXME LADSPA doesn't support GUI's at the moment */ +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_update_gui (x); +#endif +} + +static void +plugin_tilde_program (Pd_Plugin_Tilde* x, t_float prog_num) + /* set the plugin's controls to one of its presets */ +{ +#if PLUGIN_TILDE_USE_LADSPA +#endif +#if PLUGIN_TILDE_USE_VST + plugin_tilde_vst_set_program(x, (long) prog_num); +#endif +} + +static void +plugin_tilde_programname (Pd_Plugin_Tilde* x, t_symbol* progname) + /* set the name of the current program in the plugin */ +{ +#if PLUGIN_TILDE_USE_LADSPA +#endif +#if PLUGIN_TILDE_USE_VST + if (progname->s_name == NULL || strlen (progname->s_name) == 0) { + error ("plugin~: control messages must have a name and a value"); + return; + } + plugin_tilde_vst_set_program_name(x, progname->s_name); +#endif +} + + +/* EOF */ diff --git a/plugin~.h b/plugin~.h new file mode 100644 index 0000000..23cb376 --- /dev/null +++ b/plugin~.h @@ -0,0 +1,189 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: plugin~.h,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __PLUGIN_TILDE_H__ +#define __PLUGIN_TILDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "config.h" + +/* Pd header */ +#ifndef MAXPDSTRING /* lame */ +#include "m_pd.h" +#endif /* MAXPDSTRING */ + +#if 0 +# if PLUGIN_TILDE_USE_LADSPA +# include "plugin~_ladspa.h" +# endif +# if PLUGIN_TILDE_USE_VST +# include "plugin~_vst.h" +# endif +#endif /* 0 */ +/* + * Now I've moved the following two plug-in-architecture-specific structures + * here because having them in plugin~_ladspa.h and plugin~_vst.h proper will + * result in a cyclical header dependency + */ +#if PLUGIN_TILDE_USE_LADSPA +#include "ladspa/ladspa.h" +typedef struct +{ + const LADSPA_Descriptor* type; + LADSPA_Handle* instance; + + /* Memory to pass async control data to/from the plugin */ + float* control_input_values; + float* control_output_values; + /* Used for monitoring changes in the values */ + float* prev_control_output_values; + int prev_control_output_values_invalid; + + /* Pointers to signal memory for out-of-place processing */ + float** outofplace_audio_outputs; + float** actual_audio_outputs; /* real audio outputs for out-of-place */ + + unsigned long num_samples; + unsigned long sample_rate; + +} Plugin_Tilde_Ladspa; +#endif /* PLUGIN_TILDE_USE_LADSPA */ + +#if PLUGIN_TILDE_USE_VST +#include "vst/AEffect.h" +typedef struct +{ + AEffect* instance; + + /* audio wire buffer information */ + float** audio_inputs; + float** audio_outputs; + unsigned long num_samples; + + int editor_open; + +} Plugin_Tilde_Vst; +#endif /* PLUGIN_TILDE_USE_VST */ + +typedef struct +{ + /* Pd's way of object-oriented programming */ + t_object x_obj; + t_clock* x_clock; + + /* Access to LADSPA/VST plugins */ + void* plugin_library; + const char* plugin_library_filename; /* only for diagnostics */ + union { +#if PLUGIN_TILDE_USE_LADSPA + Plugin_Tilde_Ladspa ladspa; +#endif +#if PLUGIN_TILDE_USE_VST + Plugin_Tilde_Vst vst; +#endif + } plugin; + + /* Plugin information */ + unsigned num_audio_inputs; + unsigned num_audio_outputs; + unsigned num_control_inputs; + unsigned num_control_outputs; + + /* Pointers to our Pd in- and outlets */ + t_inlet** audio_inlets; + t_outlet** audio_outlets; + t_outlet* control_outlet; + + /* Pd's way of passing parameters to the DSP routine */ + t_int* dsp_vec; + unsigned dsp_vec_length; + +} Pd_Plugin_Tilde; + +/* Object construction and destruction */ +void plugin_tilde_setup (void); +static void* plugin_tilde_new (t_symbol* s_name, int argc, t_atom *argv); +static void plugin_tilde_free (Pd_Plugin_Tilde* x); +static void plugin_tilde_tick (Pd_Plugin_Tilde* x); + +/* DSP callbacks */ +static void plugin_tilde_dsp (Pd_Plugin_Tilde* x, t_signal** sp); +static t_int* plugin_tilde_perform (t_int* w); + +/* Plugin callback for sending control output messages */ +void plugin_tilde_emit_control_output (Pd_Plugin_Tilde* x, + const char* name, + float new_value); + +/* First inlet message callback for "control" messages */ +static void plugin_tilde_control (Pd_Plugin_Tilde* x, + t_symbol* ctrl_name, + t_float ctrl_value); + +static void plugin_tilde_opengui (Pd_Plugin_Tilde* x); + +static void plugin_tilde_closegui (Pd_Plugin_Tilde* x); + +/* First inlet message callback for "control" messages */ +static void plugin_tilde_print (Pd_Plugin_Tilde* x); + +/* First inlet message callback for "reset" messages */ +static void plugin_tilde_reset (Pd_Plugin_Tilde* x); + +static unsigned plugin_tilde_get_parm_number (Pd_Plugin_Tilde* x, + const char* str); + +/* internal API to wrap the different plug-in interfaces */ +static const char* plugin_tilde_search_plugin (Pd_Plugin_Tilde* x, + const char* name); +static int plugin_tilde_open_plugin (Pd_Plugin_Tilde* x, + const char* name, + const char* lib_name, + unsigned long sample_rate); +static void plugin_tilde_close_plugin (Pd_Plugin_Tilde* x); +static void plugin_tilde_apply_plugin (Pd_Plugin_Tilde* x); + +static void plugin_tilde_connect_audio (Pd_Plugin_Tilde* x, + float** audio_inputs, + float** audio_outputs, + unsigned long num_samples); +static void plugin_tilde_set_control_input_by_name (Pd_Plugin_Tilde* x, + const char* name, + float value); +static void plugin_tilde_set_control_input_by_index (Pd_Plugin_Tilde* x, + unsigned index_, + float value); +/*static float plugin_tilde_get_control_input (Pd_Plugin_Tilde* x, + unsigned int index);*/ +static void plugin_tilde_update_gui (Pd_Plugin_Tilde* x); + +static void plugin_tilde_program (Pd_Plugin_Tilde* x, t_float prog_num); +static void plugin_tilde_programname (Pd_Plugin_Tilde* x, t_symbol* progname); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PLUGIN_TILDE_H__ */ +/* EOF */ diff --git a/plugin~_ladspa.h b/plugin~_ladspa.h new file mode 100644 index 0000000..88e0086 --- /dev/null +++ b/plugin~_ladspa.h @@ -0,0 +1,108 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: plugin~_ladspa.h,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __PLUGIN_TILDE_LADSPA_H__ +#define __PLUGIN_TILDE_LADSPA_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "config.h" + +#if PLUGIN_TILDE_USE_LADSPA + +#include "plugin~.h" + +/* LADSPA header */ +#include "ladspa/ladspa.h" + +#if 0 /* moved to plugin~.h because of cyclical header dependency */ +typedef struct +{ + const LADSPA_Descriptor* type; + LADSPA_Handle* instance; + + /* Memory to pass async control data to/from the plugin */ + float* control_input_values; + float* control_output_values; + /* Used for monitoring changes in the values */ + float* prev_control_output_values; + int prev_control_output_values_invalid; + + /* Pointers to signal memory for out-of-place processing */ + float** outofplace_audio_outputs; + float** actual_audio_outputs; /* real audio outputs for out-of-place */ + + unsigned long num_samples; + unsigned long sample_rate; + +} Plugin_Tilde_Ladspa; +#endif /* moved to plugin~.h because of cyclical header dependency */ + + +/* subroutines to wrap the LADSPA interface */ +const char* plugin_tilde_ladspa_search_plugin (Pd_Plugin_Tilde* x, + const char* name); +int plugin_tilde_ladspa_open_plugin (Pd_Plugin_Tilde* x, + const char* name, + const char* lib_name, + unsigned long sample_rate); +void plugin_tilde_ladspa_close_plugin (Pd_Plugin_Tilde* x); +void plugin_tilde_ladspa_apply_plugin (Pd_Plugin_Tilde* x); + +void plugin_tilde_ladspa_print (Pd_Plugin_Tilde* x); +void plugin_tilde_ladspa_reset (Pd_Plugin_Tilde* x); + +void plugin_tilde_ladspa_connect_audio (Pd_Plugin_Tilde* x, + float** audio_inputs, + float** audio_outputs, + unsigned long num_samples); +void plugin_tilde_ladspa_set_control_input_by_name (Pd_Plugin_Tilde* x, + const char* name, + float value); +void plugin_tilde_ladspa_set_control_input_by_index (Pd_Plugin_Tilde* x, + unsigned index_, + float value); +/*float plugin_tilde_ladspa_get_control_input (Pd_Plugin_Tilde* x, + const char* name);*/ +/* Control output is handled with plugin_tilde_emit_control_output() callback */ + +/* Local subroutines */ +static void plugin_tilde_ladspa_search_plugin_callback (const char* full_filename, + void* plugin_handle, + LADSPA_Descriptor_Function descriptor_function, + void* user_data); +static void plugin_tilde_ladspa_count_ports (Pd_Plugin_Tilde* x); +static void plugin_tilde_ladspa_connect_control_ports (Pd_Plugin_Tilde* x); + +static int plugin_tilde_ladspa_alloc_outofplace_memory (Pd_Plugin_Tilde* x, unsigned long buflen); +static void plugin_tilde_ladspa_free_outofplace_memory (Pd_Plugin_Tilde* x); +static int plugin_tilde_ladspa_alloc_control_memory (Pd_Plugin_Tilde* x); +static void plugin_tilde_ladspa_free_control_memory (Pd_Plugin_Tilde* x); + +#endif /* PLUGIN_TILDE_USE_LADSPA */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PLUGIN_TILDE_LADSPA_H__ */ +/* EOF */ diff --git a/plugin~_vst.c b/plugin~_vst.c new file mode 100644 index 0000000..001924f --- /dev/null +++ b/plugin~_vst.c @@ -0,0 +1,571 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: plugin~_vst.c,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" +#if PLUGIN_TILDE_USE_VST + +#include +#include +#include +#include + +#include "plugin~.h" +#include "plugin~_vst.h" +/* VST header */ +#define AEFFECTX_H_LINUXWORKAROUND +#include "vst/aeffectx.h" +//#include "vst/AEffect.h" +/* VST dll helper functions */ +#include "vstutils.h" +#ifdef WIN32 +#include "win/vitunmsvc.h" /* strncasecmp() */ +#include /* GetForegroundWindow() */ +#endif + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + + +const char* +plugin_tilde_vst_search_plugin (Pd_Plugin_Tilde* x, + const char* name) +{ + /* searching through VST libraries not supported */ + error ("plugin~: warning: searching through VST libraries not supported"); + return NULL; +} + +int +plugin_tilde_vst_open_plugin (Pd_Plugin_Tilde* x, + const char* name, + const char* lib_name, + unsigned long sample_rate) +{ + unsigned port_index; + + /* precondition(s) */ + assert (x != NULL); + /* name is unused */ + assert (lib_name != NULL); + assert (sample_rate != 0); + + /* Initialize object struct */ + x->plugin.vst.instance = NULL; + x->plugin.vst.audio_inputs = NULL; + x->plugin.vst.audio_outputs = NULL; + x->plugin.vst.num_samples = 0; + x->plugin.vst.editor_open = 0; + +#if 0 + /* Attempt to load the plugin. */ + x->plugin_library = vstutils_load_vst_plugin_dll (lib_name); + if (x->plugin_library == NULL) + { + error ("plugin~: Unable to load VST plugin library \"%s\"", + lib_name); + return 1; + } +#endif + + /* Construct the plugin. This is supposed to call + the AudioEffect::AudioEffect() ctor eventually */ + x->plugin.vst.instance +#if 1 + =VSTLIB_new((char*)lib_name); +#else + = vstutils_init_vst_plugin (x->plugin_library, + lib_name, + plugin_tilde_vst_audioMaster); +#endif + if (x->plugin.vst.instance == NULL) { + error ("plugin~: Unable to instantiate VST plugin from library \"%s\"", + lib_name); + return 1; + } + + /* Stuff Pd_Plugin_Tilde* x into user field of AEffect for audioMaster() to use */ + x->plugin.vst.instance->user = x; + + /* Call plugin open() (through dispatcher()) in order to ensure + plugin is properly constructed */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effOpen, + 0, 0, NULL, 0); + + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~: constructed VST plugin \"%s\" successfully", + lib_name); +#endif + + + /* Check another strange id */ + if (x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effIdentify, + 0, 0, NULL, 0) + != 'NvEf') { + error ("plugin~_vst: warning: VST plugin malfunction (effIdentify != 'NvEf')"); + } + + + /* Tell the sample rate and frame length to the VST plug-in */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetSampleRate, + 0, 0, NULL, (float)sample_rate); + + /* FIXME just give some value since it will be changed later */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetBlockSize, + 0, 16, NULL, 0); + /* Find out the number of inputs and outputs needed (all VST + parameters can be automated i.e. output if the plug-in so wants + and the GUI can be operated). */ + x->num_audio_inputs = x->plugin.vst.instance->numInputs; + x->num_audio_outputs = x->plugin.vst.instance->numOutputs; + x->num_control_inputs = x->plugin.vst.instance->numParams; + x->num_control_outputs = x->plugin.vst.instance->numParams; + + /* Make sure that processReplacing() is implemented */ + if (x->plugin.vst.instance->flags & effFlagsCanReplacing == 0) { + error ("plugin~_vst: sorry, this VST plug-in type isn't supported (processReplacing() not implemented)"); + return 1; + } + + + /* Activate the plugin. */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 1, NULL, 0); + + + /* Finally, attempt open editor GUI if available */ + // plugin_tilde_vst_open_editor (x); + + + /* Make sure the user data still is there */ + assert (x->plugin.vst.instance->user == x); + + /* success */ + return 0; +} + +void +plugin_tilde_vst_close_plugin (Pd_Plugin_Tilde* x) +{ + /* precondition(s) */ + assert (x != NULL); + + /* Attempt to close editor GUI */ + plugin_tilde_vst_close_editor (x); + + if (x->plugin.vst.instance != NULL) + { + /* Deactivate the plugin. */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 0, NULL, 0); + + /* Destruct the plugin. This is supposed to translate to + a call to the AudioEffect::~AudioEffect() dtor */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effClose, + 0, 0, NULL, 0); +#if 1 + VSTLIB_delete(x->plugin.vst.instance); +#endif + x->plugin.vst.instance = NULL; + } + + + if (x->plugin_library != NULL) + { +#if 0 + vstutils_unload_vst_plugin_dll (x->plugin_library); +#endif + x->plugin_library = NULL; + } +} + +void +plugin_tilde_vst_apply_plugin (Pd_Plugin_Tilde* x) +{ + static int agurk=0; + + /* Run the plugin on Pd's buffers */ + /* FIXME need to implement out-of-place buffers and zero them here + if processReplacing() isn't implemented */ + + x->plugin.vst.instance->processReplacing (x->plugin.vst.instance, + x->plugin.vst.audio_inputs, + x->plugin.vst.audio_outputs, + x->plugin.vst.num_samples); + +} + +void +plugin_tilde_vst_print (Pd_Plugin_Tilde* x) +{ + unsigned i; + char display[25]; + long l, nprog; + + printf ("control %d in/out; audio %d in/%d out\n" + "Loaded from library \"%s\".\n", + x->num_control_inputs, + x->num_audio_inputs, + x->num_audio_outputs, + x->plugin_library_filename); + + /* print the current program name/number */ + l = x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetProgram, 0, 0, display, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetProgramName, 0, 0, display, 0); + nprog = x->plugin.vst.instance->numPrograms; + printf("Program #%ld (of %ld), \"%s\".\n",l,nprog,display); + + for (i = 0; i < x->num_control_inputs; i++) { + /* the Steinberg(tm) way... */ + char name[9]; + char label[9]; + if (i == 0) { + printf ("Control input/output(s):\n"); + } + memset (name, 0, 9); + memset (display, 0, 25); + memset (label, 0, 9); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamName, + i, 0, name, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamDisplay, + i, 0, display, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamLabel, + i, 0, label, 0); + printf (" #%d \"%s\" (%s %s)\n", + i + 1, name, display, label); + } +} + +void +plugin_tilde_vst_reset (Pd_Plugin_Tilde* x) +{ + /* precondition(s) */ + assert (x != NULL); + /* reset plug-in by first deactivating and then re-activating it */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 0, NULL, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 1, NULL, 0); +} + +void +plugin_tilde_vst_connect_audio (Pd_Plugin_Tilde* x, + float** audio_inputs, + float** audio_outputs, + unsigned long num_samples) +{ + assert (x != NULL); + assert (audio_inputs != NULL); + assert (audio_outputs != NULL); + x->plugin.vst.audio_inputs = audio_inputs; + x->plugin.vst.audio_outputs = audio_outputs; + x->plugin.vst.num_samples = num_samples; + /* Tell the block size to the VST plug-in */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 0, NULL, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetBlockSize, + 0, num_samples, NULL, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 1, NULL, 0); +} + +void +plugin_tilde_vst_set_control_input_by_name (Pd_Plugin_Tilde* x, + const char* name, + float value) +{ + unsigned parm_index; + int found_port; /* boolean */ + char parm_name[9]; /* the Steinberg(tm) way! */ + + /* precondition(s) */ + assert (x != NULL); + + /* compare control name to VST parameters' names + case-insensitively */ + found_port = 0; + for (parm_index = 0; parm_index < x->num_control_inputs; parm_index++) + { + unsigned cmp_start, cmp_length; + memset (parm_name, 0, 9); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamName, + parm_index, 0, parm_name, 0); + /* skip any initial whitespace */ + cmp_start = 0; + while (parm_name[cmp_start] != 0 + && parm_name[cmp_start] == ' ') { + cmp_start++; + } + cmp_length = MIN (strlen (name), strlen (&parm_name[cmp_start])); + if (cmp_length != 0 + && strncasecmp (name, &parm_name[cmp_start], cmp_length) == 0) + { + /* found the first port to match */ + found_port = 1; + break; + } + } + + if (!found_port) + { + error ("plugin~: VST plugin doesn't have a parameter named \"%s\"", + name); + return; + } + + plugin_tilde_vst_set_control_input_by_index (x, + parm_index, + value); +} + +void +plugin_tilde_vst_set_control_input_by_index (Pd_Plugin_Tilde* x, + unsigned index_, + float value) +{ + char name[9]; /* the Steinberg(tm) way! */ + + /* precondition(s) */ + assert (x != NULL); + /* assert (index_ >= 0); causes a warning */ + assert (index_ < x->num_control_inputs); + + /* Limit parameter to range [0, 1] */ + if (value < 0.0 || value > 1.0) { + if (value < 0.0) { + value = 0.0; + } + else { + value = 1.0; + } + error ("plugin~: warning: parameter limited to within [0, 1]"); + } + + /* set the appropriate control port value */ + x->plugin.vst.instance->setParameter (x->plugin.vst.instance, + index_, + value); + +#if PLUGIN_TILDE_DEBUG + memset (name, 0, 9); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamName, + index_, 0, name, 0); + error ("DEBUG plugin~_vst: control change parameter #%ud: \"%s\" to value %f", + index_ + 1, name, value); +#endif +} + +/* change the plugin's program; takes a program index */ +void +plugin_tilde_vst_set_program (Pd_Plugin_Tilde* x, long prog) +{ + long nprog = x->plugin.vst.instance->numPrograms; + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetProgram, 0, prog%nprog, 0, 0); +} + +long +plugin_tilde_vst_get_program (Pd_Plugin_Tilde* x) +{ + return x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetProgram, 0, 0, 0, 0); +} + +long +plugin_tilde_vst_get_num_of_programs (Pd_Plugin_Tilde* x) +{ + return x->plugin.vst.instance->numPrograms; +} + +void +plugin_tilde_vst_set_program_name (Pd_Plugin_Tilde* x, const char* progname) +{ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetProgramName, 0, 0, (void*)progname, 0); +} + +static long +plugin_tilde_vst_audioMaster (AEffect* effect, + long opcode, + long index, + long value, + void* ptr, + float opt) +{ + char param_name[9]; + +#if 0 /*PLUGIN_TILDE_DEBUG*/ + error ("DEBUG plugin~_vst: audioMaster(0x%p, %ld, %ld, %ld, 0x%p, %f)", + effect, opcode, index, value, ptr, opt); +#endif + + switch (opcode) { + case audioMasterAutomate: + assert (effect != NULL); + assert (effect->user != NULL); /* this is Pd_Plugin_Tilde* */ + effect->setParameter (effect, index, opt); + /* Send "control" messages from here */ + memset (param_name, 0, 9); + effect->dispatcher (effect, effGetParamName, index, 0, param_name, 0); + plugin_tilde_emit_control_output (effect->user, param_name, opt); + return 0; + break; + case audioMasterVersion: + return 1; + break; + case audioMasterCurrentId: + return 0; + break; + case audioMasterIdle: + effect->dispatcher (effect, effEditIdle, 0, 0, NULL, 0); + return 0; + break; + case audioMasterPinConnected: + /* return 0="true" for all inquiries for now */ + return 0; + break; + } +#if 0 /*PLUGIN_TILDE_DEBUG*/ + error ("DEBUG plugin~_vst: warning: unsupported audioMaster opcode"); +#endif + return 0; +} + +void plugin_tilde_vst_open_editor (Pd_Plugin_Tilde* x) +{ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditOpen, + 0, 0, NULL, 0); + +#if 0 /* FIXME doesn't work */ +#ifdef WIN32 + HWND parent; + + /* precondition(s) */ + assert (x != NULL); + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~_vst: open_editor()"); +#endif + + if ((x->plugin.vst.instance->flags & effFlagsHasEditor) == 0 + || x->plugin.vst.editor_open == 1) { + /* no editor or editor already open */ + return; + } + + /* Hmph, don't know about the Pd window, so give the desktop as + the parent to the plug-in; we could actually use + GetForegroundWindow(), since the user is currently typing into + the pd subpatch window */ + /*parent = GetDesktopWindow ();*/ + parent = GetForegroundWindow (); + /*parent = NULL;*/ + + /* Open the editor! */ + if (!x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditOpen, + 0, 0, parent, 0)) { + /* no luck error */ + error ("plugin~_vst: couldn't open editor"); + } else { + x->plugin.vst.editor_open = 1; + } +#endif /* WIN32 */ +#endif /* FIXME doesn't work */ +} + +void +plugin_tilde_vst_close_editor (Pd_Plugin_Tilde* x) +{ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditClose, + 0, 0, NULL, 0); + +#if 0 /* FIXME doesn't work */ +#ifdef WIN32 + + /* precondition(s) */ + assert (x != NULL); + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~_vst: close_editor()"); +#endif + + if ((x->plugin.vst.instance->flags & effFlagsHasEditor) == 0 + || x->plugin.vst.editor_open == 0) { + /* no editor or it isn't open */ + return; + } + + /* Close the editor */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditClose, + 0, 0, NULL, 0); + x->plugin.vst.editor_open = 0; + +#endif /* WIN32 */ +#endif /* FIXME doesn't work */ +} + +void +plugin_tilde_vst_update_gui (Pd_Plugin_Tilde* x) +{ +#if 0 /* FIXME doesn't work */ +#ifdef WIN32 + + /* precondition(s) */ + assert (x != NULL); + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~_vst: update_gui()"); +#endif + if (x->plugin.vst.editor_open) { + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditIdle, + 0, 0, NULL, 0); + } +#endif /* WIN32 */ +#endif /* FIXME doesn't work */ +} + +#endif /* PLUGIN_TILDE_USE_VST */ + +/* EOF */ diff --git a/plugin~_vst.h b/plugin~_vst.h new file mode 100644 index 0000000..ff12d40 --- /dev/null +++ b/plugin~_vst.h @@ -0,0 +1,108 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: plugin~_vst.h,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __PLUGIN_TILDE_VST_H__ +#define __PLUGIN_TILDE_VST_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "config.h" + +#if PLUGIN_TILDE_USE_VST + +#include "plugin~.h" + +/* VST header */ +#include "vst/AEffect.h" + +#if 0 /* moved to plugin~.h because of cyclical header dependency */ +typedef struct +{ + AEffect* instance; + + /* audio wire buffer information */ + float** audio_inputs; + float** audio_outputs; + unsigned long num_samples; + + int editor_open; +} Plugin_Tilde_Vst; +#endif /* moved to plugin~.h because of cyclical header dependency */ + + +/* subroutines to wrap the VST interface */ +const char* plugin_tilde_vst_search_plugin (Pd_Plugin_Tilde* x, + const char* name); +int plugin_tilde_vst_open_plugin (Pd_Plugin_Tilde* x, + const char* name, + const char* lib_name, + unsigned long sample_rate); + +void plugin_tilde_vst_close_editor (Pd_Plugin_Tilde* x); +void plugin_tilde_vst_open_editor (Pd_Plugin_Tilde* x); + +void plugin_tilde_vst_close_plugin (Pd_Plugin_Tilde* x); +void plugin_tilde_vst_apply_plugin (Pd_Plugin_Tilde* x); + +void plugin_tilde_vst_print (Pd_Plugin_Tilde* x); +void plugin_tilde_vst_reset (Pd_Plugin_Tilde* x); + +void plugin_tilde_vst_connect_audio (Pd_Plugin_Tilde* x, + float** audio_inputs, + float** audio_outputs, + unsigned long num_samples); +void plugin_tilde_vst_set_control_input_by_name (Pd_Plugin_Tilde* x, + const char* name, + float value); +void plugin_tilde_vst_set_control_input_by_index (Pd_Plugin_Tilde* x, + unsigned index_, + float value); + + +/* subroutines needed by the VST interface */ +static long plugin_tilde_vst_audioMaster (AEffect* effect, + long opcode, + long index, + long value, + void* ptr, + float opt); + + /* +static void plugin_tilde_vst_open_editor (Pd_Plugin_Tilde* x); +static void plugin_tilde_vst_close_editor (Pd_Plugin_Tilde* x); + */ + +void plugin_tilde_vst_update_gui (Pd_Plugin_Tilde* x); + +void plugin_tilde_vst_set_program (Pd_Plugin_Tilde*, long); +long plugin_tilde_vst_get_program (Pd_Plugin_Tilde*); +long plugin_tilde_vst_get_num_of_programs (Pd_Plugin_Tilde*); +void plugin_tilde_vst_set_program_name (Pd_Plugin_Tilde*, const char*); + +#endif /* PLUGIN_TILDE_USE_VST */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PLUGIN_TILDE_VST_H__ */ +/* EOF */ diff --git a/version.h b/version.h new file mode 100644 index 0000000..8cb2f21 --- /dev/null +++ b/version.h @@ -0,0 +1,28 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: version.h,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __PLUGIN_TILDE_VERSION_H__ +#define __PLUGIN_TILDE_VERSION_H__ + +#ifndef PLUGIN_TILDE_VERSION +#define PLUGIN_TILDE_VERSION "0.2" +#endif + +#endif /* __PLUGIN_TILDE_VERSION_H__ */ diff --git a/vstutils.h b/vstutils.h new file mode 100644 index 0000000..c90edde --- /dev/null +++ b/vstutils.h @@ -0,0 +1,50 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2001 Jarno Seppänen + Copyright (C) 2000 Richard W.E. Furse + $Id: vstutils.h,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __VSTUTILS_H__ +#define __VSTUTILS_H__ + +#include + +#ifdef WIN32 /* currently for Windows only */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* VST SDK header */ +#include "vst/AEffect.h" + +void* vstutils_load_vst_plugin_dll (const char* plugin_dll_filename); +void vstutils_unload_vst_plugin_dll (void* plugin_dll); +AEffect* vstutils_init_vst_plugin (void* plugin_dll, + const char* plugin_dll_filename, + audioMasterCallback am); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* WIN32 */ + +#endif /* __VSTUTILS_H__ */ +/* EOF */ -- cgit v1.2.1