pd-plugin_0.2.1/0000755000076500007650000000000011443243642012154 5ustar hanshanspd-plugin_0.2.1/plugin~.h0000644000076500007650000001260210755130527014024 0ustar hanshans#include "ladspa.h" #include "m_pd.h" typedef struct { const LADSPA_Descriptor* type; LADSPA_Handle* instance; /* Memory to pass async control data to/from the plugin */ float* control_input_values; int * control_input_ports; /* port indexes */ float* control_output_values; int * control_output_ports; /* port indexes */ /* 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; typedef struct { /* Pd's way of object-oriented programming */ t_object x_obj; /* Access to LADSPA/VST plugins */ void* plugin_library; const char* plugin_library_filename; /* only for diagnostics */ union { Plugin_Tilde_Ladspa ladspa; } 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; unsigned dsp_active; } Pd_Plugin_Tilde; /* Object construction and destruction */ void plugin_tilde_setup (void); static void* plugin_tilde_new (t_symbol* s_name, t_symbol* s_lib_name); static void plugin_tilde_free (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, int output_port_index); /* First inlet message callback for "control" messages */ static void plugin_tilde_control (Pd_Plugin_Tilde* x, t_symbol* ctrl_name, t_float ctrl_value); /* First inlet message callback for "control" messages */ static void plugin_tilde_list (Pd_Plugin_Tilde* x); static void plugin_tilde_info (Pd_Plugin_Tilde* x); static void plugin_tilde_plug (Pd_Plugin_Tilde* x, t_symbol* plug_name); static void plugin_tilde_active (Pd_Plugin_Tilde* x, t_float active); /* 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); /* 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_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_describe (const char* full_filename, void* plugin_handle, LADSPA_Descriptor_Function descriptor_function, void* user_data); 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); pd-plugin_0.2.1/plugin~-help.pd0000644000076500007650000000522111426363557015134 0ustar hanshans#N canvas 286 22 838 540 10; #X floatatom 638 258 0 0 0 0 - - -; #X msg 638 228 440; #X obj 588 195 loadbang; #X msg 637 287 control freq \$1; #X msg 539 286 control amp \$1; #X msg 539 229 0.7; #X floatatom 539 260 0 0 0 0 - - -; #X msg 82 409 control gain \$1; #X floatatom 82 389 0 0 0 0 - - -; #X obj 596 363 plugin~ sine_fcac; #X msg 502 319 info; #X obj 199 503 dac~; #X obj 20 47 plugin~ lpf; #X text 13 11 plugin~: LADSPA plug-in hosting for Pd.; #X obj 82 349 loadbang; #X msg 32 434 info; #N canvas 0 22 450 300 (subpatch) 0; #X array \$0-display 100 float 0; #X coords 0 1 100 -1 200 70 1; #X restore 521 459 graph; #X obj 507 401 metro 500; #X msg 506 379 1; #X obj 506 357 loadbang; #X text 19 65 Create a plug-in by label. All LADSPA plug-in libraries will be searched.; #X text 30 316 Example: stereo amplifier from LADSPA SDK; #X text 424 168 Example: sine oscillator from LADSPA SDK; #X obj 130 202 plugin~ lpf; #X text 106 114 In- and outlet functionality:; #X text 6 269 You can investigate the inputs and outputs by sending a "info" message to the first inlet.; #X msg 110 181 info; #X text 12 140 The first inlet is for control input messages. The first outlet is for control output messages \, correspondingly.; #X text 425 138 The rest inlets are for audio input and the rest outlets are for audio output signals.; #X msg 30 404 reset; #X msg 499 294 reset; #X obj 202 376 osc~ 220; #X msg 82 369 0.05; #X obj 647 426 tabwrite~ \$0-display; #X obj 68 247 print INFO; #X msg 146 181 listplugins; #X obj 138 225 route label; #X obj 138 246 print PLUGIN_NAME; #X obj 574 385 print SINE_FCAC; #X obj 67 502 print AMP_STEREO; #X obj 130 466 plugin~ amp_stereo; #X obj 430 35 plugin~ compress_peak cmt.so; #X obj 430 57 print INFO; #X msg 430 13 info; #X text 425 79 Create a plug-in by label and library name. Only the selected LADSPA plug-in library is searched ('cmt.so' is packaged in "cmt" in Debian/Ubuntu \, "ladspa-cmt" in Mac OS X/Fink \, and "ladspa-cmt-plugins" in Fedora).; #X connect 0 0 3 0; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 2 0 5 0; #X connect 3 0 9 0; #X connect 4 0 9 0; #X connect 5 0 6 0; #X connect 6 0 4 0; #X connect 7 0 40 0; #X connect 8 0 7 0; #X connect 9 0 38 0; #X connect 9 1 33 0; #X connect 10 0 9 0; #X connect 14 0 32 0; #X connect 15 0 40 0; #X connect 17 0 33 0; #X connect 18 0 17 0; #X connect 19 0 18 0; #X connect 23 0 34 0; #X connect 23 0 36 0; #X connect 26 0 23 0; #X connect 29 0 40 0; #X connect 30 0 9 0; #X connect 31 0 40 1; #X connect 31 0 40 2; #X connect 32 0 8 0; #X connect 35 0 23 0; #X connect 36 0 37 0; #X connect 40 0 39 0; #X connect 40 1 11 0; #X connect 40 2 11 1; #X connect 41 0 42 0; #X connect 43 0 41 0; pd-plugin_0.2.1/plugin~.c0000644000076500007650000011016511426363557014031 0ustar hanshans/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins Copyright (C) 2000 Jarno Seppänen remIXed 2005 $Id: plugin~.c,v 1.5 2005-04-30 20:30:53 ix9 Exp $ 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 #include #include #include #include "plugin~.h" #include "jutils.h" #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifdef HAVE_LOCALE_H # include static char*s_locale=NULL; static void plugin_tilde_pushlocale(void) { if(s_locale)verbose(1, "pushing locale '%s'", s_locale); s_locale=setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); } static void plugin_tilde_poplocale(void) { if(!s_locale)verbose(1, "popping empty locale"); setlocale(LC_NUMERIC, s_locale); s_locale=NULL; } #else static void plugin_tilde_pushlocale(void) { static int again=0; if(!again) { verbose(1, "plugins~: couldn't modify locales (compiled without locale.h)"); verbose(1, " if you experience weird characters try running Pd with LANG=C"); } again=1; } static void plugin_tilde_poplocale (void) {} #endif static int plugin_tilde_have_plugin(Pd_Plugin_Tilde* x); static t_class* plugin_tilde_class = NULL; void plugin_tilde_setup (void) { /* Make a new Pd class with 2 string creation parameters */ plugin_tilde_class = class_new (gensym ("plugin~"), (t_newmethod)plugin_tilde_new, (t_method)plugin_tilde_free, sizeof (Pd_Plugin_Tilde), 0, A_DEFSYM, A_DEFSYM, 0); assert (plugin_tilde_class != NULL); /* Let's be explicit in not converting the signals in any way */ assert (sizeof (float) == sizeof (t_float)); assert (sizeof (float) == sizeof (LADSPA_Data)); class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_dsp,gensym ("dsp"),0); class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_control,gensym ("control"),A_SYMBOL, A_FLOAT, 0); class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_info,gensym ("info"),0); class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_list,gensym ("listplugins"),0); class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_plug,gensym ("plug"),A_SYMBOL,0); class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_active,gensym ("active"),A_FLOAT,0); class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_reset,gensym ("reset"),0); class_addmethod (plugin_tilde_class,nullfn,gensym ("signal"),0); } static void* plugin_tilde_new (t_symbol* s_name, t_symbol* s_lib_name) { Pd_Plugin_Tilde* x = NULL; unsigned i = 0; /* Allocate object struct */ x = (Pd_Plugin_Tilde*)pd_new (plugin_tilde_class); if(NULL==x)return NULL; /* Initialize object struct */ x->plugin_library = NULL; x->plugin_library_filename = NULL; x->num_audio_inputs = 2; x->num_audio_outputs = 2; x->num_control_inputs = 1; x->num_control_outputs = 1; x->audio_inlets = NULL; x->audio_outlets = NULL; x->control_outlet = NULL; x->dsp_vec = NULL; x->dsp_vec_length = 0; x->dsp_active = 0; if (s_name->s_name != NULL) { if (s_lib_name->s_name == NULL || strlen (s_lib_name->s_name) == 0) x->plugin_library_filename = plugin_tilde_search_plugin (x, s_name->s_name); else x->plugin_library_filename = strdup (s_lib_name->s_name); if (x->plugin_library_filename != NULL) { if (plugin_tilde_open_plugin (x, s_name->s_name, x->plugin_library_filename, (unsigned long)sys_getsr ())) { error("plugin~: Unable to open plugin '%s' in '%s'", s_name->s_name, x->plugin_library_filename); plugin_tilde_ladspa_close_plugin (x); } else { post("plugin~: \"%s\"", x->plugin.ladspa.type->Name); } } } /* 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*)); /* 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)); if(NULL==x->dsp_vec)return NULL; return x; } static void plugin_tilde_free (Pd_Plugin_Tilde* x) { unsigned i = 0; /* 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_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) { 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, int output_port_index) { /* Construct and outlet a "control" message with three Pd atoms */ t_atom anything_atoms[3]; 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; anything_atoms[2].a_type = A_FLOAT; anything_atoms[2].a_w.w_float = output_port_index; outlet_anything (x->control_outlet, gensym ("control"), 3, 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; if(!plugin_tilde_have_plugin(x))return; if (ctrl_name->s_name == NULL || strlen (ctrl_name->s_name) == 0) { pd_error(x, "plugin~: control messages must have a name and a value"); return; } 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_info (Pd_Plugin_Tilde* x) { unsigned port_index = 0; t_atom at[5]; LADSPA_PortDescriptor port_type; LADSPA_PortRangeHintDescriptor iHintDescriptor; if(!plugin_tilde_have_plugin(x))return; for (port_index = 0; port_index < x->plugin.ladspa.type->PortCount; port_index++) { port_type = x->plugin.ladspa.type->PortDescriptors[port_index]; iHintDescriptor = x->plugin.ladspa.type->PortRangeHints[port_index].HintDescriptor; t_symbol*xlet=gensym("unknown"); t_symbol*type=gensym("unknown"); t_symbol*name=gensym("unknown"); t_float bound_lo=0.; t_float bound_hi=1.; if(LADSPA_IS_PORT_INPUT (port_type)) xlet=gensym("in"); else if (LADSPA_IS_PORT_OUTPUT (port_type)) xlet=gensym("out"); if (LADSPA_IS_PORT_CONTROL (port_type)) type=gensym("control"); else if (LADSPA_IS_PORT_AUDIO (port_type)) type=gensym("audio"); name=gensym(x->plugin.ladspa.type->PortNames[port_index]); if (LADSPA_IS_HINT_BOUNDED_BELOW(iHintDescriptor)) bound_lo=x->plugin.ladspa.type->PortRangeHints[port_index].LowerBound; if (LADSPA_IS_HINT_BOUNDED_ABOVE(iHintDescriptor)) bound_hi=x->plugin.ladspa.type->PortRangeHints[port_index].UpperBound; // post("port#%d: %s %s %s %f..%f", port_index, xlet->s_name, type->s_name, name->s_name, bound_lo, bound_hi); SETSYMBOL(at+0, xlet); SETSYMBOL(at+1, type); SETSYMBOL(at+2, name); SETFLOAT (at+3, bound_lo); SETFLOAT (at+4, bound_hi); outlet_anything (x->control_outlet, gensym ("port"), 5, at); } } static void plugin_tilde_list (Pd_Plugin_Tilde* x) { void* user_data[1]; user_data[0] = x; plugin_tilde_pushlocale(); LADSPAPluginSearch(plugin_tilde_ladspa_describe,(void*)user_data); plugin_tilde_poplocale(); } static void plugin_tilde_ladspa_describe(const char * pcFullFilename, void * pvPluginHandle, LADSPA_Descriptor_Function fDescriptorFunction, void* user_data) { Pd_Plugin_Tilde* x = (((void**)user_data)[0]); t_atom at[1]; const LADSPA_Descriptor * psDescriptor; long lIndex; SETSYMBOL(at, gensym(pcFullFilename)); outlet_anything (x->control_outlet, gensym ("library"), 1, at); for (lIndex = 0; (psDescriptor = fDescriptorFunction(lIndex)) != NULL; lIndex++) { SETSYMBOL(at, gensym ((char*)psDescriptor->Name)); outlet_anything (x->control_outlet, gensym ("name"), 1, at); SETSYMBOL(at, gensym ((char*)psDescriptor->Label)); outlet_anything (x->control_outlet, gensym ("label"), 1, at); SETFLOAT(at, psDescriptor->UniqueID); outlet_anything (x->control_outlet, gensym ("id"), 1, at); SETSYMBOL(at, gensym ((char*)psDescriptor->Maker)); outlet_anything (x->control_outlet, gensym ("maker"), 1, at); } } static void plugin_tilde_active (Pd_Plugin_Tilde* x, t_float active) { x->dsp_active = active; } static void plugin_tilde_plug (Pd_Plugin_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 (x, plug_name->s_name); if (x->plugin_library_filename == NULL) error("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 ())) error("plugin~: Unable to open plugin"); else { post("plugin~: \"%s\"", x->plugin.ladspa.type->Name); } } static void plugin_tilde_reset (Pd_Plugin_Tilde* x) { plugin_tilde_ladspa_reset (x); } 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; 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) { return plugin_tilde_ladspa_search_plugin (x, name); } static int plugin_tilde_open_plugin (Pd_Plugin_Tilde* x, const char* name, const char* lib_name, unsigned long sample_rate) { int ret = 0; verbose(2, "plugin~: open_plugin (x, \"%s\", \"%s\", %ld);", name, lib_name, sample_rate); ret = plugin_tilde_ladspa_open_plugin (x, name, lib_name, sample_rate); if (ret == 0) { x->dsp_active = 1; verbose(1, "plugin~: plugin active"); } // plugin_tilde_info (x); return ret; } static void plugin_tilde_close_plugin (Pd_Plugin_Tilde* x) { verbose(2, "plugin~: close_plugin (x)"); plugin_tilde_ladspa_close_plugin (x); verbose(1, "plugin~: destructed plugin successfully"); } static void plugin_tilde_apply_plugin (Pd_Plugin_Tilde* x) { if (x->dsp_active == 1) plugin_tilde_ladspa_apply_plugin (x); } static void plugin_tilde_connect_audio (Pd_Plugin_Tilde* x, float** audio_inputs, float** audio_outputs, unsigned long num_samples) { plugin_tilde_ladspa_connect_audio (x, audio_inputs, audio_outputs, num_samples); } static void plugin_tilde_set_control_input_by_name (Pd_Plugin_Tilde* x, const char* name, float value) { plugin_tilde_ladspa_set_control_input_by_name (x, name, value); } 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 */ { plugin_tilde_ladspa_set_control_input_by_index (x, index_, value); } const char* plugin_tilde_ladspa_search_plugin (Pd_Plugin_Tilde* x, const char* name) { char* lib_name = NULL; void* user_data[2]; user_data[0] = (void*)(&lib_name); user_data[1] = (void*)name; lib_name = NULL; plugin_tilde_pushlocale(); LADSPAPluginSearch (plugin_tilde_ladspa_search_plugin_callback, (void*)user_data); plugin_tilde_poplocale(); /* The callback (allocates and) writes lib_name, if it finds the plugin */ return lib_name; } static void plugin_tilde_ladspa_search_plugin_callback (const char* full_filename, void* plugin_handle, LADSPA_Descriptor_Function descriptor_function, void* user_data) { const LADSPA_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) { // vedrbose(1, "plugin~: searching library \"%s\"...", full_filename); for (plug_index = 0; (descriptor = descriptor_function (plug_index)) != NULL; plug_index++) { // verbose(1, "plugin~: label \"%s\"", descriptor->Label); if (strcasecmp (name, descriptor->Label) == 0) { /* found a matching plugin */ *out_lib_name = strdup (full_filename); verbose(1, "plugin~: found plugin \"%s\" in library \"%s\"", name, full_filename); /* don't need to look any further */ break; } } } } int plugin_tilde_ladspa_open_plugin (Pd_Plugin_Tilde* x, const char* name, const char* lib_name, unsigned long sample_rate) { /* precondition(s) */ assert (x != NULL); assert (lib_name != NULL); assert (name != NULL); assert (sample_rate != 0); /* Initialize object struct */ x->plugin.ladspa.type = NULL; x->plugin.ladspa.instance = NULL; x->plugin.ladspa.control_input_values = NULL; x->plugin.ladspa.control_output_values = NULL; x->plugin.ladspa.control_input_ports = NULL; x->plugin.ladspa.control_output_ports = NULL; x->plugin.ladspa.prev_control_output_values = NULL; x->plugin.ladspa.prev_control_output_values_invalid = 1; x->plugin.ladspa.outofplace_audio_outputs = NULL; x->plugin.ladspa.actual_audio_outputs = NULL; x->plugin.ladspa.num_samples = 0; x->plugin.ladspa.sample_rate = sample_rate; /* Attempt to load the plugin. */ plugin_tilde_pushlocale(); x->plugin_library = loadLADSPAPluginLibrary (lib_name); if (x->plugin_library == NULL) { /* error */ plugin_tilde_poplocale(); error("plugin~: Unable to load LADSPA plugin library \"%s\"", lib_name); return 1; } x->plugin.ladspa.type = findLADSPAPluginDescriptor (x->plugin_library, lib_name, name); plugin_tilde_poplocale(); if (x->plugin.ladspa.type == NULL) { error("plugin~: Unable to find LADSPA plugin \"%s\" within library \"%s\"", name, lib_name); return 1; } /* Construct the plugin. */ x->plugin.ladspa.instance = x->plugin.ladspa.type->instantiate (x->plugin.ladspa.type, sample_rate); if (x->plugin.ladspa.instance == NULL) { /* error */ error("plugin~: Unable to instantiate LADSPA plugin \"%s\"", x->plugin.ladspa.type->Name); return 1; } verbose(1, "plugin~: constructed plugin \"%s\" successfully", x->plugin.ladspa.type->Name); /* Find out the number of inputs and outputs needed. */ plugin_tilde_ladspa_count_ports (x); /* Allocate memory for control values */ if (plugin_tilde_ladspa_alloc_control_memory (x)) { error("plugin~: out of memory"); return 1; /* error */ } /* Connect control ports with buffers */ plugin_tilde_ladspa_connect_control_ports (x); /* Activate the plugin. */ if (x->plugin.ladspa.type->activate != NULL) { x->plugin.ladspa.type->activate (x->plugin.ladspa.instance); } /* success */ return 0; } void plugin_tilde_ladspa_close_plugin (Pd_Plugin_Tilde* x) { /* precondition(s) */ if (x->plugin.ladspa.instance != NULL) { /* Deactivate the plugin. */ if (x->plugin.ladspa.type->deactivate != NULL) { x->plugin.ladspa.type->deactivate (x->plugin.ladspa.instance); } /* Destruct the plugin. */ x->plugin.ladspa.type->cleanup (x->plugin.ladspa.instance); x->plugin.ladspa.instance = NULL; } /* Free the control value memory */ plugin_tilde_ladspa_free_control_memory (x); if (x->plugin_library != NULL) { unloadLADSPAPluginLibrary (x->plugin_library); x->plugin_library = NULL; x->plugin.ladspa.type = NULL; } /* Free the out-of-place memory */ plugin_tilde_ladspa_free_outofplace_memory (x); } void plugin_tilde_ladspa_apply_plugin (Pd_Plugin_Tilde* x) { unsigned i; /* Run the plugin on Pd's buffers */ x->plugin.ladspa.type->run (x->plugin.ladspa.instance, x->plugin.ladspa.num_samples); /* Copy out-of-place buffers to Pd buffers if used */ if (x->plugin.ladspa.outofplace_audio_outputs != NULL) { for (i = 0; i < x->num_audio_outputs; i++) { unsigned j; for (j = 0; j < (unsigned)x->plugin.ladspa.num_samples; j++) { x->plugin.ladspa.actual_audio_outputs[i][j] = x->plugin.ladspa.outofplace_audio_outputs[i][j]; } } } /* Compare control output values to previous and send control messages, if necessary */ for (i = 0; i < x->num_control_outputs; i++) { /* Check whether the prev values have been initialized; if not, send a control message for each of the control outputs */ if ((x->plugin.ladspa.control_output_values[i] != x->plugin.ladspa.prev_control_output_values[i]) || x->plugin.ladspa.prev_control_output_values_invalid) { /* Emit a control message */ plugin_tilde_emit_control_output (x, x->plugin.ladspa.type->PortNames[x->plugin.ladspa.control_output_ports[i]], x->plugin.ladspa.control_output_values[i], i); /* Update the corresponding control monitoring value */ x->plugin.ladspa.prev_control_output_values[i] = x->plugin.ladspa.control_output_values[i]; } } x->plugin.ladspa.prev_control_output_values_invalid = 0; } void plugin_tilde_ladspa_reset (Pd_Plugin_Tilde* x) { /* precondition(s) */ if(!plugin_tilde_have_plugin(x))return; if (x->plugin.ladspa.type->activate != NULL && x->plugin.ladspa.type->deactivate == NULL) { verbose(1, "plugin~: Warning: Plug-in defines activate() method but no deactivate() method"); } /* reset plug-in by first deactivating and then re-activating it */ if (x->plugin.ladspa.type->deactivate != NULL) { x->plugin.ladspa.type->deactivate (x->plugin.ladspa.instance); } if (x->plugin.ladspa.type->activate != NULL) { x->plugin.ladspa.type->activate (x->plugin.ladspa.instance); } } void plugin_tilde_ladspa_connect_audio (Pd_Plugin_Tilde* x, float** audio_inputs, float** audio_outputs, unsigned long num_samples) { unsigned port_index = 0; unsigned input_count = 0; unsigned output_count = 0; if(!plugin_tilde_have_plugin(x))return; /* Allocate out-of-place memory if needed */ if (plugin_tilde_ladspa_alloc_outofplace_memory (x, num_samples)) { error("plugin~: out of memory"); return; } if (x->plugin.ladspa.outofplace_audio_outputs != NULL) { x->plugin.ladspa.actual_audio_outputs = audio_outputs; audio_outputs = x->plugin.ladspa.outofplace_audio_outputs; } input_count = 0; output_count = 0; for (port_index = 0; port_index < x->plugin.ladspa.type->PortCount; port_index++) { LADSPA_PortDescriptor port_type; port_type = x->plugin.ladspa.type->PortDescriptors[port_index]; if (LADSPA_IS_PORT_AUDIO (port_type)) { if (LADSPA_IS_PORT_INPUT (port_type)) { x->plugin.ladspa.type->connect_port (x->plugin.ladspa.instance, port_index, (LADSPA_Data*)audio_inputs[input_count]); input_count++; } else if (LADSPA_IS_PORT_OUTPUT (port_type)) { x->plugin.ladspa.type->connect_port (x->plugin.ladspa.instance, port_index, (LADSPA_Data*)audio_outputs[output_count]); output_count++; } } } x->plugin.ladspa.num_samples = num_samples; } void plugin_tilde_ladspa_set_control_input_by_name (Pd_Plugin_Tilde* x, const char* name, float value) { unsigned port_index = 0; unsigned ctrl_input_index = 0; int found_port = 0; /* boolean */ /* precondition(s) */ assert (x != NULL); if (name == NULL || strlen (name) == 0) { pd_error(x, "plugin~: no control port name specified"); return; } if(NULL==x->plugin.ladspa.type) { error("plugin~: unable to determine LADSPA type"); 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->plugin.ladspa.type->PortCount; port_index++) { LADSPA_PortDescriptor port_type; port_type = x->plugin.ladspa.type->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->plugin.ladspa.type->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) { error("plugin~: plugin doesn't have a control input port named \"%s\"", name); return; } plugin_tilde_ladspa_set_control_input_by_index (x, ctrl_input_index, value); } void plugin_tilde_ladspa_set_control_input_by_index (Pd_Plugin_Tilde* x, unsigned ctrl_input_index, float value) { unsigned port_index = 0; unsigned ctrl_input_count = 0; int found_port = 0; /* boolean */ /* precondition(s) */ assert (x != NULL); /* assert (ctrl_input_index >= 0); causes a warning */ /* assert (ctrl_input_index < x->num_control_inputs); */ if(NULL==x->plugin.ladspa.type) { error("plugin~: unable to determine LADSPA type"); return; } if (ctrl_input_index >= x->num_control_inputs) { error("plugin~: control port number %d is out of range [1, %d]", ctrl_input_index + 1, x->num_control_inputs); return; } /* bound parameter value */ /* sigh, need to find the N'th ctrl input port by hand */ found_port = 0; ctrl_input_count = 0; for (port_index = 0; port_index < x->plugin.ladspa.type->PortCount; port_index++) { LADSPA_PortDescriptor port_type; port_type = x->plugin.ladspa.type->PortDescriptors[port_index]; if (LADSPA_IS_PORT_CONTROL (port_type) && LADSPA_IS_PORT_INPUT (port_type)) { if (ctrl_input_index == ctrl_input_count) { found_port = 1; break; } ctrl_input_count++; } } if (!found_port) { error("plugin~: plugin doesn't have %ud control input ports", ctrl_input_index + 1); return; } /* out of bounds rules WTF!!!!~ if (x->plugin.ladspa.type->PortRangeHints != NULL) { const LADSPA_PortRangeHint* hint = &x->plugin.ladspa.type->PortRangeHints[port_index]; if (LADSPA_IS_HINT_BOUNDED_BELOW (hint->HintDescriptor)) { bounded_from_below = 1; lower_bound = hint->LowerBound; if (LADSPA_IS_HINT_SAMPLE_RATE (hint->HintDescriptor)) { assert (x->plugin.ladspa.sample_rate != 0); lower_bound *= (float)x->plugin.ladspa.sample_rate; } } if (LADSPA_IS_HINT_BOUNDED_ABOVE (hint->HintDescriptor)) { bounded_from_above = 1; upper_bound = hint->UpperBound; if (LADSPA_IS_HINT_SAMPLE_RATE (hint->HintDescriptor)) { assert (x->plugin.ladspa.sample_rate != 0); upper_bound *= (float)x->plugin.ladspa.sample_rate; } } } bounded = 0; if (bounded_from_below && value < lower_bound) { value = lower_bound; bounded = 1; } if (bounded_from_above && value > upper_bound) { value = upper_bound; bounded = 1; } */ /* set the appropriate control port value */ x->plugin.ladspa.control_input_values[ctrl_input_index] = value; // verbose(1, "plugin~: control change control input port #%ud to value %f", ctrl_input_index + 1, value); } static void plugin_tilde_ladspa_count_ports (Pd_Plugin_Tilde* x) { unsigned i = 0; x->num_audio_inputs = 0; x->num_audio_outputs = 0; x->num_control_inputs = 0; x->num_control_outputs = 0; for (i = 0; i < x->plugin.ladspa.type->PortCount; i++) { LADSPA_PortDescriptor port_type; port_type = x->plugin.ladspa.type->PortDescriptors[i]; if (LADSPA_IS_PORT_AUDIO (port_type)) { if (LADSPA_IS_PORT_INPUT (port_type)) { x->num_audio_inputs++; } else if (LADSPA_IS_PORT_OUTPUT (port_type)) { x->num_audio_outputs++; } } else if (LADSPA_IS_PORT_CONTROL (port_type)) { if (LADSPA_IS_PORT_INPUT (port_type)) { x->num_control_inputs++; } else if (LADSPA_IS_PORT_OUTPUT (port_type)) { x->num_control_outputs++; } } } verbose(1, "plugin~: plugin ports: audio %d/%d ctrl %d/%d", x->num_audio_inputs, x->num_audio_outputs, x->num_control_inputs, x->num_control_outputs); } static void plugin_tilde_ladspa_connect_control_ports (Pd_Plugin_Tilde* x) { unsigned port_index = 0; unsigned input_count = 0; unsigned output_count = 0; input_count = 0; output_count = 0; for (port_index = 0; port_index < x->plugin.ladspa.type->PortCount; port_index++) { LADSPA_PortDescriptor port_type; port_type = x->plugin.ladspa.type->PortDescriptors[port_index]; if (LADSPA_IS_PORT_CONTROL (port_type)) { if (LADSPA_IS_PORT_INPUT (port_type)) { x->plugin.ladspa.type->connect_port (x->plugin.ladspa.instance, port_index, &x->plugin.ladspa.control_input_values[input_count]); x->plugin.ladspa.control_input_ports[input_count] = port_index; input_count++; } else if (LADSPA_IS_PORT_OUTPUT (port_type)) { x->plugin.ladspa.type->connect_port (x->plugin.ladspa.instance, port_index, &x->plugin.ladspa.control_output_values[output_count]); x->plugin.ladspa.control_output_ports[output_count] = port_index; output_count++; } } } } static int plugin_tilde_ladspa_alloc_outofplace_memory (Pd_Plugin_Tilde* x, unsigned long buflen) { assert (x != NULL); plugin_tilde_ladspa_free_outofplace_memory (x); if (LADSPA_IS_INPLACE_BROKEN (x->plugin.ladspa.type->Properties)) { unsigned i = 0; x->plugin.ladspa.outofplace_audio_outputs = (t_float**) calloc (x->num_audio_outputs, sizeof (t_float*)); if (x->plugin.ladspa.outofplace_audio_outputs == NULL) { return 1; /* error */ } for (i = 0; i < x->num_audio_outputs; i++) { x->plugin.ladspa.outofplace_audio_outputs[i] = (t_float*) calloc (buflen, sizeof (t_float)); if (x->plugin.ladspa.outofplace_audio_outputs[i] == NULL) { /* FIXME free got buffers? */ return 1; /* error */ } } } return 0; /* success */ } static void plugin_tilde_ladspa_free_outofplace_memory (Pd_Plugin_Tilde* x) { assert (x != NULL); if (x->plugin.ladspa.outofplace_audio_outputs != NULL) { unsigned i = 0; for (i = 0; i < x->num_audio_outputs; i++) { free (x->plugin.ladspa.outofplace_audio_outputs[i]); } free (x->plugin.ladspa.outofplace_audio_outputs); x->plugin.ladspa.outofplace_audio_outputs = NULL; } } static int plugin_tilde_ladspa_alloc_control_memory (Pd_Plugin_Tilde* x) { x->plugin.ladspa.control_input_values = NULL; x->plugin.ladspa.control_input_ports = NULL; if (x->num_control_inputs > 0) { x->plugin.ladspa.control_input_values = (float*)calloc (x->num_control_inputs, sizeof (float)); x->plugin.ladspa.control_input_ports = (int*)calloc (x->num_control_inputs, sizeof (int)); if (x->plugin.ladspa.control_input_values == NULL || x->plugin.ladspa.control_input_ports == NULL) { return 1; /* error */ } } x->plugin.ladspa.control_output_values = NULL; x->plugin.ladspa.control_output_ports = NULL; x->plugin.ladspa.prev_control_output_values = NULL; if (x->num_control_outputs > 0) { x->plugin.ladspa.control_output_values = (float*)calloc (x->num_control_outputs, sizeof (float)); x->plugin.ladspa.control_output_ports = (int*)calloc (x->num_control_outputs, sizeof (int)); x->plugin.ladspa.prev_control_output_values = (float*)calloc (x->num_control_outputs, sizeof (float)); if (x->plugin.ladspa.control_output_values == NULL || x->plugin.ladspa.prev_control_output_values == NULL || x->plugin.ladspa.control_output_ports == NULL) { return 1; /* error */ } } /* Indicate initial conditions */ x->plugin.ladspa.prev_control_output_values_invalid = 1; return 0; /* success */ } static void plugin_tilde_ladspa_free_control_memory (Pd_Plugin_Tilde* x) { if (x->plugin.ladspa.control_input_values != NULL) { free (x->plugin.ladspa.control_input_values); x->plugin.ladspa.control_input_values = NULL; } if (x->plugin.ladspa.control_output_values != NULL) { free (x->plugin.ladspa.control_output_values); x->plugin.ladspa.control_output_values = NULL; } if (x->plugin.ladspa.prev_control_output_values != NULL) { free (x->plugin.ladspa.prev_control_output_values); x->plugin.ladspa.prev_control_output_values = NULL; } if (x->plugin.ladspa.control_input_ports != NULL) { free (x->plugin.ladspa.control_input_ports); x->plugin.ladspa.control_input_ports = NULL; } if (x->plugin.ladspa.control_output_ports != NULL) { free (x->plugin.ladspa.control_output_ports); x->plugin.ladspa.control_output_ports = NULL; } } static int plugin_tilde_have_ladspa_plugin(Pd_Plugin_Tilde* x) { if(NULL==x->plugin.ladspa.instance) { error("plugin~: LADSPA instance not found"); return 0; } if(NULL==x->plugin.ladspa.type) { error("plugin~: LADSPA type not found"); return 0; } return 1; } static int plugin_tilde_have_plugin(Pd_Plugin_Tilde* x) { if(NULL==x)return 0; if (NULL==x->plugin_library || x->plugin_library_filename == NULL) { error("plugin~: plugin not found"); return 0; } if(NULL==x->plugin.ladspa.type) { error("plugin~: unable to determine LADSPA type"); return 0; } return plugin_tilde_have_ladspa_plugin(x); } pd-plugin_0.2.1/README.txt0000644000076500007650000000046111440621270013645 0ustar hanshansLADSPA and VST plug-in hosting for Pd This is a Pd tilde object for hosting LADSPA audio plug-ins. The LADSPA plug-in interface is supported completely. The object will search your LADSPA path for plugins, which are loadable by name as an argument to the plugin~ object. Jarno Seppänen, jams@cs.tut.fi pd-plugin_0.2.1/LICENSE.txt0000644000076500007650000003574511440621270014007 0ustar hanshansGNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. 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 pd-plugin_0.2.1/plugin~-meta.pd0000644000076500007650000000025211440621270015112 0ustar hanshans#N canvas 15 49 200 200 10; #N canvas 25 49 420 300 META 1; #X text 10 25 AUTHOR Jarno Seppänen ; #X text 10 10 VERSION 0.2.1; #X restore 10 10 pd META; pd-plugin_0.2.1/SConstruct0000644000076500007650000000117111426363557014217 0ustar hanshansimport glob import os import re prefix = "/usr/local/lib/pd" env = Environment(CPPPATH = Split(prefix + '/src /usr/include /usr/local/include . ../../pd/src ../../src src'), CPPDEFINES=['PD','UNIX'], SHLIBPREFIX = '', SHLIBSUFFIX = '.pd_linux', CCFLAGS = '-pipe -O2 -g') #check for headers conf = Configure(env) if conf.CheckCHeader('locale.h'): env.Append(CPPDEFINES='HAVE_LOCALE_H') external = env.SharedLibrary('plugin~',glob.glob('*.c')) env.Alias('install', env.Install(os.path.join(prefix, 'extra'), external)) env.Alias('install', env.Install(os.path.join(prefix, 'doc/5.reference'),'plugin~-help.pd')) Default(external) pd-plugin_0.2.1/Makefile0000644000076500007650000002521411443243253013616 0ustar hanshans## Pd library template version 1.0.4 # For instructions on how to use this template, see: # http://puredata.info/docs/developer/MakefileTemplate LIBRARY_NAME = plugin~ # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically SOURCES = plugin~.c # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically PDOBJECTS = # example patches and related files, in the 'examples' subfolder EXAMPLES = # manuals and related files, in the 'manual' subfolder MANUAL = # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included EXTRA_DIST = plugin~-gui.pd ChangeLog SConstruct jutils.h plugin~.h # NOTE: modified to build jload.c and jsearch.c and link it into plugin~ EXTRA_SOURCES = jsearch.c jload.c #------------------------------------------------------------------------------# # # things you might need to edit if you are using other C libraries # #------------------------------------------------------------------------------# CFLAGS = -DPD -I"$(PD_INCLUDE)" -Wall -W -g LDFLAGS = LIBS = #------------------------------------------------------------------------------# # # you shouldn't need to edit anything below here, if we did it right :) # #------------------------------------------------------------------------------# # get library version from meta file LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd) CFLAGS += -DVERSION='"$(LIBRARY_VERSION)"' PD_INCLUDE = $(PD_PATH)/include # where to install the library, overridden below depending on platform prefix = /usr/local libdir = $(prefix)/lib pkglibdir = $(libdir)/pd-externals objectsdir = $(pkglibdir) INSTALL = install INSTALL_PROGRAM = $(INSTALL) -p -m 644 INSTALL_DATA = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -p -m 755 -d ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION) UNAME := $(shell uname -s) ifeq ($(UNAME),Darwin) CPU := $(shell uname -p) ifeq ($(CPU),arm) # iPhone/iPod Touch SOURCES += $(SOURCES_iphoneos) EXTENSION = pd_darwin OS = iphoneos PD_PATH = /Applications/Pd-extended.app/Contents/Resources IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin CC=$(IPHONE_BASE)/gcc CPP=$(IPHONE_BASE)/cpp CXX=$(IPHONE_BASE)/g++ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer CFLAGS := $(IPHONE_CFLAGS) $(OPT_CFLAGS) $(CFLAGS) LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) else # Mac OS X SOURCES += $(SOURCES_macosx) EXTENSION = pd_darwin OS = macosx PD_PATH = /Applications/Pd-extended.app/Contents/Resources OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast # build universal 32-bit on 10.4 and 32/64 on newer ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 SOURCES += $(SOURCES_iphoneos) endif CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib # if the 'pd' binary exists, check the linking against it to aid with stripping LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd) LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) # install into ~/Library/Pd on Mac OS X since /usr/local isn't used much pkglibdir=$(HOME)/Library/Pd endif endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += -fPIC LDFLAGS += -Wl,--export-dynamic -shared -fPIC LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_cygwin) EXTENSION = dll OS = cygwin PD_PATH = $(cygpath $(PROGRAMFILES))/pd OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -Wl,--export-dynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" LIBS += -lc -lpd STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif ifeq (MINGW,$(findstring MINGW,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_windows) EXTENSION = dll OS = windows PD_PATH = $(shell cd "$(PROGRAMFILES)"/pd && pwd) OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer -march=i686 -mtune=pentium4 CFLAGS += -mms-bitfields LDFLAGS += -s -shared -Wl,--enable-auto-import LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.c=-help.pd) CFLAGS += $(OPT_CFLAGS) .PHONY = install libdir_install single_install install-doc install-exec install-examples install-manual clean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) %.o: %.c $(CC) $(CFLAGS) -o "$*.o" -c "$*.c" plugin~.$(EXTENSION): plugin~.o $(EXTRA_SOURCES:.c=.o) $(CC) $(LDFLAGS) -o plugin~.$(EXTENSION) plugin~.o $(EXTRA_SOURCES:.c=.o) $(LIBS) chmod a-x plugin~.$(EXTENSION) # this links everything into a single binary file $(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(CC) $(LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples install-manual $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES))" || (\ $(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) # install library linked as single binary single_install: $(LIBRARY_NAME) install-doc install-exec $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) install-doc: $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \ $(INSTALL_DATA) $(HELPPATCHES) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt $(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt install-examples: test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \ done install-manual: test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done clean: -rm -f -- $(EXTRA_SOURCES:.c=.o) -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) -rm -f -- $(SOURCES:.c=.$(EXTENSION)) -rm -f -- $(LIBRARY_NAME).o -rm -f -- $(LIBRARY_NAME).$(EXTENSION) distclean: clean -rm -f -- $(DISTBINDIR).tar.gz -rm -rf -- $(DISTBINDIR) -rm -f -- $(DISTDIR).tar.gz -rm -rf -- $(DISTDIR) -rm -f -- $(ORIGDIR).tar.gz -rm -rf -- $(ORIGDIR) $(DISTBINDIR): $(INSTALL_DIR) $(DISTBINDIR) libdir: all $(DISTBINDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) $(INSTALL_DATA) $(SOURCES) $(DISTBINDIR) $(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTBINDIR) # tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) $(DISTDIR): $(INSTALL_DIR) $(DISTDIR) $(ORIGDIR): $(INSTALL_DIR) $(ORIGDIR) dist: $(DISTDIR) $(INSTALL_DATA) Makefile $(DISTDIR) $(INSTALL_DATA) README.txt $(DISTDIR) $(INSTALL_DATA) LICENSE.txt $(DISTDIR) $(INSTALL_DATA) $(EXTRA_SOURCES) $(DISTDIR) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd $(DISTDIR) test -z "$(strip $(ALLSOURCES))" || \ $(INSTALL_DATA) $(ALLSOURCES) $(DISTDIR) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) $(DISTDIR) test -z "$(strip $(HELPPATCHES))" || \ $(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_DATA) $(EXTRA_DIST) $(DISTDIR) test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DISTDIR)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \ done test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DISTDIR)/manual && \ for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \ done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package dpkg-source: debclean make distclean dist mv $(DISTDIR) $(ORIGDIR) tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR) rm -f -- $(DISTDIR).tar.gz rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) etags: etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h showsetup: @echo "CFLAGS: $(CFLAGS)" @echo "LDFLAGS: $(LDFLAGS)" @echo "LIBS: $(LIBS)" @echo "PD_INCLUDE: $(PD_INCLUDE)" @echo "PD_PATH: $(PD_PATH)" @echo "objectsdir: $(objectsdir)" @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "UNAME: $(UNAME)" @echo "CPU: $(CPU)" @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" pd-plugin_0.2.1/jutils.h0000644000076500007650000000471210755130527013645 0ustar hanshans/* 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~ */ #ifndef LADSPA_SDK_LOAD_PLUGIN_LIB #define LADSPA_SDK_LOAD_PLUGIN_LIB /*****************************************************************************/ #include "ladspa.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, LADSPA_Descriptor_Function fDescriptorFunction, void* user_data); /* 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 */ pd-plugin_0.2.1/jsearch.c0000644000076500007650000000670711443243074013750 0ustar hanshans/* 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~ */ /*****************************************************************************/ #include #include #include #include #include #include #include /*****************************************************************************/ #include "ladspa.h" #include "jutils.h" /*****************************************************************************/ /* Search just the one directory. */ static void LADSPADirectoryPluginSearch (const char * pcDirectory, LADSPAPluginSearchCallbackFunction fCallbackFunction, void* user_data) { char * pcFilename; DIR * psDirectory; LADSPA_Descriptor_Function fDescriptorFunction; long lDirLength; long iNeedSlash; struct dirent * psDirectoryEntry; void * pvPluginHandle; 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(); fDescriptorFunction = (LADSPA_Descriptor_Function)dlsym(pvPluginHandle, "ladspa_descriptor"); if (dlerror() == NULL && fDescriptorFunction) { /* We've successfully found a ladspa_descriptor function. Pass it to the callback function. */ fCallbackFunction(pcFilename, pvPluginHandle, fDescriptorFunction, user_data); 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; const char * pcStart; pcLADSPAPath = getenv("LADSPA_PATH"); if (!pcLADSPAPath) { //fprintf(stderr, "Warning: no LADSPA_PATH, assuming /usr/lib/ladspa:/usr/local/lib/ladspa\n"); #ifdef __APPLE__ pcLADSPAPath = "/sw/lib/ladspa:/usr/local/lib/ladspa"; #else pcLADSPAPath = "/usr/lib/ladspa:/usr/local/lib/ladspa"; #endif } 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 */ pd-plugin_0.2.1/jload.c0000644000076500007650000001246211443243074013415 0ustar hanshans/* 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~ */ /*****************************************************************************/ #include #include #include #include /*****************************************************************************/ #include "ladspa.h" #include "jutils.h" /*****************************************************************************/ /* This function provides a wrapping of dlopen(). When the filename is not an absolute path (i.e. does not begin with / character), this routine will search the LADSPA_PATH for the file. */ static void * dlopenLADSPA(const char * pcFilename, int iFlag) { char * pcBuffer; const char * pcEnd; const char * pcLADSPAPath; const char * pcStart; int iEndsInSO; int iNeedSlash; size_t iFilenameLength; void * pvResult; 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 = getenv("LADSPA_PATH"); 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); free(pcBuffer); } 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 */ pd-plugin_0.2.1/plugin~-gui.pd0000644000076500007650000000652510755130527014771 0ustar hanshans#N canvas 0 220 950 684 12; #X obj 497 2 adc~; #X obj 450 78 dac~; #X msg 240 3 info; #X msg 274 2 listplugins; #X obj 388 105 route id name label maker; #X obj 387 103 widget q q1 -bg black -fg "#ff0045" -height 42 -width 5; #X obj 418 103 widget q q1 -bg black -fg white -height 42 -width 23 ; #X obj 443 622 route scroll; #X msg 444 645 scroll \$1; #X obj 422 106 prepend add; #X obj 557 103 widget q q1 -bg black -fg orange -height 42 -width 16 ; #X obj 567 642 route scroll; #X msg 566 667 scroll \$1; #X obj 391 644 route scroll; #X msg 391 667 scroll \$1; #X obj 686 629 route scroll; #X msg 684 652 scroll \$1; #X obj 654 103 widget q q1 -bg black -fg cyan -height 42 -width 49 ; #X obj 390 106 prepend add; #X obj 560 107 prepend add; #X obj 658 109 prepend add; #X obj 319 50 plugin~ tap_equalizer; #X obj 41 69 widget q q1 -width 24 -bg gray -fg purple -height 18; #X obj 107 76 unpack s f f; #X obj 298 100 route port; #X obj 298 119 route in; #X obj 298 138 route control; #X obj 87 76 a2l; #X msg 238 70 add \$1; #X msg 189 70 add \$1; #X obj 187 69 widget q q1 -width 8 -bg gray -fg purple -height 18; #X obj 237 69 widget q q1 -width 8 -bg gray -fg purple -height 18; #X msg 188 70 clear; #X obj 113 425 widget ngrid n1 #w 256 #h 256; #X obj 193 325 niagara 1; #X obj 193 382 glue; #X obj 193 363 a2l; #X obj 193 401 prepend add; #X msg 112 393 move swarm; #X msg 120 373 move; #X obj 369 8 prepend control; #X text 557 7 plusgin~; #X text 570 23 currently supports LADSPA; #X text 643 400 if you can see this \, you need widgets from /extensions/gui/ix ; #X msg 114 428 redefine; #X obj 242 344 expr $f1 + ($f2-$f1)/2.; #X obj 193 344 Append; #X text 41 51 param; #X text 211 52 min; #X text 261 52 max; #X text 388 85 id; #X text 522 85 name; #X text 628 85 label; #X text 916 85 maker; #X obj 559 667 route symbol; #X msg 497 45 plug \$1; #X obj 590 59 plugain~; #X obj 422 28 demux; #X connect 0 0 21 1; #X connect 0 1 56 1; #X connect 2 0 32 0; #X connect 2 0 57 0; #X connect 3 0 21 0; #X connect 4 0 18 0; #X connect 4 1 9 0; #X connect 4 2 19 0; #X connect 4 3 20 0; #X connect 5 0 13 0; #X connect 6 0 7 0; #X connect 7 0 8 0; #X connect 8 0 5 0; #X connect 8 0 10 0; #X connect 8 0 17 0; #X connect 9 0 6 0; #X connect 10 0 11 0; #X connect 10 0 54 0; #X connect 11 0 12 0; #X connect 12 0 5 0; #X connect 12 0 6 0; #X connect 12 0 17 0; #X connect 13 0 14 0; #X connect 14 0 6 0; #X connect 14 0 10 0; #X connect 14 0 17 0; #X connect 15 0 16 0; #X connect 16 0 5 0; #X connect 16 0 6 0; #X connect 16 0 10 0; #X connect 17 0 15 0; #X connect 18 0 5 0; #X connect 19 0 10 0; #X connect 20 0 17 0; #X connect 21 0 4 0; #X connect 21 0 24 0; #X connect 21 1 1 0; #X connect 23 0 22 0; #X connect 23 1 29 0; #X connect 23 2 28 0; #X connect 24 0 25 0; #X connect 25 0 26 0; #X connect 26 0 27 0; #X connect 26 0 34 0; #X connect 27 0 23 0; #X connect 28 0 31 0; #X connect 29 0 30 0; #X connect 32 0 30 0; #X connect 32 0 22 0; #X connect 32 0 31 0; #X connect 32 0 44 0; #X connect 33 0 40 0; #X connect 34 0 46 0; #X connect 34 1 45 0; #X connect 34 1 35 1; #X connect 35 0 37 0; #X connect 36 0 35 0; #X connect 37 0 33 0; #X connect 38 0 33 0; #X connect 39 0 33 0; #X connect 40 0 57 0; #X connect 44 0 33 0; #X connect 45 0 46 1; #X connect 46 0 36 0; #X connect 54 0 55 0; #X connect 55 0 56 0; #X connect 56 0 24 0; #X connect 56 1 1 1; #X connect 57 0 21 0; #X connect 57 1 56 0; pd-plugin_0.2.1/ChangeLog0000644000076500007650000000526410755130527013737 0ustar hanshans2005-05-00 Carmen Rocco * VST support is gone, actually, it was never here, but removed some stuff to clean it up, VST? detour to /externals/grill/vst/ * you can create the plugin without arguments, it will default to 2 channels new methods: * active: enable or disable the plugin * listplugins: lists all your LADSPA plugins... * info: info on the current plugin, like assignable params, etc. * plug: load a new plug 2001-04-04 Jarno Seppänen * Released version 0.2 * plugin~_ladspa.c (plugin_tilde_ladspa_set_control_input_by_name): control port name search bug fix 2001-03-10 Jarno Seppänen * plugin~_ladspa.c (plugin_tilde_ladspa_set_control_input_by_index): implemented control port value bounding * plugin~*.[ch]: added possibility to set control values by number in addition to setting then by name; this effectively enables a way around the problems Pd has with spaces 2001-03-05 Jarno Seppänen * Makefile.am: made plugin~ to install to "extra/plugin~" under the Pd installation tree * win: added new subdirectory "win" for MSVC-related files 2001-02-27 Jarno Seppänen * plugin~_vst.[ch]: implemented VST plug-in hosting * plugin~_ladspa.[ch]: separated LADSPA plug-in hosting 2001-02-26 Jarno Seppänen * vst: added new subdirectory "vst" for VST SDK files * ladspa: moved LADSPA SDK header "ladspa.h" to subdirectory "ladspa" 2000-06-15 Jarno Seppänen * Released initial release 0.1 plugin~ NEWS --- history of changes. Overview of changes in version 0.2, released April 4 2001 ========================================================= * control/parameter value setting by parameter number (starting with a '#' character) in addition to using parameter name * LADSPA: Implemented control value bounding * Support for VST 1.0 (processReplacing()) plug-ins under Windows * LADSPA bug fixes under Linux (huge thanks to Linium for quality assurance, merci! :) Overview of changes in version 0.1, released June 15 2000 ========================================================= * Initial release * Control ports mapped to Pd asynchronous messages. Input controls are changed on incoming messages and outgoing messages are sent on changes in output control values. * Audio ports mapped to Pd signal in/outlets * Searching for plug-ins in all LADSPA libraries * Resetting the plug-in's internal state on incoming "reset" messages * Printing plug-in information on incoming "print" messages * Supports out-of-place processing for plug-ins that need this * Distributed under the GNU General Public License