[linux-audio-dev] A Plugin API

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: [linux-audio-dev] A Plugin API
From: Richard W.E. Furse (richard_AT_muse.demon.co.uk)
Date: ma helmi  28 2000 - 10:04:27 EST


Got annoyed about the whole plugin thing and wrote a prototype API this
morning. As suggested in an earlier message, I believe this plugin API
should be a subset rather than a superset of the logical functionality of
systems in use at the moment. This is partly an attempt to provoke
discussion but starting from something I'm pretty sure will work in its own
right.

It's a strongly float-based approach using dynamic libraries which I think
will be highly compatible with most of the C/C++ code/ideas out there
(Quasimodo, Csound, MuCoS, aRts, MN etc) although all programs would of
course need to write a loader and wrapper. And yes, it's really really
simplistic and doesn't cover events or MIDI. The reason for this is that I
don't think we've agreed on a 'right way' to do this or even that a 'right
way' might exist and in the meantime we're stopping inexperienced audio
programmers getting their hands dirty writing conventional plugins.

I include the API below (in header file form with internal documentation).
Apologies for the largish posting (though I think we can cope in this day
and age...).

-- Richard

/* ladspa.h - Copyright 2000 Richard W.E. Furse */

#ifndef LADSPA_INCLUDED
#define LADSPA_INCLUDED

/***********************************************************************
******/

/* Overview:
   --------- */
/* The concept of the 'unit generator' was developed by Max Matthews
   at Bell Labs in 1960 as part of the Music III software synthesis
   package. See "The Technology of Computer Music", M. Matthews,
   Cambridge Massachusetts, MIT Press 1969.

   There is a large number of synthesis packages in use or development
   on the Linux platform at this time. This API ('The Linux Audio
   Developer's Simple Plugin API') attempts to give programmers the
   ability to write simple unit generators in C and link them
   dynamically ('plug') into a range of these packages ('hosts'). Unit
   generators will be organised into dynamically loaded libraries
   ('plugins'). It should be possible for any host and any plugin to
   communicate completely through this interface.

   This API is deliberately short and simple. To achieve compatibility
   with a range of promising Linux sound synthesis packages it
   attempts to find the 'lowest common denominator' in their logical
   behaviour. Having said this, certain limiting decisions are
   implicit, notably the use of floats for all data transfer and
   absence of a parameterised 'initialisation' phase.

   Plugins are expected to use the 'control rate' thinking implicit in
   the Music N languages (including Csound). Unit generators have
   'ports' that are inputs or outputs for audio or control data and
   the plugin is 'run' for a 'frame' corresponding to a short time
   interval measured in samples. Audio data is communicated using
   arrays of floats, allowing a frame of audio to be processed by the
   unit generator in a single block. Control data is communicated
   using simple float values. Control data may only change once per
   frame and so is not suitable for the transfer of many types of
   data, however this provides a significant performance benefit. The
   unit generator may assume that all its inputs and outputs are bound
   before it is asked to run a frame.

   This API contains very limited error-handling at this time. */

/***********************************************************************
******/

/* Unit Generator Properties:
   -------------------------- */
/* Unit generators may have special properties. These are ORed
   together. */

typedef int LADSPA_UGProperties;

/* Indicates that the unit generator has a real-time dependency and so
   its output not be cached of subject to serious latency. */
#define LADSPA_UG_PROPERTY_REALTIME 1

#define LADSPA_IS_UG_REALTIME(x) ((x) && LADSPA_UG_PROPERTY_REALTIME)

/***********************************************************************
******/

/* Unit Generator Ports:
   --------------------- */
/* Unit generators have 'ports' that are inputs or outputs of audio or
   data. Ports can communicate arrays of floats (for audio-rate
   inputs/outputs) or single floats (for control-rate
   input/outputs). This information is encapsulated in the
   LADSPA_UGPortDescriptor type which is assembled by ORing properties
   together. By default a port is an audio-rate output. */

typedef int LADSPA_UGPortDescriptor;

/* Indicates that the port is an input rather than an output. */
#define LADSPA_UG_PORT_INPUT 1
/* Indicates that the port is a control-rate (single float) port
   rather than an audio-rate (float array) port. */
#define LADSPA_UG_PORT_CONTROL 2

#define LADSPA_IS_UG_PORT_INPUT(x) ((x) && LADSPA_UG_PORT_INPUT)
#define LADSPA_IS_UG_PORT_OUTPUT(x) (!((x) && LADSPA_UG_PORT_INPUT))
#define LADSPA_IS_UG_PORT_CONTROL(x) ((x) && LADSPA_UG_PORT_CONTROL)
#define LADSPA_IS_UG_PORT_AUDIO(x) (!((x) && LADSPA_UG_PORT_CONTROL))

/***********************************************************************
******/

/* Unit Generator Handles:
   ----------------------- */

/* This unit generator handle indicates access to a particular
   instance of the unit generator concerned. It is valid to compare
   this to NULL. */
typedef void * LADSPA_UGHandle;

/***********************************************************************
******/

/* Descriptor for a Type of Unit Generator:
   ---------------------------------------- */
/* This structure is used to describe a type of unit generator. It
   provides a number of functions to examine the type, instantiate it,
   link it to buffers and workspaces and to run it. */

struct LADSPA_UGDescriptor {

  /* This indicates a number of properties of the unit generator. */
  LADSPA_UGProperties m_iProperties;

  /* This member points to the name of the unit generator
     (e.g. "Sine Oscillator"). */
  const char * m_pcUnitGeneratorName;

  /* This indicates the number of ports (input AND output) present on
     the unit generator. */
  int m_iPortCount;

  /* This member indicates an array of port descriptor. Valid indexes
     numbers vary from 0 to m_iPortCount-1. */
  LADSPA_UGPortDescriptor * m_piPortDescriptors;

  /* This member is a function pointer that takes a port number as an
     input and returns a short null-terminated string (e.g. "frequency
     (Hz)") describing the port. The string returned should be
     finished with (but not freed) before calling this method again in
     case the memory space is reused by the plugin. */
  const char * (*m_pfGetPortName)(const int iPort);

  /* This member is a function pointer that instantiates a unit
     generator. A handle is returned, indicating the new function. The
     instantiation function accepts a (float) sample rate as a
     parameter. Returns NULL if instantiation fails. */
  LADSPA_UGHandle (*m_pfInstantiate)(const float fSampleRate);

  /* This member is a function pointer that connects a port on an
     instantiated unit generator to a memory location at which a frame
     of data for the port will be read/written. The data location is
     expected to be a block of floats for audio rate ports or a single
     float for control rate ports. Memory issues will be managed by
     the host. The unit generator should read/write the data at these
     locations every frame and the data present at the time of this
     connection call should not be considered meaningful. Connection
     functions may be called more than once for a single instance of a
     plugin to allow the host to change the buffers that the unit
     generator is reading or writing. They must be called at least
     once for each port. When working with blocks of floats, the unit
     generator should pay careful attention to the frame size passed
     to the run function as the block allocated may only just be large
     enough to contain the block of samples. */
  void (*m_pfConnectPort)(LADSPA_UGHandle psInstance,
                          const int iPort,
                          float * pfDataLocation);

  /* This method is a function pointer that runs an instance of a unit
     generator for a frame. Two parameters are required: the first is
     a handle to the particular instance to be run and the second
     indicates the frame size (in samples) for which the unit
     generator may run. */
  void (*m_pfRun)(LADSPA_UGHandle psInstance,
                  const int iFrameSize);

  /* Once an instance of a unit generator has been finished with it
     can be deleted using the following function. The handle passed
     ceases to be valid after this call. */
  void (*m_pfCleanup)(LADSPA_UGHandle psInstance);

  /* Reserved area for extensions. Must be initialised to zero. */
  char m_acReserved[1000];

};

/***********************************************************************
******/

/* Loading A Plugin:
   ----------------- */
/* The exact mechanism by which a plugin is loaded is host-dependent,
   however what the host will need to know is:
   (1) The library containing the plugin. It should be possible to
   load this library using dlopen() and family.
   (2) The names of all LADSPA_UGDescriptorAccesor functions
   present.
   (3) Any additional information required by the host, for instance
   an 'opcode' name and spec. */

/***********************************************************************
******/

/* Writing a Plugin:
   ----------------- */
/* A plugin programmer should write a LADSPA_UGDescriptorAccessor
   function for each unit generator present. Functions will be
   required to fill in all entries in the LADSPA_UGDescriptor
   structure passed so these should be written also. When the plugin
   code is complete it should be stored in a dynamic library for use
   with dlopen(). With GNU CC this can be achieved using -fPIC.

   It is recommended that the following naming convention is used for
   accessor functions: "UG_<coder/company>_<UGname>_<version>". For
   example, my second oscillator class might be
   UG_RichardFurse_Oscillator_2. */

typedef void
LADSPA_UGDescriptorAccessor(struct LADSPA_UGDescriptor * psDescriptor);

/***********************************************************************
******/

#endif

/* EOF */


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : pe maalis 10 2000 - 07:23:27 EST