Chris@49: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */
Chris@0: 
Chris@0: /* dssi.h
Chris@0: 
Chris@0:    DSSI version 0.10
Chris@0:    Copyright (c) 2004,2005 Chris Cannam, Steve Harris and Sean Bolton
Chris@0:    
Chris@0:    This library is free software; you can redistribute it and/or
Chris@0:    modify it under the terms of the GNU Lesser General Public License
Chris@0:    as published by the Free Software Foundation; either version 2.1 of
Chris@0:    the License, or (at your option) any later version.
Chris@0:    
Chris@0:    This library is distributed in the hope that it will be useful, but
Chris@0:    WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Chris@0:    Lesser General Public License for more details.
Chris@0:    
Chris@0:    You should have received a copy of the GNU Lesser General Public
Chris@0:    License along with this library; if not, write to the Free Software
Chris@0:    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
Chris@0:    USA.
Chris@0: */
Chris@0: 
Chris@0: #ifndef DSSI_INCLUDED
Chris@0: #define DSSI_INCLUDED
Chris@0: 
Chris@0: #include "ladspa.h"
Chris@0: #include "alsa/seq_event.h"
Chris@0: 
Chris@0: #define DSSI_VERSION "0.10"
Chris@0: #define DSSI_VERSION_MAJOR 0
Chris@0: #define DSSI_VERSION_MINOR 10
Chris@0: 
Chris@0: #ifdef __cplusplus
Chris@0: extern "C" {
Chris@0: #endif
Chris@0: 
Chris@0: /* 
Chris@0:    There is a need for an API that supports hosted MIDI soft synths
Chris@0:    with GUIs in Linux audio applications.  In time the GMPI initiative
Chris@0:    should comprehensively address this need, but the requirement for
Chris@0:    Linux applications to be able to support simple hosted synths is
Chris@0:    here now, and GMPI is not.  This proposal (the "DSSI Soft Synth
Chris@0:    Interface" or DSSI, pronounced "dizzy") aims to provide a simple
Chris@0:    solution in a way that we hope will prove complete and compelling
Chris@0:    enough to support now, yet not so compelling as to supplant GMPI or
Chris@0:    any other comprehensive future proposal.
Chris@0: 
Chris@0:    For simplicity and familiarity, this API is based as far as
Chris@0:    possible on existing work -- the LADSPA plugin API for control
Chris@0:    values and audio processing, and the ALSA sequencer event types for
Chris@0:    MIDI event communication.  The GUI part of the proposal is quite
Chris@0:    new, but may also be applicable retroactively to LADSPA plugins
Chris@0:    that do not otherwise support this synth interface.
Chris@0: */
Chris@0: 
Chris@0: /*
Chris@0:    A program wishing to use the DSSI v2 API should set the following
Chris@0:    symbol to 2 before including this header.
Chris@0: */
Chris@0: #if (!defined DSSI_API_LEVEL)
Chris@0: #define DSSI_API_LEVEL 1
Chris@0: #endif
Chris@0: 
Chris@0: typedef struct _DSSI_Program_Descriptor {
Chris@0: 
Chris@0:     /** Bank number for this program.  Note that DSSI does not support
Chris@0:         MIDI-style separation of bank LSB and MSB values.  There is no
Chris@0:         restriction on the set of available banks: the numbers do not
Chris@0:         need to be contiguous, there does not need to be a bank 0, etc. */
Chris@0:     unsigned long Bank;
Chris@0: 
Chris@0:     /** Program number (unique within its bank) for this program.
Chris@0: 	There is no restriction on the set of available programs: the
Chris@0: 	numbers do not need to be contiguous, there does not need to
Chris@0: 	be a program 0, etc. */
Chris@0:     unsigned long Program;
Chris@0: 
Chris@0:     /** Name of the program. */
Chris@0:     const char * Name;
Chris@0: 
Chris@0: } DSSI_Program_Descriptor;
Chris@0: 
Chris@0: 
Chris@0: #define DSSI_TRANSPORT_VALID_STATE  0x01
Chris@0: #define DSSI_TRANSPORT_VALID_BPM    0x02
Chris@0: #define DSSI_TRANSPORT_VALID_BBT    0x10
Chris@0: #define DSSI_TRANSPORT_VALID_TIME   0x20
Chris@0: 
Chris@0: #define DSSI_TRANSPORT_STATE_STOPPED       0
Chris@0: #define DSSI_TRANSPORT_STATE_RUNNING       1
Chris@0: #define DSSI_TRANSPORT_STATE_FREEWHEELING  2
Chris@0: #define DSSI_TRANSPORT_STATE_OTHER         3  /* waiting for sync, ? */
Chris@0: 
Chris@0: typedef struct _DSSI_Transport_Info {
Chris@0: 
Chris@0:     /** The value of this field indicates which of the following
Chris@0:      *  transport information fields contain valid values. It is
Chris@0:      *  the logical OR of the DSSI_TRANSPORT_VALID_* bits defined
Chris@0:      *  above, and may be zero. */
Chris@0:     int  Valid;
Chris@0: 
Chris@0: 
Chris@0:     /** This field is valid when (Valid & DSSI_TRANSPORT_VALID_STATE)
Chris@0:      *  is true:
Chris@0:      *
Chris@0:      *  ---- The current transport state, one of the DSSI_TRANSPORT_STATE_*
Chris@0:      *       values defined above. */
Chris@0:     int  State;
Chris@0: 
Chris@0: 
Chris@0:     /** This field is valid when (Valid & DSSI_TRANSPORT_VALID_BPM)
Chris@0:      *  is true:
Chris@0:      *
Chris@0:      *  ---- The current tempo, in beats per minute.  */
Chris@0:     double Beats_Per_Minute;
Chris@0: 
Chris@0: 
Chris@0:     /** These six fields are valid when (Valid & DSSI_TRANSPORT_VALID_BBT)
Chris@0:      *  is true:
Chris@0:      *
Chris@0:      *  ---- The bar number at the beginning of the current process cycle. */
Chris@0:     unsigned long Bar;
Chris@0: 
Chris@0:     /** ---- The beat within that Bar. */
Chris@0:     unsigned long Beat;
Chris@0:     
Chris@0:     /** ---- The tick within that Beat. */
Chris@0:     unsigned long Tick;
Chris@0: 
Chris@0:     /** ---- The (possibly fractional) tick count since transport 'start'
Chris@0:      *       and the beginning of the current Bar. */
Chris@0:     double Bar_Start_Tick;
Chris@0: 
Chris@0:     /** ---- The number of beats per bar. */
Chris@0:     float  Beats_Per_Bar;
Chris@0: 
Chris@0:     /** ---- The number of ticks for each beat. */
Chris@0:     double Ticks_Per_Beat;
Chris@0: 
Chris@0:     /* [Sean says: I left out the 'beat_type' (time signature "denominator")
Chris@0:      * field of the jack_position_t structure, because I think it's useless
Chris@0:      * except to a notation program. Does anybody else feel like we need it?]
Chris@0:      */
Chris@0: 
Chris@0:     /** These two fields are valid when (Valid & DSSI_TRANSPORT_VALID_TIME)
Chris@0:      *  is true:
Chris@0:      *
Chris@0:      *  ---- The transport time at the beginning of the current process
Chris@0:      *       cycle, in seconds. */
Chris@0:     double  Current_Time;
Chris@0: 
Chris@0:     /** ---- The transport time at the beginning of the next process
Chris@0:              cycle, unless repositioning occurs. */
Chris@0:     double  Next_Time;
Chris@0: 
Chris@0: } DSSI_Transport_Info;
Chris@0: 
Chris@0: typedef struct _DSSI_Host_Descriptor DSSI_Host_Descriptor; /* below */
Chris@0: 
Chris@0: typedef struct _DSSI_Descriptor {
Chris@0: 
Chris@0:     /**
Chris@0:      * DSSI_API_Version
Chris@0:      *
Chris@0:      * This member indicates the DSSI API level used by this plugin.
Chris@0:      * All plugins must set this to 1 or 2.  The version 1 API contains
Chris@0:      * all DSSI_Descriptor fields through run_multiple_synths_adding(),
Chris@0:      * while the version 2 API adds the receive_host_descriptor().
Chris@0:      */
Chris@0:     int DSSI_API_Version;
Chris@0: 
Chris@0:     /**
Chris@0:      * LADSPA_Plugin
Chris@0:      *
Chris@0:      * A DSSI synth plugin consists of a LADSPA plugin plus an
Chris@0:      * additional framework for controlling program settings and
Chris@0:      * transmitting MIDI events.  A plugin must fully implement the
Chris@0:      * LADSPA descriptor fields as well as the required LADSPA
Chris@0:      * functions including instantiate() and (de)activate().  It
Chris@0:      * should also implement run(), with the same behaviour as if
Chris@0:      * run_synth() (below) were called with no synth events.
Chris@0:      *
Chris@0:      * In order to instantiate a synth the host calls the LADSPA
Chris@0:      * instantiate function, passing in this LADSPA_Descriptor
Chris@0:      * pointer.  The returned LADSPA_Handle is used as the argument
Chris@0:      * for the DSSI functions below as well as for the LADSPA ones.
Chris@0:      */
Chris@0:     const LADSPA_Descriptor *LADSPA_Plugin;
Chris@0: 
Chris@0:     /**
Chris@0:      * configure()
Chris@0:      *
Chris@0:      * This member is a function pointer that sends a piece of
Chris@0:      * configuration data to the plugin.  The key argument specifies
Chris@0:      * some aspect of the synth's configuration that is to be changed,
Chris@0:      * and the value argument specifies a new value for it.  A plugin
Chris@0:      * that does not require this facility at all may set this member
Chris@0:      * to NULL.
Chris@0:      *
Chris@0:      * This call is intended to set some session-scoped aspect of a
Chris@0:      * plugin's behaviour, for example to tell the plugin to load
Chris@0:      * sample data from a particular file.  The plugin should act
Chris@0:      * immediately on the request.  The call should return NULL on
Chris@0:      * success, or an error string that may be shown to the user.  The
Chris@0:      * host will free the returned value after use if it is non-NULL.
Chris@0:      *
Chris@0:      * Calls to configure() are not automated as timed events.
Chris@0:      * Instead, a host should remember the last value associated with
Chris@0:      * each key passed to configure() during a given session for a
Chris@0:      * given plugin instance, and should call configure() with the
Chris@0:      * correct value for each key the next time it instantiates the
Chris@0:      * "same" plugin instance, for example on reloading a project in
Chris@0:      * which the plugin was used before.  Plugins should note that a
Chris@0:      * host may typically instantiate a plugin multiple times with the
Chris@0:      * same configuration values, and should share data between
Chris@0:      * instances where practical.
Chris@0:      *
Chris@0:      * Calling configure() completely invalidates the program and bank
Chris@0:      * information last obtained from the plugin.
Chris@0:      *
Chris@0:      * Reserved and special key prefixes
Chris@0:      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Chris@0:      * The DSSI: prefix
Chris@0:      * ----------------
Chris@0:      * Configure keys starting with DSSI: are reserved for particular
Chris@0:      * purposes documented in the DSSI specification.  At the moment,
Chris@0:      * there is one such key: DSSI:PROJECT_DIRECTORY.  A host may call
Chris@0:      * configure() passing this key and a directory path value.  This
Chris@0:      * indicates to the plugin and its UI that a directory at that
Chris@0:      * path exists and may be used for project-local data.  Plugins
Chris@0:      * may wish to use the project directory as a fallback location
Chris@0:      * when looking for other file data, or as a base for relative
Chris@0:      * paths in other configuration values.
Chris@0:      *
Chris@0:      * The GLOBAL: prefix
Chris@0:      * ------------------
Chris@0:      * Configure keys starting with GLOBAL: may be used by the plugin
Chris@0:      * and its UI for any purpose, but are treated specially by the
Chris@0:      * host.  When one of these keys is used in a configure OSC call
Chris@0:      * from the plugin UI, the host makes the corresponding configure
Chris@0:      * call (preserving the GLOBAL: prefix) not only to the target
Chris@0:      * plugin but also to all other plugins in the same instance
Chris@0:      * group, as well as their UIs.  Note that if any instance
Chris@0:      * returns non-NULL from configure to indicate error, the host
Chris@0:      * may stop there (and the set of plugins on which configure has
Chris@0:      * been called will thus depend on the host implementation).
Chris@0:      * See also the configure OSC call documentation in RFC.txt.
Chris@0:      */
Chris@0:     char *(*configure)(LADSPA_Handle Instance,
Chris@0: 		       const char *Key,
Chris@0: 		       const char *Value);
Chris@0: 
Chris@0:     #define DSSI_RESERVED_CONFIGURE_PREFIX "DSSI:"
Chris@0:     #define DSSI_GLOBAL_CONFIGURE_PREFIX "GLOBAL:"
Chris@0:     #define DSSI_PROJECT_DIRECTORY_KEY \
Chris@0: 	DSSI_RESERVED_CONFIGURE_PREFIX "PROJECT_DIRECTORY"
Chris@0: 
Chris@0:     /**
Chris@0:      * get_program()
Chris@0:      *
Chris@0:      * This member is a function pointer that provides a description
Chris@0:      * of a program (named preset sound) available on this synth.  A
Chris@0:      * plugin that does not support programs at all should set this
Chris@0:      * member to NULL.
Chris@0:      *
Chris@0:      * The Index argument is an index into the plugin's list of
Chris@0:      * programs, not a program number as represented by the Program
Chris@0:      * field of the DSSI_Program_Descriptor.  (This distinction is
Chris@0:      * needed to support synths that use non-contiguous program or
Chris@0:      * bank numbers.)
Chris@0:      *
Chris@0:      * This function returns a DSSI_Program_Descriptor pointer that is
Chris@0:      * guaranteed to be valid only until the next call to get_program,
Chris@0:      * deactivate, or configure, on the same plugin instance.  This
Chris@0:      * function must return NULL if passed an Index argument out of
Chris@0:      * range, so that the host can use it to query the number of
Chris@0:      * programs as well as their properties.
Chris@0:      */
Chris@0:     const DSSI_Program_Descriptor *(*get_program)(LADSPA_Handle Instance,
Chris@0: 						  unsigned long Index);
Chris@0:     
Chris@0:     /**
Chris@0:      * select_program()
Chris@0:      *
Chris@0:      * This member is a function pointer that selects a new program
Chris@0:      * for this synth.  The program change should take effect
Chris@0:      * immediately at the start of the next run_synth() call.  (This
Chris@0:      * means that a host providing the capability of changing programs
Chris@0:      * between any two notes on a track must vary the block size so as
Chris@0:      * to place the program change at the right place.  A host that
Chris@0:      * wanted to avoid this would probably just instantiate a plugin
Chris@0:      * for each program.)
Chris@0:      * 
Chris@0:      * A plugin that does not support programs at all should set this
Chris@0:      * member NULL.  Plugins should ignore a select_program() call
Chris@0:      * with an invalid bank or program.
Chris@0:      *
Chris@0:      * A plugin is not required to select any particular default
Chris@0:      * program on activate(): it's the host's duty to set a program
Chris@0:      * explicitly.  The current program is invalidated by any call to
Chris@0:      * configure().
Chris@0:      *
Chris@0:      * A plugin is permitted to re-write the values of its input
Chris@0:      * control ports when select_program is called.  The host should
Chris@0:      * re-read the input control port values and update its own
Chris@0:      * records appropriately.  (This is the only circumstance in
Chris@0:      * which a DSSI plugin is allowed to modify its own input ports.)
Chris@0:      */
Chris@0:     void (*select_program)(LADSPA_Handle Instance,
Chris@0: 			   unsigned long Bank,
Chris@0: 			   unsigned long Program);
Chris@0: 
Chris@0:     /**
Chris@0:      * get_midi_controller_for_port()
Chris@0:      *
Chris@0:      * This member is a function pointer that returns the MIDI
Chris@0:      * controller number or NRPN that should be mapped to the given
Chris@0:      * input control port.  If the given port should not have any MIDI
Chris@0:      * controller mapped to it, the function should return DSSI_NONE.
Chris@0:      * The behaviour of this function is undefined if the given port
Chris@0:      * number does not correspond to an input control port.  A plugin
Chris@0:      * that does not want MIDI controllers mapped to ports at all may
Chris@0:      * set this member NULL.
Chris@0:      *
Chris@0:      * Correct values can be got using the macros DSSI_CC(num) and
Chris@0:      * DSSI_NRPN(num) as appropriate, and values can be combined using
Chris@0:      * bitwise OR: e.g. DSSI_CC(23) | DSSI_NRPN(1069) means the port
Chris@0:      * should respond to CC #23 and NRPN #1069.
Chris@0:      *
Chris@0:      * The host is responsible for doing proper scaling from MIDI
Chris@0:      * controller and NRPN value ranges to port ranges according to
Chris@0:      * the plugin's LADSPA port hints.  Hosts should not deliver
Chris@0:      * through run_synth any MIDI controller events that have already
Chris@0:      * been mapped to control port values.
Chris@0:      *
Chris@0:      * A plugin should not attempt to request mappings from
Chris@0:      * controllers 0 or 32 (MIDI Bank Select MSB and LSB).
Chris@0:      */
Chris@0:     int (*get_midi_controller_for_port)(LADSPA_Handle Instance,
Chris@0: 					unsigned long Port);
Chris@0: 
Chris@0:     /**
Chris@0:      * run_synth()
Chris@0:      *
Chris@0:      * This member is a function pointer that runs a synth for a
Chris@0:      * block.  This is identical in function to the LADSPA run()
Chris@0:      * function, except that it also supplies events to the synth.
Chris@0:      *
Chris@0:      * A plugin may provide this function, run_multiple_synths() (see
Chris@0:      * below), both, or neither (if it is not in fact a synth).  A
Chris@0:      * plugin that does not provide this function must set this member
Chris@0:      * to NULL.  Authors of synth plugins are encouraged to provide
Chris@0:      * this function if at all possible.
Chris@0:      *
Chris@0:      * The Events pointer points to a block of EventCount ALSA
Chris@0:      * sequencer events, which is used to communicate MIDI and related
Chris@0:      * events to the synth.  Each event is timestamped relative to the
Chris@0:      * start of the block, (mis)using the ALSA "tick time" field as a
Chris@0:      * frame count. The host is responsible for ensuring that events
Chris@0:      * with differing timestamps are already ordered by time.
Chris@0:      *
Chris@0:      * See also the notes on activation, port connection etc in
Chris@0:      * ladpsa.h, in the context of the LADSPA run() function.
Chris@0:      *
Chris@0:      * Note Events
Chris@0:      * ~~~~~~~~~~~
Chris@0:      * There are two minor requirements aimed at making the plugin
Chris@0:      * writer's life as simple as possible:
Chris@0:      * 
Chris@0:      * 1. A host must never send events of type SND_SEQ_EVENT_NOTE.
Chris@0:      * Notes should always be sent as separate SND_SEQ_EVENT_NOTE_ON
Chris@0:      * and NOTE_OFF events.  A plugin should discard any one-point
Chris@0:      * NOTE events it sees.
Chris@0:      * 
Chris@0:      * 2. A host must not attempt to switch notes off by sending
Chris@0:      * zero-velocity NOTE_ON events.  It should always send true
Chris@0:      * NOTE_OFFs.  It is the host's responsibility to remap events in
Chris@0:      * cases where an external MIDI source has sent it zero-velocity
Chris@0:      * NOTE_ONs.
Chris@0:      *
Chris@0:      * Bank and Program Events
Chris@0:      * ~~~~~~~~~~~~~~~~~~~~~~~
Chris@0:      * Hosts must map MIDI Bank Select MSB and LSB (0 and 32)
Chris@0:      * controllers and MIDI Program Change events onto the banks and
Chris@0:      * programs specified by the plugin, using the DSSI select_program
Chris@0:      * call.  No host should ever deliver a program change or bank
Chris@0:      * select controller to a plugin via run_synth.
Chris@0:      */
Chris@0:     void (*run_synth)(LADSPA_Handle    Instance,
Chris@0: 		      unsigned long    SampleCount,
Chris@0: 		      snd_seq_event_t *Events,
Chris@0: 		      unsigned long    EventCount);
Chris@0: 
Chris@0:     /**
Chris@0:      * run_synth_adding()
Chris@0:      *
Chris@0:      * This member is a function pointer that runs an instance of a
Chris@0:      * synth for a block, adding its outputs to the values already
Chris@0:      * present at the output ports.  This is provided for symmetry
Chris@0:      * with LADSPA run_adding(), and is equally optional.  A plugin
Chris@0:      * that does not provide it must set this member to NULL.
Chris@0:      */
Chris@0:     void (*run_synth_adding)(LADSPA_Handle    Instance,
Chris@0: 			     unsigned long    SampleCount,
Chris@0: 			     snd_seq_event_t *Events,
Chris@0: 			     unsigned long    EventCount);
Chris@0: 
Chris@0:     /**
Chris@0:      * run_multiple_synths()
Chris@0:      *
Chris@0:      * This member is a function pointer that runs multiple synth
Chris@0:      * instances for a block.  This is very similar to run_synth(),
Chris@0:      * except that Instances, Events, and EventCounts each point to
Chris@0:      * arrays that hold the LADSPA handles, event buffers, and
Chris@0:      * event counts for each of InstanceCount instances.  That is,
Chris@0:      * Instances points to an array of InstanceCount pointers to
Chris@0:      * DSSI plugin instantiations, Events points to an array of
Chris@0:      * pointers to each instantiation's respective event list, and
Chris@0:      * EventCounts points to an array containing each instantiation's
Chris@0:      * respective event count.
Chris@0:      *
Chris@0:      * A host using this function must guarantee that ALL active
Chris@0:      * instances of the plugin are represented in each call to the
Chris@0:      * function -- that is, a host may not call run_multiple_synths()
Chris@0:      * for some instances of a given plugin and then call run_synth()
Chris@0:      * as well for others.  'All .. instances of the plugin' means
Chris@0:      * every instance sharing the same LADSPA label and shared object
Chris@0:      * (*.so) file (rather than every instance sharing the same *.so).
Chris@0:      * 'Active' means any instance for which activate() has been called
Chris@0:      * but deactivate() has not.
Chris@0:      *
Chris@0:      * A plugin may provide this function, run_synths() (see above),
Chris@0:      * both, or neither (if it not in fact a synth).  A plugin that
Chris@0:      * does not provide this function must set this member to NULL.
Chris@0:      * Plugin authors implementing run_multiple_synths are strongly
Chris@0:      * encouraged to implement run_synth as well if at all possible,
Chris@0:      * to aid simplistic hosts, even where it would be less efficient
Chris@0:      * to use it.
Chris@0:      */
Chris@0:     void (*run_multiple_synths)(unsigned long     InstanceCount,
Chris@0:                                 LADSPA_Handle    *Instances,
Chris@0:                                 unsigned long     SampleCount,
Chris@0:                                 snd_seq_event_t **Events,
Chris@0:                                 unsigned long    *EventCounts);
Chris@0: 
Chris@0:     /**
Chris@0:      * run_multiple_synths_adding()
Chris@0:      *
Chris@0:      * This member is a function pointer that runs multiple synth
Chris@0:      * instances for a block, adding each synth's outputs to the
Chris@0:      * values already present at the output ports.  This is provided
Chris@0:      * for symmetry with both the DSSI run_multiple_synths() and LADSPA
Chris@0:      * run_adding() functions, and is equally optional.  A plugin
Chris@0:      * that does not provide it must set this member to NULL.
Chris@0:      */
Chris@0:     void (*run_multiple_synths_adding)(unsigned long     InstanceCount,
Chris@0:                                        LADSPA_Handle    *Instances,
Chris@0:                                        unsigned long     SampleCount,
Chris@0:                                        snd_seq_event_t **Events,
Chris@0:                                        unsigned long    *EventCounts);
Chris@0: 
Chris@0: #if (DSSI_API_LEVEL > 1)
Chris@0: 
Chris@0:     /**
Chris@0:      * receive_host_descriptor()
Chris@0:      *
Chris@0:      * This member is a function pointer by which a host may provide
Chris@0:      * a plugin with a pointer to its DSSI_Host_Descriptor. Hosts
Chris@0:      * which provide host descriptor support must call this function
Chris@0:      * once per plugin shared object file, before any calls to
Chris@0:      * instantiate().
Chris@0:      *
Chris@0:      * NOTE: This field was added in version 2 of the DSSI API. Hosts
Chris@0:      * supporting version 2 must not access this field in a plugin
Chris@0:      * whose DSSI_API_Version is 1, and plugins supporting version 2
Chris@0:      * should behave reasonably under hosts (of any version) which do
Chris@0:      * not implement this function. A version 2 plugin that does not
Chris@0:      * provide this function must set this member to NULL.
Chris@0:      */
Chris@0:     void (*receive_host_descriptor)(const DSSI_Host_Descriptor *Descriptor);
Chris@0: 
Chris@0: #endif
Chris@0: 
Chris@0: } DSSI_Descriptor;
Chris@0: 
Chris@0: struct _DSSI_Host_Descriptor {
Chris@0: 
Chris@0:     /**
Chris@0:      * DSSI_API_Version
Chris@0:      *
Chris@0:      * This member indicates the DSSI API level used by this host.
Chris@0:      * All hosts must set this to 2.  Hopefully, we'll get this right
Chris@0:      * the first time, and this will never be needed.
Chris@0:      */
Chris@0:     int DSSI_API_Version;
Chris@0: 
Chris@0:     /**
Chris@0:      * request_transport_information()
Chris@0:      *
Chris@0:      * This member is a function pointer by which a plugin instance may
Chris@0:      * request that a host begin providing transport information (if
Chris@0:      * Request is non-zero), or notify the host that it no longer needs
Chris@0:      * transport information (if Request is zero).  Upon receiving a
Chris@0:      * non-zero request, the host should return a pointer to a
Chris@0:      * DSSI_Transport_Info structure if it is able to provide transport
Chris@0:      * information, or NULL otherwise.
Chris@0:      *
Chris@0:      * Once a plugin instance has received a non-null transport
Chris@0:      * information pointer, it may read from the structure at any time
Chris@0:      * within the execution of an audio class function (see doc/RFC.txt).
Chris@0:      * It should not consider the structure contents to be meaningful
Chris@0:      * while within a instantiation or control class function.  Also,
Chris@0:      * since the validity of fields within the structure may change
Chris@0:      * between each new invocation of an audio class function, a plugin
Chris@0:      * instance must check the Valid field of the structure accordingly
Chris@0:      * before using the structure's other contents.
Chris@0:      *
Chris@0:      * A host which does not support this function must set this member
Chris@0:      * to NULL.
Chris@0:      */
Chris@0:     DSSI_Transport_Info *
Chris@0:         (*request_transport_information)(LADSPA_Handle Instance,
Chris@0:                                          int           Request);
Chris@0: 
Chris@0:     /**
Chris@0:      * request_midi_send()
Chris@0:      *
Chris@0:      * This member is a function pointer that allows a plugin to
Chris@0:      * request the ability to send MIDI events to the host.
Chris@0:      *
Chris@0:      * While the interpretation of plugin-generated MIDI events is
Chris@0:      * host implementation specific, a mechanism exists by which a
Chris@0:      * plugin may declare to the host the number of destination
Chris@0:      * 'ports' and MIDI channels it can expect will be used in the
Chris@0:      * plugin-generated events.  Plugins which generate unchannelized
Chris@0:      * MIDI should supply zero for both Ports and Channels, otherwise
Chris@0:      * they should supply the maximum numbers for Ports and Channels
Chris@0:      * they expect to use.
Chris@0:      *
Chris@0:      * A plugin instance must call this function during instantiate().
Chris@0:      * [Sean says: this restriction seems reasonable to me, since
Chris@0:      * the host may need to create output ports, etc., and instantiate()
Chris@0:      * seems like a good place to do such things.  I'm sure I haven't
Chris@0:      * fully thought through all the details, though....]
Chris@0:      *
Chris@0:      * The host should return a non-zero value if it is able to
Chris@0:      * provide MIDI send for the plugin instance, otherwise it should
Chris@0:      * return zero, and the plugin instance may not subsequently call
Chris@0:      * midi_send().
Chris@0:      *
Chris@0:      * A host which does not support the MIDI send function must set
Chris@0:      * both this member and (*midi_send)() below to NULL.
Chris@0:      */
Chris@0:     int (*request_midi_send)(LADSPA_Handle Instance,
Chris@0:                              unsigned char Ports,
Chris@0:                              unsigned char Channels);
Chris@0: 
Chris@0:     /**
Chris@0:      * midi_send()
Chris@0:      *
Chris@0:      * This member is a function pointer by which a plugin actually
Chris@0:      * sends MIDI events to the host (provided it has received a non-
Chris@0:      * zero return from request_midi_send()). As in the run_synth()
Chris@0:      * functions, the Event pointer points to a block of EventCount
Chris@0:      * ALSA sequencer events.  The dest.port and data.*.channel fields
Chris@0:      * of each event are used to specify destination port and channel,
Chris@0:      * respectively, when the plugin is supplying channelized events.
Chris@0:      *
Chris@0:      * A plugin may only call this function from within the execution
Chris@0:      * of the audio class run_*() or select_program() functions. When
Chris@0:      * called from a run_*() functions, the events are timestamped
Chris@0:      * relative to the start of the block, (mis)using the ALSA "tick
Chris@0:      * time" field as a frame count. The plugin is responsible for
Chris@0:      * ensuring that events with differing timestamps are already
Chris@0:      * ordered by time, and that timestamps across multiple calls to
Chris@0:      * midi_send() from within the same run_*() invocation are
Chris@0:      * monotonic.  When midi_send() is called from within
Chris@0:      * select_program(), the timestamps are ignored, and the events
Chris@0:      * are considered to originate at the same frame time as the
Chris@0:      * select_program() call, if such a timing can be considered
Chris@0:      * meaningful.
Chris@0:      *
Chris@0:      * The memory pointed to by Event belongs to the plugin, and it is
Chris@0:      * the host's responsibility to copy the events as needed before
Chris@0:      * returning from the midi_send() call.
Chris@0:      *
Chris@0:      * A host which does not support the MIDI send function must set
Chris@0:      * both this member and (*request_midi_send)() above to NULL.
Chris@0:      */
Chris@0:     void (*midi_send)(LADSPA_Handle    Instance,
Chris@0:                       snd_seq_event_t *Event,
Chris@0:                       unsigned long    EventCount);
Chris@0: 
Chris@0:    /**
Chris@0:     * . . . additional fields could follow here, possibly supporting:
Chris@0:     *
Chris@0:     *   - a facility by which a plugin instance may request from a
Chris@0:     *       host a non-realtime thread in which to do off-line
Chris@0:     *       rendering, I/O, etc., thus (hopefully) avoiding the
Chris@0:     *       crashes that seem to occur when plugins create their own
Chris@0:     *       threads.  I got this idea after noticing that ZynAddSubFX
Chris@0:     *       achieves its gorgeous textures while remaining very
Chris@0:     *       responsive by doing a lot of non-real-time rendering.
Chris@0:     *       Several other uses for it have been mentioned on the DSSI
Chris@0:     *       list; I forget what.
Chris@0:     *
Chris@0:     *   - per-voice audio output
Chris@0:     */
Chris@0: 
Chris@0:     int (*request_non_rt_thread)(LADSPA_Handle Instance,
Chris@0: 				 void (*RunFunction)(LADSPA_Handle Instance));
Chris@0: };
Chris@0: 
Chris@0: /**
Chris@0:  * DSSI supports a plugin discovery method similar to that of LADSPA:
Chris@0:  *
Chris@0:  * - DSSI hosts may wish to locate DSSI plugin shared object files by
Chris@0:  *    searching the paths contained in the DSSI_PATH and LADSPA_PATH
Chris@0:  *    environment variables, if they are present.  Both are expected
Chris@0:  *    to be colon-separated lists of directories to be searched (in
Chris@0:  *    order), and DSSI_PATH should be searched first if both variables
Chris@0:  *    are set.
Chris@0:  *
Chris@0:  * - Each shared object file containing DSSI plugins must include a
Chris@0:  *   function dssi_descriptor(), with the following function prototype
Chris@0:  *   and C-style linkage.  Hosts may enumerate the plugin types
Chris@0:  *   available in the shared object file by repeatedly calling
Chris@0:  *   this function with successive Index values (beginning from 0),
Chris@0:  *   until a return value of NULL indicates no more plugin types are
Chris@0:  *   available.  Each non-NULL return is the DSSI_Descriptor
Chris@0:  *   of a distinct plugin type.
Chris@0:  */
Chris@0: 
Chris@0: const DSSI_Descriptor *dssi_descriptor(unsigned long Index);
Chris@0:   
Chris@0: typedef const DSSI_Descriptor *(*DSSI_Descriptor_Function)(unsigned long Index);
Chris@0: 
Chris@0: /*
Chris@0:  * Macros to specify particular MIDI controllers in return values from
Chris@0:  * get_midi_controller_for_port()
Chris@0:  */
Chris@0: 
Chris@0: #define DSSI_CC_BITS			0x20000000
Chris@0: #define DSSI_NRPN_BITS			0x40000000
Chris@0: 
Chris@0: #define DSSI_NONE			-1
Chris@0: #define DSSI_CONTROLLER_IS_SET(n)	(DSSI_NONE != (n))
Chris@0: 
Chris@0: #define DSSI_CC(n)			(DSSI_CC_BITS | (n))
Chris@0: #define DSSI_IS_CC(n)			(DSSI_CC_BITS & (n))
Chris@0: #define DSSI_CC_NUMBER(n)		((n) & 0x7f)
Chris@0: 
Chris@0: #define DSSI_NRPN(n)			(DSSI_NRPN_BITS | ((n) << 7))
Chris@0: #define DSSI_IS_NRPN(n)			(DSSI_NRPN_BITS & (n))
Chris@0: #define DSSI_NRPN_NUMBER(n)		(((n) >> 7) & 0x3fff)
Chris@0: 
Chris@0: #ifdef __cplusplus
Chris@0: }
Chris@0: #endif
Chris@0: 
Chris@0: #endif /* DSSI_INCLUDED */