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 <[EMAIL PROTECTED]>
 * 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
 * ([EMAIL PROTECTED]).
 *
 * 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__ */

Reply via email to