On Tue, 2009-07-28 at 14:12 -0500, Gabriel M. Beddingfield wrote:
> Hi Damon,
> 
> On Tue, 28 Jul 2009, Damon Chaplin wrote:
> > A quick update - fixes have been found for blop, caps & cmt, and the
> > ladspa Sine plugin problem is fixed in the latest version.
> 
> Great job!  Did you update your test program?  Could you please post it to 
> the list?

I've only reordered it so it connects the ports before calling activate,
to avoid the crashes with the amb and swh plugins.

I've attached the new version.

Damon

/*
 * Test app to load & run all LADSPA plugins for one cycle.
 *
 * Compile with:
 * gcc `pkg-config --cflags --libs gmodule-2.0` -lm -o test-ladspa test-ladspa.c
 *
 * Simply run it with './test-ladspa' to test all plugins.
 * Run it with './test-ladspa -p PACKAGE' to test a particular package.
 * (Run ./test-ladspa --help to see the list of known packages.)
 *
 * Run it with 'valgrind --tool=memcheck ./test-ladspa' to spot memory errors.
 */
#include <stdlib.h>
#include <math.h>
#include <glib.h>
#include <gmodule.h>
#include <ladspa.h>

/* The default places to look for LADSPA plugins, if LADSPA_PATH isn't set. */
#define DEFAULT_LADSPA_PATH	"/usr/lib/ladspa:/usr/local/lib/ladspa"

/* The sample rate to pass to the plugins. We don't output audio so it's not
   too important. */
#define SAMPLE_RATE		48000

/* The number of samples to use for the run. Again, not too important. */
#define NUM_SAMPLES		256

static char *package = NULL;
static char **file_list = NULL;

/* These are the lists of files containing the plugins in the various
   packages. I got most of these using 'rpm -ql <PACKAGE>'. There may be
   more packages around that I haven't got installed at present. */
static char *amb_file_list[] = { "ambisonic1.so", "ambisonic2.so", NULL };
static char *blop_file_list[] = { 
  "adsr_1653.so", "adsr_1680.so", "amp_1654.so", "branch_1673.so",
  "dahdsr_2021.so", "difference_2030.so", "fmod_1656.so",
  "interpolator_1660.so", "lp4pole_1671.so", "parabola_1649_data.so",
  "product_1668.so", "pulse_1645.so", "quantiser100_2029.so",
  "quantiser20_2027.so", "quantiser50_2028.so", "random_1661.so",
  "ratio_2034.so", "sawtooth_1641_data.so", "sawtooth_1641.so",
  "sequencer16_1677.so", "sequencer32_1676.so", "sequencer64_1675.so",
  "square_1643_data.so", "square_1643.so", "sum_1665.so",
  "sync_pulse_2023.so", "sync_square_1678.so", "tracker_2025.so",
  "triangle_1649.so",
  NULL
};
static char *calf_file_list[] = { "calf.so", NULL };
static char *caps_file_list[] = { "caps.so", NULL };
static char *cmt_file_list[] = { "cmt.so", NULL };
static char *fil_file_list[] = { "filters.so", NULL };
static char *ladspa_file_list[] = { "amp.so", "delay.so", "filter.so",
				    "noise.so", "sine.so", NULL };
static char *mcp_file_list[] = { "cs_chorus.so", "cs_phaser.so",
				 "mvchpf24.so", "mvclpf24.so", NULL };
static char *rev_file_list[] = { "g2reverb.so", NULL };
static char *swh_file_list[] = {
  "alias_1407.so", "allpass_1895.so", "am_pitchshift_1433.so", "amp_1181.so", 
  "analogue_osc_1416.so", "bandpass_a_iir_1893.so", "bandpass_iir_1892.so", 
  "bode_shifter_1431.so", "bode_shifter_cv_1432.so", "butterworth_1902.so", 
  "chebstortion_1430.so", "comb_1190.so", "comb_1887.so",
  "comb_splitter_1411.so", "const_1909.so", "crossover_dist_1404.so", 
  "dc_remove_1207.so", "decay_1886.so", "decimator_1202.so", "declip_1195.so", 
  "delay_1898.so", "delayorama_1402.so", "diode_1185.so", "divider_1186.so", 
  "dj_eq_1901.so", "dj_flanger_1438.so", "dyson_compress_1403.so", 
  "fad_delay_1192.so", "fast_lookahead_limiter_1913.so", "flanger_1191.so", 
  "fm_osc_1415.so", "foldover_1213.so", "foverdrive_1196.so",
  "freq_tracker_1418.so", "gate_1410.so", "giant_flange_1437.so",
  "gong_1424.so", "gong_beater_1439.so", "gsm_1215.so", "gverb_1216.so", 
  "hard_limiter_1413.so", "harmonic_gen_1220.so", "hermes_filter_1200.so", 
  "highpass_iir_1890.so", "hilbert_1440.so", "imp_1199.so", "impulse_1885.so", 
  "inv_1429.so", "karaoke_1409.so", "latency_1914.so", "lcr_delay_1436.so", 
  "lowpass_iir_1891.so", "ls_filter_1908.so", "matrix_ms_st_1421.so", 
  "matrix_spatialiser_1422.so", "matrix_st_ms_1420.so", "mbeq_1197.so", 
  "mod_delay_1419.so", "multivoice_chorus_1201.so", "notch_iir_1894.so", 
  "phasers_1217.so", "pitch_scale_1193.so", "pitch_scale_1194.so", 
  "plate_1423.so", "pointer_cast_1910.so", "rate_shifter_1417.so", 
  "retro_flange_1208.so", "revdelay_1605.so", "ringmod_1188.so", 
  "satan_maximiser_1408.so", "sc1_1425.so", "sc2_1426.so", "sc3_1427.so", 
  "sc4_1882.so", "sc4m_1916.so", "se4_1883.so", "shaper_1187.so", 
  "sifter_1210.so", "sin_cos_1881.so", "single_para_1203.so", 
  "sinus_wavewrapper_1198.so", "smooth_decimate_1414.so", "split_1406.so", 
  "step_muxer_1212.so", "surround_encoder_1401.so", "svf_1214.so", 
  "tape_delay_1211.so", "transient_1206.so", "triple_para_1204.so", 
  "valve_1209.so", "valve_rect_1405.so", "vynil_1905.so",
  "wave_terrain_1412.so", "xfade_1915.so", "zm1_1428.so", 
  NULL
};
static char *tap_file_list[] = {
  "tap_autopan.so", "tap_chorusflanger.so", "tap_deesser.so", "tap_doubler.so", 
  "tap_dynamics_m.so", "tap_dynamics_st.so", "tap_echo.so", "tap_eq.so", 
  "tap_eqbw.so", "tap_limiter.so", "tap_pinknoise.so", "tap_pitch.so", 
  "tap_reflector.so", "tap_reverb.so", "tap_rotspeak.so", "tap_sigmoid.so", 
  "tap_tremolo.so", "tap_tubewarmth.so", "tap_vibrato.so",
  NULL
};
static char *vco_file_list[] = { "blvco.so", "vco_sawpulse.so", NULL };


static gpointer
create_buffer_for_port (LADSPA_Descriptor *descriptor,
			gint               port_num)
{
  LADSPA_PortDescriptor port_descriptor;
  const LADSPA_PortRangeHint *port_range_hint;
  LADSPA_PortRangeHintDescriptor hint_descriptor;
  gfloat *buffer, minimum, maximum, value = 0.0F;
  gint i;

  port_descriptor = descriptor->PortDescriptors[port_num];
  port_range_hint = &descriptor->PortRangeHints[port_num];
  hint_descriptor = port_range_hint->HintDescriptor;

  if (port_descriptor & LADSPA_PORT_AUDIO)
    {
      buffer = g_new (float, NUM_SAMPLES);
      for (i = 0; i < NUM_SAMPLES; i++)
	buffer[i] = 0.0F;
    }
  else
    {
      buffer = g_new (float, 1);

      minimum = port_range_hint->LowerBound;
      if (LADSPA_IS_HINT_SAMPLE_RATE (hint_descriptor))
	minimum *= SAMPLE_RATE;

      maximum = port_range_hint->UpperBound;
      if (LADSPA_IS_HINT_SAMPLE_RATE (hint_descriptor))
	maximum *= SAMPLE_RATE;

      /* Calculate the default value. See ladspa.h for the formulas.
	 We could try testing plugins with all kinds of input data later. */
      if (LADSPA_IS_HINT_HAS_DEFAULT (hint_descriptor))
	{
	  if (LADSPA_IS_HINT_DEFAULT_MINIMUM (hint_descriptor))
	    value = minimum;
	  else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM (hint_descriptor))
	    value = maximum;
	  else if (LADSPA_IS_HINT_DEFAULT_0 (hint_descriptor))
	    value = 0;
	  else if (LADSPA_IS_HINT_DEFAULT_1 (hint_descriptor))
	    value = 1;
	  else if (LADSPA_IS_HINT_DEFAULT_100 (hint_descriptor))
	    value = 100;
	  else if (LADSPA_IS_HINT_DEFAULT_440 (hint_descriptor))
	    value = 440;

	  else if (LADSPA_IS_HINT_DEFAULT_LOW (hint_descriptor))
	    {
	      if (LADSPA_IS_HINT_LOGARITHMIC (hint_descriptor))
		value = exp (log (minimum) * 0.75 + log (maximum) * 0.25);
	      else
		value = (minimum * 0.75 + maximum * 0.25);
	    }
	  else if (LADSPA_IS_HINT_DEFAULT_MIDDLE (hint_descriptor))
	    {
	      if (LADSPA_IS_HINT_LOGARITHMIC (hint_descriptor))
		value = exp (log (minimum) * 0.5 + log (maximum) * 0.5);
	      else
		value = (minimum * 0.5 + maximum * 0.5);
	    }
	  else if (LADSPA_IS_HINT_DEFAULT_HIGH (hint_descriptor))
	    {
	      if (LADSPA_IS_HINT_LOGARITHMIC (hint_descriptor))
		value = exp (log (minimum) * 0.25 + log (maximum) * 0.75);
	      else
		value = (minimum * 0.25 + maximum * 0.75);
	    }
	}

      *buffer = value;
    }

  return buffer;
}


/* Returns TRUE if a plugin should be skipped. */
static gboolean
skip_file (const gchar       *filename)
{
  gint i;

  if (file_list)
    {
      for (i = 0; file_list[i]; i++)
	{
	  if (!strcmp (file_list[i], filename))
	    return FALSE;
	}
      return TRUE;
    }

  return FALSE;
}


static void
test_ladspa_plugin (const gchar       *filename,
		    LADSPA_Descriptor *descriptor)
{
  LADSPA_Handle ladspa_instance;
  gint num_ports, port_num;
  GList *buffers = NULL, *elem;
  gpointer buffer;

#if 1
  g_print ("###############################################################################\n");
#endif

#if 1
  g_print ("Testing  %i: %s (%s)\n", descriptor->UniqueID,
	   descriptor->Name ? descriptor->Name : "Unnamed", filename);
#endif

  /* Instantiate the plugin. */
  ladspa_instance = descriptor->instantiate (descriptor, SAMPLE_RATE);

  /* Connect up the ports. */
  num_ports = descriptor->PortCount;
  for (port_num = 0; port_num < num_ports; port_num++)
    {
      buffer = create_buffer_for_port (descriptor, port_num);
#if 0
      g_print ("Connecting port: %i to: %p\n", port_num, buffer);
#endif
      descriptor->connect_port (ladspa_instance, port_num, buffer);
      buffers = g_list_prepend (buffers, buffer);
    }

  /* Activate it, if necessary. */
  if (descriptor->activate)
    descriptor->activate (ladspa_instance);

  /* Do one run of the plugin. */
  descriptor->run (ladspa_instance, NUM_SAMPLES);

  /* Free the buffers. */
  for (elem = buffers; elem; elem = elem->next)
    g_free (elem->data);
  g_list_free (buffers);

  /* Deactivate it, if necessary. */
  if (descriptor->deactivate)
    descriptor->deactivate (ladspa_instance);

  /* Free any resources. */
  descriptor->cleanup (ladspa_instance);
}


static void
scan_ladspa_plugin (gchar             *pathname,
		    const gchar       *filename)
{
  GModule *module;
  LADSPA_Descriptor_Function ladspa_func;
  LADSPA_Descriptor *descriptor;
  gpointer symbol;
  gint i;

  module = g_module_open (pathname, G_MODULE_BIND_LAZY);
  if (!module)
    return;

  /* Lookup the special "ladspa_descriptor" symbol. */
  if (g_module_symbol (module, "ladspa_descriptor", &symbol))
    {
      ladspa_func = (LADSPA_Descriptor_Function) symbol;

      /* Get the LADSPA descriptor for each module in the library. */
      for (i = 0; ; i++)
	{
	  descriptor = (LADSPA_Descriptor*) ladspa_func (i);
	  if (!descriptor)
	    break;
	  test_ladspa_plugin (filename, descriptor);
	}
    }

  g_module_close (module);
}


static void
scan_ladspa_directory (gchar   *directory)
{
  GDir *dir;
  const char *filename;
  char *pathname;

  dir = g_dir_open (directory, 0, NULL);
  if (!dir)
    return;

  /* Step through the files in the LADSPA plugin directory. */
  while ((filename = g_dir_read_name (dir)))
    {
      if (skip_file (filename))
	{
#if 0
	  g_print ("Skipping file: %s\n", filename);
#endif
	  continue;
	}

      pathname = g_strdup_printf ("%s%c%s", directory, G_DIR_SEPARATOR,
				  filename);
      scan_ladspa_plugin (pathname, filename);
      g_free (pathname);
    }

  g_dir_close (dir);
}


static void
test_ladspa_plugins ()
{
  const gchar *path;
  gchar **directories;
  gint directory_num;

  /* Use the $LADSPA_PATH environment variable, or the default path if that
     hasn't been set. */
  path = g_getenv ("LADSPA_PATH");
  if (!path)
    path = DEFAULT_LADSPA_PATH;

  /* Split the path into an array of directories. */
  directories = g_strsplit (path, ":", -1);

  /* Scan each directory in turn. */
  for (directory_num = 0; directories[directory_num]; directory_num++)
    scan_ladspa_directory (directories[directory_num]);

  /* Free the array. */
  g_strfreev (directories);
}


/* Command-line options. */
static GOptionEntry entries[] = 
{
  { "package", 'p', 0, G_OPTION_ARG_STRING, &package, "Package to test (amb, blop, calf, caps, cmt, fil, ladspa, mcp, rev, swh, tap or vco)", "PACKAGE" },
  { NULL }
};

int
main (int argc, char *argv[])
{
  GOptionContext *context;
  GError *error = NULL;

  context = g_option_context_new ("- test LADSPA plugins");
  g_option_context_add_main_entries (context, entries, NULL);
  if (!g_option_context_parse (context, &argc, &argv, &error))
    {
      g_print ("option parsing failed: %s\n", error->message);
      exit (1);
    }

  /* If a package is specified, set the appropriate file list to scan. */
  if (package)
    {
      if (!strcmp (package, "amb"))
	file_list = amb_file_list;
      else if (!strcmp (package, "blop"))
	file_list = blop_file_list;
      else if (!strcmp (package, "calf"))
	file_list = calf_file_list;
      else if (!strcmp (package, "caps"))
	file_list = caps_file_list;
      else if (!strcmp (package, "cmt"))
	file_list = cmt_file_list;
      else if (!strcmp (package, "fil"))
	file_list = fil_file_list;
      else if (!strcmp (package, "ladspa"))
	file_list = ladspa_file_list;
      else if (!strcmp (package, "mcp"))
	file_list = mcp_file_list;
      else if (!strcmp (package, "rev"))
	file_list = rev_file_list;
      else if (!strcmp (package, "swh"))
	file_list = swh_file_list;
      else if (!strcmp (package, "tap"))
	file_list = tap_file_list;
      else if (!strcmp (package, "vco"))
	file_list = vco_file_list;
    }

  test_ladspa_plugins ();

  return 0;
}
_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@lists.linuxaudio.org
http://lists.linuxaudio.org/mailman/listinfo/linux-audio-dev

Reply via email to