aboutsummaryrefslogtreecommitdiff
path: root/plugin~.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugin~.c')
-rw-r--r--plugin~.c1016
1 files changed, 779 insertions, 237 deletions
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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 */