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(a)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(a)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__ */