From 9d9262c32f4bc9c0dad8b92828acba53c889cb79 Mon Sep 17 00:00:00 2001 From: carmen rocco Date: Fri, 29 Apr 2005 00:43:36 +0000 Subject: yeah svn path=/trunk/externals/plugin~/; revision=2849 --- plugin~.c | 1016 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 779 insertions(+), 237 deletions(-) (limited to 'plugin~.c') diff --git a/plugin~.c b/plugin~.c index b9d3a8d..1525559 100644 --- a/plugin~.c +++ b/plugin~.c @@ -1,6 +1,7 @@ /* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins Copyright (C) 2000 Jarno Seppänen - $Id: plugin~.c,v 1.2 2003-01-23 12:32:04 ggeiger Exp $ + remIXed 2005 Carmen Rocco + $Id: plugin~.c,v 1.3 2005-04-29 00:43:36 ix9 Exp $ This file is part of plugin~. @@ -18,29 +19,21 @@ 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" +#include "jutils.h" -#if PLUGIN_TILDE_USE_LADSPA -#define PLUGIN_TILDE_BRAND "LADSPA" -#endif -#if PLUGIN_TILDE_USE_VST -#define PLUGIN_TILDE_BRAND "VST" +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) #endif static t_class* plugin_tilde_class = NULL; -void -plugin_tilde_setup (void) +void plugin_tilde_setup (void) { /* Make a new Pd class with 2 string creation parameters */ plugin_tilde_class = class_new (gensym ("plugin~"), @@ -53,48 +46,20 @@ plugin_tilde_setup (void) /* 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_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); - - /* 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); - - /* 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, t_symbol* s_lib_name) + 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_DEFSYM, A_DEFFLOAT, 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"),0); + class_addmethod (plugin_tilde_class,(t_method)plugin_tilde_bypass,gensym ("bypass"),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; @@ -106,9 +71,9 @@ plugin_tilde_new (t_symbol* s_name, t_symbol* s_lib_name) /* 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_audio_inputs = 2; + x->num_audio_outputs = 2; + x->num_control_inputs = 1; x->num_control_outputs = 0; x->audio_inlets = NULL; x->audio_outlets = NULL; @@ -116,60 +81,34 @@ plugin_tilde_new (t_symbol* s_name, t_symbol* s_lib_name) x->dsp_vec = NULL; x->dsp_vec_length = 0; - /* Check creation arguments */ - assert (s_name != NULL); - if (s_name->s_name == NULL || strlen (s_name->s_name) == 0) { - error ("plugin~: No " PLUGIN_TILDE_BRAND " plugin selected"); - goto PLUGIN_TILDE_NEW_RETURN_NULL; - } - - /* 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 (s_lib_name != NULL); - if (s_lib_name->s_name == NULL || strlen (s_lib_name->s_name) == 0) { + if (s_lib_name != NULL) { + if (s_lib_name->s_name == NULL || strlen (s_lib_name->s_name) == 0) { /* Search for the plugin library */ x->plugin_library_filename = plugin_tilde_search_plugin (x, s_name->s_name); if (x->plugin_library_filename == NULL) { - error ("plugin~: " PLUGIN_TILDE_BRAND " plugin not found in any library"); - goto PLUGIN_TILDE_NEW_RETURN_NULL; + post("plugin~: plugin not found in any library"); + goto PLUGIN_TILDE_NEW_RETURN_NULL; } - } - else { + } + else { /* Search in the given plugin library */ x->plugin_library_filename = strdup (s_lib_name->s_name); - } -#endif /* PLUGIN_TILDE_USE_LADSPA */ -#if PLUGIN_TILDE_USE_VST - if (s_lib_name->s_name != NULL - && strlen (s_lib_name->s_name) > 0) { - error ("plugin~: warning: superfluous creation argument \"%s\"", - s_lib_name->s_name); - } - /* Remember plugin library filename */ - x->plugin_library_filename = strdup (s_name->s_name); -#endif /* PLUGIN_TILDE_USE_VST */ - - /* Load LADSPA/VST plugin */ - if (plugin_tilde_open_plugin (x, - s_name->s_name, - x->plugin_library_filename, - (unsigned long)sys_getsr ())) { - error ("plugin~: Unable to open " PLUGIN_TILDE_BRAND " plugin"); + } + /* Load LADSPA/VST plugin */ + if (plugin_tilde_open_plugin (x, + s_name->s_name, + x->plugin_library_filename, + (unsigned long)sys_getsr ())) { + post("plugin~: Unable to open 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 @@ -196,33 +135,22 @@ plugin_tilde_new (t_symbol* s_name, t_symbol* s_lib_name) 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; + free ((void*)x->plugin_library_filename); + x->plugin_library_filename = NULL; } return NULL; /* Indicate error to Pd */ + } -static void -plugin_tilde_free (Pd_Plugin_Tilde* x) +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); @@ -261,21 +189,7 @@ plugin_tilde_free (Pd_Plugin_Tilde* x) } } -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) +static void plugin_tilde_dsp (Pd_Plugin_Tilde* x, t_signal** sp) { unsigned i = 0; unsigned long num_samples; @@ -301,8 +215,7 @@ plugin_tilde_dsp (Pd_Plugin_Tilde* x, t_signal** sp) dsp_addv (plugin_tilde_perform, x->dsp_vec_length, x->dsp_vec); } -static t_int* -plugin_tilde_perform (t_int* w) +static t_int* plugin_tilde_perform (t_int* w) { unsigned i = 0; Pd_Plugin_Tilde* x = NULL; @@ -325,8 +238,7 @@ plugin_tilde_perform (t_int* w) return w + (x->dsp_vec_length + 1); } -void -plugin_tilde_emit_control_output (Pd_Plugin_Tilde* x, +void plugin_tilde_emit_control_output (Pd_Plugin_Tilde* x, const char* name, float new_value, int output_port_index) @@ -342,8 +254,7 @@ plugin_tilde_emit_control_output (Pd_Plugin_Tilde* x, outlet_anything (x->control_outlet, gensym ("control"), 3, anything_atoms); } -static void -plugin_tilde_control (Pd_Plugin_Tilde* x, +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 */ @@ -355,7 +266,7 @@ plugin_tilde_control (Pd_Plugin_Tilde* x, /* 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"); + post("plugin~: control messages must have a name and a value"); return; } parm_num = plugin_tilde_get_parm_number (x, ctrl_name->s_name); @@ -367,46 +278,99 @@ plugin_tilde_control (Pd_Plugin_Tilde* x, } } -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) */ +static void plugin_tilde_info (Pd_Plugin_Tilde* x) { assert (x != NULL); + unsigned port_index = 0; + unsigned input_count = 0; + unsigned output_count = 0; + t_atom at[5]; + at[0].a_type = A_SYMBOL; + at[1].a_type = A_SYMBOL; + at[2].a_type = A_SYMBOL; + at[3].a_type = A_FLOAT; + at[4].a_type = A_FLOAT; + + for (port_index = 0; port_index < x->plugin.ladspa.type->PortCount; port_index++) { + LADSPA_PortDescriptor port_type; + LADSPA_PortRangeHintDescriptor iHintDescriptor; + port_type = x->plugin.ladspa.type->PortDescriptors[port_index]; + iHintDescriptor = x->plugin.ladspa.type->PortRangeHints[port_index].HintDescriptor; + + if (LADSPA_IS_PORT_INPUT (port_type)) + at[0].a_w.w_symbol = gensym ("in"); + else if (LADSPA_IS_PORT_OUTPUT (port_type)) + at[0].a_w.w_symbol = gensym ("out"); + if (LADSPA_IS_PORT_CONTROL (port_type)) + at[1].a_w.w_symbol = gensym ("control"); + else if (LADSPA_IS_PORT_AUDIO (port_type)) + at[1].a_w.w_symbol = gensym ("audio"); + at[2].a_w.w_symbol = gensym ((char*)x->plugin.ladspa.type->PortNames[port_index]); + if (LADSPA_IS_HINT_BOUNDED_BELOW(iHintDescriptor)) + at[3].a_w.w_float = x->plugin.ladspa.type->PortRangeHints[port_index].LowerBound; + else + at[3].a_w.w_float = 0; + if (LADSPA_IS_HINT_BOUNDED_ABOVE(iHintDescriptor)) + at[4].a_w.w_float = x->plugin.ladspa.type->PortRangeHints[port_index].UpperBound; + else + at[4].a_w.w_float = 1; + + outlet_anything (x->control_outlet, gensym ("port"), 5, at); + } - printf ("This is plugin~ version %s -- NO WARRANTY -- Copyright (C) 2000 Jarno Seppänen\n", - PLUGIN_TILDE_VERSION); -#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) +static void plugin_tilde_list (Pd_Plugin_Tilde* x) { + post("listing plugins\n"); + LADSPAPluginSearch(plugin_tilde_describe,x); +} + +static void plugin_tilde_describe(const char * pcFullFilename, + void * pvPluginHandle, + LADSPA_Descriptor_Function fDescriptorFunction, Pd_Plugin_Tilde* x) { + t_atom at[1]; + const LADSPA_Descriptor * psDescriptor; + long lIndex; + + at[0].a_type = A_SYMBOL; + at[0].a_w.w_symbol = gensym ((char*)pcFullFilename); + outlet_anything (x->control_outlet, gensym ("library"), 1, at); + + for (lIndex = 0; + (psDescriptor = fDescriptorFunction(lIndex)) != NULL; + lIndex++) { + at[0].a_w.w_symbol = gensym ((char*)psDescriptor->Name); + outlet_anything (x->control_outlet, gensym ("name"), 1, at); + at[0].a_w.w_symbol = gensym ((char*)psDescriptor->Label); + outlet_anything (x->control_outlet, gensym ("label"), 1, at); + at[0].a_type = A_FLOAT; + at[0].a_w.w_float = psDescriptor->UniqueID; + outlet_anything (x->control_outlet, gensym ("id"), 1, at); + at[0].a_type = A_SYMBOL; + at[0].a_w.w_symbol = gensym ((char*)psDescriptor->Maker); + outlet_anything (x->control_outlet, gensym ("maker"), 1, at); + } + + dlclose(pvPluginHandle); +} + +static void plugin_tilde_bypass (Pd_Plugin_Tilde* x) { +} + +static void plugin_tilde_plug (Pd_Plugin_Tilde* x) { +} + + +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, +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 */ @@ -436,130 +400,708 @@ plugin_tilde_get_parm_number (Pd_Plugin_Tilde* x, } } -static const char* -plugin_tilde_search_plugin (Pd_Plugin_Tilde* x, +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, +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);", + + post("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 + + post("plugin~: plugin active"); + + + + // plugin_tilde_info (x); + return ret; } -static void -plugin_tilde_close_plugin (Pd_Plugin_Tilde* x) +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 + post("plugin~: close_plugin (x)"); + + + 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 + + + + post("plugin~: destructed plugin successfully"); + } -static void -plugin_tilde_apply_plugin (Pd_Plugin_Tilde* x) +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, +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, +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, +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) + +const char* plugin_tilde_ladspa_search_plugin (Pd_Plugin_Tilde* x, + const char* name) { -#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 + char* lib_name = NULL; + void* user_data[2]; + + user_data[0] = (void*)(&lib_name); + user_data[1] = (void*)name; + + lib_name = NULL; + LADSPAPluginSearch (plugin_tilde_ladspa_search_plugin_callback, + (void*)user_data); + + /* 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) + { + // post("plugin~: searching library \"%s\"...", full_filename); + + for (plug_index = 0; + (descriptor = descriptor_function (plug_index)) != NULL; + plug_index++) + { + // post("plugin~: label \"%s\"", descriptor->Label); + + if (strcasecmp (name, descriptor->Label) == 0) + { + /* found a matching plugin */ + *out_lib_name = strdup (full_filename); + + post("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) +{ + unsigned port_index; + + /* 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. */ + x->plugin_library = loadLADSPAPluginLibrary (lib_name); + if (x->plugin_library == NULL) + { + /* error */ + post("plugin~: Unable to load LADSPA plugin library \"%s\"", + lib_name); + return 1; + } + x->plugin.ladspa.type = findLADSPAPluginDescriptor (x->plugin_library, + lib_name, + name); + if (x->plugin.ladspa.type == NULL) + { + post("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 */ + post("plugin~: Unable to instantiate LADSPA plugin \"%s\"", + x->plugin.ladspa.type->Name); + return 1; + } + + post("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)) { + post("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) */ + assert (x != NULL); + + 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) */ + assert (x != NULL); + assert (x->plugin.ladspa.type != NULL); + assert (x->plugin.ladspa.instance != NULL); + + if (x->plugin.ladspa.type->activate != NULL + && x->plugin.ladspa.type->deactivate == NULL) + { + post("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; + + /* Allocate out-of-place memory if needed */ + if (plugin_tilde_ladspa_alloc_outofplace_memory (x, num_samples)) { + post("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) { + post("plugin~: no control port name specified"); + return; + } + + /* compare control name to LADSPA control input ports' names + case-insensitively */ + found_port = 0; + ctrl_input_index = 0; + for (port_index = 0; port_index < x->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) + { + post("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 */ + int bounded_from_below = 0; + int bounded_from_above = 0; + int bounded = 0; + float lower_bound = 0; + float upper_bound = 0; + + /* precondition(s) */ + assert (x != NULL); + /* assert (ctrl_input_index >= 0); causes a warning */ + /* assert (ctrl_input_index < x->num_control_inputs); */ + if (ctrl_input_index >= x->num_control_inputs) { + post("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) { + post("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; + + // post("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++; + } + } + } + + post("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; + } } -/* EOF */ -- cgit v1.2.1