[linux-audio-dev] XAP status : incomplete draft

Tim Hockin thockin at hockin.org
Fri Dec 13 04:01:01 UTC 2002


Here is a draft incorportaing a lot of what we've talked about.   It is
missing a lot, and some is probably wrong/inconsistent.  We've been talking
a LOT. :)

Notes:
* All VVID stuff is missing
* All pitch stuff is missing
* Currently uses a monolithic ChannelType for channels until actual answer
is decided (though I rather like the simple monolith)
* several things are not commented or are insufficiently commented
* Several FIXMEs
* several things still on the TODO list

Have at it...

Tim




/* $Id: $ */
/*
 * Tim Hockin <thockin at hockin.org>
 * Copyright (c) 2001-2002 Tim Hockin
 *
 * This header file defines the API for the XAP - the XAP Audio Plugin
 * interface.
 *
 * Goals:
 * The main goal of this API is to provide an API that is full-featured
 * enough to be the primary plugin system for audio-development
 * applications, while remaining as simple, lightweight, and self-contained
 * as possible.
 *
 * Credits:
 * This API originated from LADSPA by Richard W.E. Furse et al. and evolved
 * through dialog between Tim Hockin,  David Olofson, Steve Harris, and
 * others via the linux-audio-devel mailing list
 * (linux-audio-dev at music.columbia.edu).
 *
 * Overview:
 * Plugins are loaded from shared object files.  A shared object file holds
 * one or more plugin descriptors, accessed by index.  Each descriptor holds
 * all the information about a single plugin - it's identification,
 * capabilities, controls, and access methods.
 */
#ifndef XAP_H__
#define XAP_H__

#ifdef __cplusplus
extern "C" {
#endif


#include <stdint.h>

/*
 * The current version of the API: read as "major.minor.micro".
 */
#define XAP_VERSION			0x000010
#define XAP_MKVERSION(maj, min, mic)	(((mar)<<16) | ((min)<<8) | (mic))

/*
 * A single audio sample: this datatype is used for passing audio data
 * between plugins and hosts.  Data is normalized between -1.0 and 1.0
 * as the 0dB value, with 0.0 being silence.
 */
typedef float XAP_sample;

/* the fundamental XAP types */
typedef struct XAP_descriptor	XAP_descriptor;
typedef struct XAP_channel	XAP_channel;
typedef struct XAP_port		XAP_port;
typedef struct XAP_host		XAP_host;
typedef struct XAP_control	XAP_control;
typedef enum   XAP_ctrl_type	XAP_ctrl_type;
typedef struct XAP_ctrl_int	XAP_ctrl_int;
typedef struct XAP_ctrl_float	XAP_ctrl_float;
typedef struct XAP_ctrl_enum	XAP_ctrl_enum;
typedef struct XAP_ctrl_string	XAP_ctrl_string;
typedef struct XAP_raw_data	XAP_raw_data;
typedef struct XAP_ctrl_raw	XAP_ctrl_raw;
typedef struct XAP_event_port	XAP_event_port;
typedef struct XAP_event_queue	XAP_event_queue;
typedef struct XAP_event	XAP_event;
typedef enum   XAP_event_id	XAP_event_id;
typedef uint32_t		XAP_timestamp;

/*
 * A plugin descriptor: this structure describes what an plugin can do.
 * Every plugin has exactly one descriptor, which the host must treat as
 * READ-ONLY.
 */
struct XAP_descriptor {
	/*
	 * The ID is a bitmask of the vendor code (high-order 16 bits) and
	 * the product code (low-order 16 bits).  The vendor code is
	 * assigned by a central authority, and the product code is vendor
	 * assigned.  For plugins that are in development, or for vendors
	 * who have not yet received a vendor code, the vendor code field
	 * should be 0.  Vendors/authors MUST NOT distribute plugins with
	 * the vendor code set to 0.
	 */
	uint32_t xap_id;

	/*
	 * The api is the XAP_VERSION that this plugin understands.  Hosts
	 * should use this to allow older plugins to load without
	 * overstepping the plugin's capabilities.
	 */
	uint32_t xap_api;

	/*
	 * The serial is simply a number by which the host can compare two
	 * versions of a plugin and pick the later version.  The actual
	 * value has no meaning to the host.  The only requirement for this
	 * field is that the value never gets smaller in new releases.
	 */
	uint32_t xap_serial;

	/*
	 * The label is a file-unique, non-whitespace, string identifier for
	 * the plugin.  Hosts can use the filename and label to identify a
	 * plugin uniquely.  The label is all upper case, by convention.
	 */
	const char *xap_label;

	/*
	 * The name is an arbitrary string, which hosts can display to
	 * users.
	 */
	const char *xap_name;

	/*
	 * These are display-friendly fields, which hosts can display to
	 * users.
	 */
	const char *xap_version;
	const char *xap_author;
	const char *xap_copyright;
	const char *xap_license;
	const char *xap_url;
	const char *xap_notes;

	/* master controls and I/O */
	int xap_n_controls;
	XAP_control **xap_controls;
	int xap_n_ports;
	XAP_port **ch_ports;

	/* channel descriptors */
	int xap_n_channel_types;
	XAP_channel *xap_channel_types;
	//FIXME: how to get the num/info currently instantiated channels?

	//FIXME: enumerate negative return values == better error reporting

	/*
	 * create: instantiate the plugin
	 *
	 * This method is used to create an instance of the plugin described
	 * by the descriptor.  Memory will be allocated and state will be
	 * initialized in this method.
	 *
	 * Arguments:
	 *  descriptor: a pointer to the plugin descriptor.
	 *  host: a pointer to the host callback structure.
	 *  rate: the host sample rate (see xap_set_rate below).
	 *
	 * Returns:
	 *  This method returns a pointer to a plugin-private handle.  If
	 *  initialization fails for any reason, this method must return
	 *  NULL.
	 */
	void *(*xap_create)(XAP_descriptor *descriptor, XAP_host *host,
	    int rate);
	//FIXME: how to enumerate errors from this?
	//FIXME: return something better than void *?

	/*
	 * destroy: destroy an instance
	 *
	 * This method is used to destroy and clean up after an instance of
	 * the plugin.  All allocated resources must be released.  After
	 * this method is invoked, the plugin handle is no longer valid.
	 * This function can not fail.
	 *
	 * Arguments:
	 *  plugin: a pointer to the plugin instance.
	 *
	 * Returns:
	 *  This method does not return a value.
	 */
	void (*xap_destroy)(void *plugin);

	/*
	 * set_rate: set the sample rate
	 *
	 * This method may only be called on plugins that are not active.
	 * There is no required set of supported sample rates, but plugins
	 * should support the common sample rates (44100, 48000, 96000) to
	 * be generally useful.  Hosts should always check that all plugins
	 * support the desired sample rate.
	 *
	 * Arguments:
	 *  plugin: a pointer to the plugin instance.
	 *  rate: the desired sample rate.
	 *
	 * Returns:
	 *  This method returns 0 on success and -1 if the sample rate is
	 *  not supported or some error occurred.
	 */
	int (*xap_set_rate)(void *plugin, int rate);

	/*
	 * activate: prepare a plugin for running
	 *
	 * This method is used to prepare a plugin before being run.  This
	 * is an optional method, and if provided, will be called once
	 * before the first call to the run() method.  This method will not
	 * be called again by the host until the deactivate() method has
	 * been called.  Plugins may interpret or ignore the quality
	 * parameter as they see fit.
	 *
	 * Arguments:
	 *  plugin: a pointer to the plugin instance.
	 *  quality: an integer between 1 (lowest) and 10 (highest).
	 *
	 * Returns:
	 *  This method returns 0 on success and -1 on error.
	 */
	int (*xap_activate)(void *plugin, int quality);

	/*
	 * deactivate: stop a plugin after running
	 *
	 * This method is used to shut down a plugin when the host is done
	 * running it.  This method, if provided, will be called at least
	 * once some time after a call to the activate() method and before
	 * the destroy() method.  Hosts may use the deactivate()/activate()
	 * pair as a way to reset the plugin's state.
	 *
	 * Arguments:
	 *  plugin: a pointer to the plugin instance.
	 *
	 * Returns:
	 *  This method returns 0 on success and -1 on error.
	 */
	int (*xap_deactivate)(void *plugin);

	/*
	 * connect_port: connect buffers for data
	 *
	 * Hosts must connect ports to buffers in order for a plugin to
	 * operate.  The Plugins are expected to handle the case of the
	 * input buffer being the same as the output buffer (in-place
	 * operation) transparently to the host.  The host must connect
	 * every port except if the host and plugin agree to disable a
	 * port (see xap_disable_port), in which case it does not need to
	 * be connected.
	 *
	 * Arguments:
	 *  plugin: a pointer to the plugin instance.
	 *  channel: the channel number or CHANNEL_MASTER
	 *  port: the port number (zero-based value).
	 *  buffer: the buffer in which to read/write audio data.
	 *
	 * Returns:
	 *  This method returns 0 on success and -1 on error.
	 */
	int (*xap_connect_port)(void *plugin, int channel, int port,
	    XAP_sample *buffer);

	/*
	 * disable_port: request that a port not be used.
	 *
	 * If a host does not want the plugin to operate on a given port, it
	 * may ask the plugin to disable the port.  This method is optional,
	 * but highly recommended if the plugin can save cycles.  If the
	 * plugin provides this method and this method succeeds, the port
	 * does not need to be connected.  If this method is not provided,
	 * or this method fails, the host must follow normal port connection
	 * rules.  If a host disables a port and later connects it, the port
	 * is enabled.  If the host wishes to disable it again, it must call
	 * this method again.
	 *
	 * Arguments:
	 *  plugin: a pointer to the plugin instance.
	 *  channel: the channel number or XAP_CHANNEL_MASTER
	 *  port: the port number (zero-based value).
	 *
	 * Returns:
	 *  These methods return 0 on success and -1 on error.
	 */
	int (*xap_disable_port)(void *plugin, int channel, int port);

	/*
	 * get an event port, XAP_CHANNEL_MASTER for master 
	 */
	XAP_event_port *(*xap_event_port)(void *plugin, int channel, int index);

	/*
	 * run: use the plugin
	 *
	 * This method invokes the plugin for a number of audio samples,
	 * which are provided on connected ports.
	 *
	 * Arguments:
	 *  plugin: a pointer to the plugin instance.
	 *  nsamples: the number of samples available on port buffers.
	 *
	 * Returns:
	 *  This method returns 0 on success and -1 on error.
	 */
	int (*xap_run)(void *plugin, int nsamples, XAP_timestamp now);
};

struct XAP_channel {
	char *chan_label;
	char *chan_name;
	uint32_t chan_flags;

	/* how many instances of this channel are allowed? */
	int chan_count_min;
	int chan_count_max;

	/* channel controls and I/O */
	int chan_n_controls;
	XAP_control **chan_controls;
	int chan_n_ports;
	XAP_port **chan_ports;
};

/* an audio port */
struct XAP_port {
	char *port_label;
	char *port_name;
	char *port_hints;
	uint32_t port_flags;
};

/* flags for various control types */
#define XAP_PTFL_INPUT_P		0x01
#define XAP_PORT_IS_INPUT(port)		((port)->flags & XAP_CTFL_INPUT_P)
#define XAP_PORT_IS_OUTPUT(port)	(!((port)->flags & XAP_CTFL_INPUT_P))

/* common port labels - a good source of hints to the host! */
#define XAP_PORTHINT_MONO		"MONO"
#define XAP_PORTHINT_FLEFT		"FRONT_LEFT"
#define XAP_PORTHINT_FRIGHT		"FRONT_RIGHT"
#define XAP_PORTHINT_FCENTER		"FRONT_CENTER"
#define XAP_PORTHINT_RLEFT		"REAR_LEFT"
#define XAP_PORTHINT_RRIGHT		"REAR_RIGHT"
#define XAP_PORTHINT_SUB		"SUB"
#define XAP_PORTHINT_SLEFT		"SURR_LEFT"
#define XAP_PORTHINT_SRIGHT		"SURR_RIGHT"

/*
 * A XAP host: this provides callbacks for plugins to access host-provided
 * resources.  This puts control of things such as failures in the hands of
 * the host, not the plugin.
 */
struct XAP_host {
	//FIXME: some sort of host ID/version ?
	uint32_t host_api;
	//FIXME: how does the host know where an event came from?
	XAP_event_queue *host_queue;
	void *(*host_malloc)(size_t size);
	void (*host_free)(void *ptr);
	void *(*host_realloc)(void *ptr, size_t size);
	void (*host_alloc_failure)(void);
	//FIXME: get_buffer(int nsamples) ?
	//FIXME: free_buffer() ?
	//FIXME: get_silent_buffer(int nsamples) ?
};

struct XAP_event_port {
	XAP_event_queue *evp_queue;
	uint32_t exp_cookie;
};

/* the various types that a control may be */
enum XAP_ctrl_type{
	XAP_CTRL_INT = 1,
	XAP_CTRL_FLOAT = 2,
	XAP_CTRL_ENUM = 3,
	XAP_CTRL_STRING = 4,
	XAP_CTRL_RAW = 5,
};

/* for declaring ctrl sub-types */
#define XAP_CONTROL_COMMON_FIELDS_ \
	/* \
	 * Label is a unique (within this plugin), non-whitespace string \
	 * identifier. The label is all upper case, by convention. \
	 */ \
	const char *ctrl_label; \
	/* display-friendly name */ \
	const char *ctrl_name; \
	/* hints to the host */ \
	const char *ctrl_hints; \
	/* the type of control */ \
	XAP_ctrl_type ctrl_type; \
	/* global and per-type flags - XAP_CTFL_* */ \
	uint32_t ctrl_flags; \
	/* hints about real-time behavior of controls - XAP_RTFL_* */ \
	uint32_t ctrl_rtflags;

/* a knob, button, etc. of a plugin */
struct XAP_control {
	XAP_CONTROL_COMMON_FIELDS_
};
/* to help in declaring arrays of pointers to structs statically */
#define XAP_DECL_CONTROL(type)	(XAP_control *)&(XAP_ctrl_ ## type)

/* the expanded structs for each control type */
struct XAP_ctrl_int {
	XAP_CONTROL_COMMON_FIELDS_
	int ctrl_min;
	int ctrl_max;
	int ctrl_default;
};

struct XAP_ctrl_float {
	XAP_CONTROL_COMMON_FIELDS_
	float ctrl_min;
	float ctrl_max;
	float ctrl_default;
};

struct XAP_ctrl_enum {
	XAP_CONTROL_COMMON_FIELDS_
	int ctrl_min;
	int ctrl_max;
	int ctrl_default;
	const char **ctrl_options;
};

struct XAP_ctrl_string {
	XAP_CONTROL_COMMON_FIELDS_
	const char *ctrl_default;
};

struct XAP_raw_data {
	int raw_size;  /* bytes */
	void *raw_data;
};

struct XAP_ctrl_raw {
	XAP_CONTROL_COMMON_FIELDS_
	XAP_raw_data *ctrl_default;
};

/* flags for various control types */
#define XAP_CTFL_PERVOICE_P		0x01
#define XAP_CTRL_IS_VOICE(ctrl)		((ctrl)->flags & XAP_CTFL_VOICE_P)
#define XAP_CTRL_IS_CHANNEL(ctrl)	(!((ctrl)->flags & XAP_CTFL_VOICE_P))
#define XAP_CTFL_INPUT_P		0x02
#define XAP_CTRL_IS_INPUT(ctrl)		((ctrl)->flags & XAP_CTFL_INPUT_P)
#define XAP_CTRL_IS_OUTPUT(ctrl)	(!((ctl)->flags & XAP_CTFL_INPUT_P))
#define XAP_CTFL_HARDLIM_P		0x04
#define XAP_CTRL_IS_HARDLIMIT(ctrl)	((ctrl)->flags & XAP_CTFL_HARDLIM_P)
#define XAP_CTRL_IS_SOFTLIMIT(ctrl)	(!((ctl)->flags & XAP_CTFL_HARDLIM_P))

//FIXME: renumber, re-examine
#define XAP_CTFL_SCALAR		0x01	/* is scalar to the sample rate */
#define XAP_CTFL_LOG		0x02	/* is logarithmic */
#define XAP_CTFL_FILE		0x04	/* is a file name */
#define XAP_CTFL_DIR		0x08	/* is a directory */
#define XAP_CTFL_BOOL		0x10	/* is a boolean */
#define XAP_CTFL_FRAMES		0x20	/* is a measurement of frames */
#define XAP_CTFL_RDONLY		0x40	/* is read-only */

/* flags to identify real-time behavior of controls */
#define XAP_RTFL_NEVER		0x01	/* is never RT safe */
#define XAP_RTFL_MALLOC		0x02	/* allocates/frees memory */
#define XAP_RTFL_HMALLOC	0x04	/* allocates memory through the host */
#define XAP_RTFL_HFREE		0x08	/* frees memory through the host */
#define XAP_RTFL_FILEIO		0x10	/* performs file I/O */
#define XAP_RTFL_SLOW		0x20	/* is 'slow' in general */

/* common control labels - a good source of hints to the host! */
#define XAP_CTRLHINT_VELOCITY		"VELOCITY"	//voice
#define XAP_CTRLHINT_AFTERTOUCH		"AFTERTOUCH"	//voice
#define XAP_CTRLHINT_CHPRESSURE		"CHPRESSURE"	//channel
#define XAP_CTRLHINT_PITCH		"PITCH"		//channel,voice
#define XAP_CTRLHINT_MODULATION		"MODULATION"	//channel,voice
#define XAP_CTRLHINT_BREATH		"BREATH"	//channel,voice
#define XAP_CTRLHINT_FOOTPEDAL		"FOOTPEDAL"	//channel,voice
#define XAP_CTRLHINT_PORTATIME		"PORTATIME"	//channel,voice
#define XAP_CTRLHINT_VOLUME		"VOLUME"	//channel,voice
#define XAP_CTRLHINT_BALANCE		"BALANCE"	//channel,voice
#define XAP_CTRLHINT_PAN		"PAN"		//channel,voice
#define XAP_CTRLHINT_EXPRESSION		"EXPRESSION"	//channel,voice
#define XAP_CTRLHINT_HOLDPEDAL		"HOLDPEDAL"	//channel,voice: bool
#define XAP_CTRLHINT_PORTAMENTO		"PORTAMENTO"	//channel,voice: bool
#define XAP_CTRLHINT_SOSTENUTO		"SOSTENUTO"	//channel,voice: bool
#define XAP_CTRLHINT_SOFTPEDAL		"SOFTPEDAL"	//channel,voice: bool
#define XAP_CTRLHINT_HOLD2PEDAL		"HOLD2PEDAL"	//channel,voice: bool
#define XAP_CTRLHINT_SNDTIMBRE		"SNDTIMBRE"	//channel,voice
#define XAP_CTRLHINT_SNDRELEASE		"SNDRELEASE"	//channel,voice
#define XAP_CTRLHINT_SNDATTACK		"SNDATTACK"	//channel,voice
#define XAP_CTRLHINT_SNDBRIGHT		"SNDBRIGHT"	//channel,voice
#define XAP_CTRLHINT_FXDEPTH		"FXDEPTH"	//channel,voice
#define XAP_CTRLHINT_TREMELO		"TREMELO"	//channel,voice
#define XAP_CTRLHINT_CHORUS		"CHORUS"	//channel,voice
#define XAP_CTRLHINT_CELESTE		"CELESTE"	//channel,voice
#define XAP_CTRLHINT_PHASER		"PHASER"	//channel,voice
#define XAP_CTRLHINT_POLYPHONY		"POLYPHONY"	//channel
#define XAP_CTRLHINT_TEMPO		"TEMPO"		//channel
#define XAP_CTRLHINT_VOICECTRL		"VOICECTRL"	//channel
//FIXME: describe these controls, maybe have a macro to declare them [0.0-1.0]
// or [-1.0 to 1.0] or whatever

/* An event queue - where events are actually stored */
struct XAP_event_queue {
	XAP_event *evq_first;
	XAP_event *evq_last;
};

/*
 * An event - passed to plugins on their XAP_event_queue. The ev_time field
 * is a sample count, from some arbitrary start.  Hosts pass the timestamp
 * of the start of the buffer to the plugin run() method.
 */
struct XAP_event {
	XAP_event *ev_next;
	uint32_t ev_cookie;
	XAP_timestamp ev_time;
	XAP_event_id ev_event;
	uint32_t ev_voice;
	XAP_event_ramp ev_ramp_type;
	XAP_timestamp ev_ramp_length;
};

/* The known events */
enum XAP_event_id {
	XAP_EVENT_NULL = 0,
	XAP_EVENT_CTRL = 1,
};

/* ramp styles */
enum XAMP_event_ramp {
	XAP_RAMP_NONE = 0,
	XAP_RAMP_LINEAR = 1,
};

/* how the host learns about the plugin */
XAP_descriptor *xap_descriptor(int index);


/*
 * utility functions
 */

/* return true if time0 is after time1 */
static inline int
xap_time_after(XAP_timestamp time0, XAP_timestamp time1)
{
	return ((long)(time1) - (long)(time0) < 0);
}
#define xap_time_before(t0, t1)		xap_time_after(t1, t0)

/* return true if time0 is after or equal to time1 */
static inline int
xap_time_after_eq(XAP_timestamp time0, XAP_timestamp time1)
{
	return ((long)(time1) - (long)(time0) <= 0);
}
#define xap_time_before_eq(t0, t1)	xap_time_after_eq(t1, t0)


#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* XAP_H__ */



More information about the Linux-audio-dev mailing list