Home | History | Annotate | Line # | Download | only in dev
midictl.h revision 1.4
      1  1.4  jmcneill /* $NetBSD: midictl.h,v 1.4 2011/11/23 23:07:31 jmcneill Exp $ */
      2  1.2      chap 
      3  1.2      chap /*-
      4  1.4  jmcneill  * Copyright (c) 2006, 2008 The NetBSD Foundation, Inc.
      5  1.2      chap  * All rights reserved.
      6  1.2      chap  *
      7  1.2      chap  * This code is derived from software contributed to The NetBSD Foundation
      8  1.4  jmcneill  * by Chapman Flack and by Andrew Doran.
      9  1.2      chap  *
     10  1.2      chap  * Redistribution and use in source and binary forms, with or without
     11  1.2      chap  * modification, are permitted provided that the following conditions
     12  1.2      chap  * are met:
     13  1.2      chap  * 1. Redistributions of source code must retain the above copyright
     14  1.2      chap  *    notice, this list of conditions and the following disclaimer.
     15  1.2      chap  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.2      chap  *    notice, this list of conditions and the following disclaimer in the
     17  1.2      chap  *    documentation and/or other materials provided with the distribution.
     18  1.2      chap  *
     19  1.2      chap  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.2      chap  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.2      chap  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.2      chap  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.2      chap  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.2      chap  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.2      chap  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.2      chap  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.2      chap  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.2      chap  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.2      chap  * POSSIBILITY OF SUCH DAMAGE.
     30  1.2      chap  */
     31  1.2      chap 
     32  1.2      chap #ifndef _SYS_DEV_MIDICTL_H_
     33  1.2      chap #define _SYS_DEV_MIDICTL_H_
     34  1.2      chap 
     35  1.2      chap /*
     36  1.2      chap  * General support for MIDI controllers, registered parameters, and
     37  1.2      chap  * nonregistered parameters. It interprets MIDI messages that update
     38  1.2      chap  * these values, maintains the associated state, and provides an API
     39  1.2      chap  * for obtaining the current value of any controller or parameter and
     40  1.2      chap  * tracking changes to it.
     41  1.2      chap  *
     42  1.2      chap  * One function provides the interface for message parsing. When a message
     43  1.2      chap  * is received, once it has been determined to be a MIDI_CTL_CHANGE message,
     44  1.2      chap  * simply call midictl_change(&mc, chan, ctlval) where chan is the channel
     45  1.2      chap  * extracted from the first byte, and ctlval points to the remaining two
     46  1.2      chap  * bytes of the message received.
     47  1.2      chap  *
     48  1.2      chap  * The API for reading the state is equally simple. Use
     49  1.2      chap  * midictl_read(&mc, chan, ctlr, dflt)
     50  1.2      chap  * midictl_rpn_read(&mc, chan, rpn, dflt)
     51  1.2      chap  * midictl_nrpn_read(&mc, chan, nrpn, dflt)
     52  1.2      chap  * to read the current value of controller #ctlr, RP #rpn, or NRP #nrpn,
     53  1.2      chap  * respectively. (For 14-bit controllers, use the MSB number as ctlr, not
     54  1.2      chap  * the LSB number.) You get the complete current value; for 14-bit controllers
     55  1.2      chap  * and parameters you get a single 14-bit integer without fussing about the
     56  1.2      chap  * multiple MIDI messages needed to set it. If you read a controller or
     57  1.2      chap  * parameter that no MIDI message has yet written, you get back the value dflt.
     58  1.2      chap  * If you read one whose MSB or LSB only has been written, you get what you
     59  1.2      chap  * would get if the value had been dflt before the write.
     60  1.2      chap  *
     61  1.2      chap  * The functions may be called from any context but reentrant calls operating
     62  1.2      chap  * on the same midictl are unsupported, with one exception: calls back into
     63  1.2      chap  * midictl from a notify handler it has called are permitted. If you are
     64  1.2      chap  * calling midictl_change in a driver function called by midi(4), you are ok
     65  1.2      chap  * as midi(4) itself serializes its calls into the driver. For other uses,
     66  1.2      chap  * avoiding reentrant calls is up to you.
     67  1.2      chap  *
     68  1.2      chap  * A strict division of labor limits complexity. This module knows as little
     69  1.2      chap  * about the meanings of different MIDI parameters and controllers as possible
     70  1.2      chap  * to do its job: it knows which controllers are overloaded to serve as
     71  1.2      chap  * channel mode messages, and which are overloaded to provide access to the
     72  1.2      chap  * RPN and NRPN space. It knows which controllers are 14-bit, 7-bit, or 1-bit
     73  1.2      chap  * according to the table online at midi.org. (All parameters are treated as
     74  1.2      chap  * 14-bit.) It does not know or care about the specified default values;
     75  1.2      chap  * client code is expected to know those defaults for whatever controls it
     76  1.2      chap  * actually implements, and supply them when calling midictl_*read(). That
     77  1.2      chap  * avoids the need for a large table of specified values for things most
     78  1.2      chap  * clients will never read. A header file defining the official defaults could
     79  1.2      chap  * be useful for clients to include for use when calling midictl_*read, but
     80  1.2      chap  * is not part of this module. Reset All Controllers is simply handled by
     81  1.2      chap  * forgetting controllers have been written at all, so the next read by
     82  1.2      chap  * the client will return the client's supplied default.
     83  1.2      chap  *
     84  1.2      chap  * An incoming MIDI stream may refer to many controllers and parameters the
     85  1.2      chap  * client does not implement. To limit memory use, messages are ignored by
     86  1.2      chap  * default if they target a controller or parameter the client has never
     87  1.2      chap  * read. To indicate which controllers/parameters it supports, the client
     88  1.2      chap  * should simply read them when starting.
     89  1.2      chap  *
     90  1.2      chap  * Where the task is to generically process some MIDI stream without losing
     91  1.2      chap  * data, accept_any_ctl_rpn can be set to 1 in the midictl structure, and
     92  1.2      chap  * state will be kept for any incoming controller or RPN update. The separate
     93  1.2      chap  * flag accept_any_nrpn enables the same behavior for nonregistered parameters.
     94  1.2      chap  *
     95  1.2      chap  * Whenever a change is made to any value for which state is being kept, the
     96  1.2      chap  * notify function will be called with MIDICTL_CTLR, MIDICTL_RPN, or
     97  1.2      chap  * MIDICTL_NRPN, the channel, and the controller, rp, or nrp number,
     98  1.2      chap  * respectively. The controller number will never refer to the LSB of a 14-bit
     99  1.2      chap  * controller. The new /value/ is not included; if the change is of interest,
    100  1.2      chap  * the client reads the value and thereby supplies the default (which can still
    101  1.2      chap  * be needed if the update is to half of a 14-bit value). The notify function
    102  1.2      chap  * is also called, with appropriate evt codes, on receipt of channel mode
    103  1.2      chap  * messages.
    104  1.2      chap  *
    105  1.2      chap  * Reset All Controllers:
    106  1.2      chap  *
    107  1.2      chap  * The Reset All Controllers message will cause this module to forget settings
    108  1.2      chap  * for all controllers on the affected channel other than those specifically
    109  1.2      chap  * excepted by MIDI RP-015. Registered and nonregistered parameters are not
    110  1.2      chap  * affected. The notify function is then called with evt = MIDICTL_RESET.
    111  1.2      chap  *
    112  1.2      chap  * The client's response to MIDICTL_RESET should include reading all
    113  1.2      chap  * controllers it cares about, to ensure (if the accept_any_ctl_rpn flag is not
    114  1.2      chap  * set) that they will continue to be tracked. The client must also reset to
    115  1.2      chap  * defaults the following pieces of channel state that are not managed by this
    116  1.2      chap  * module, but required by RP-015 to be reset:
    117  1.2      chap  *  Pitch Bend
    118  1.2      chap  *  Channel Pressure
    119  1.2      chap  *  Key Pressure (for all keys on channel)
    120  1.2      chap  * The client does NOT reset the current Program.
    121  1.2      chap  */
    122  1.2      chap #include <sys/midiio.h>
    123  1.2      chap #include <sys/stdint.h>
    124  1.2      chap 
    125  1.2      chap /*
    126  1.2      chap  * Events that may be reported via a midictl_notify function.
    127  1.2      chap  * Enum starts at 1<<16 so that enum|key can be used as a switch expression.
    128  1.2      chap  * Key is 0 except where shown below.
    129  1.2      chap  */
    130  1.2      chap typedef enum {
    131  1.2      chap 	MIDICTL_CTLR      = 1<<16,	/* key=ctlr */
    132  1.2      chap 	MIDICTL_RPN       = 2<<16,	/* key=rpn */
    133  1.2      chap 	MIDICTL_NRPN      = 3<<16,	/* key=nrpn */
    134  1.2      chap 	MIDICTL_RESET     = 4<<16,	/* Reset All Controllers received */
    135  1.2      chap 	MIDICTL_NOTES_OFF = 5<<16,	/* All Notes Off received */
    136  1.2      chap 	MIDICTL_SOUND_OFF = 6<<16,	/* All Sound Off received */
    137  1.2      chap 	MIDICTL_LOCAL     = 7<<16,	/* if (key) localIsOn else localIsOff */
    138  1.2      chap 	MIDICTL_MODE      = 8<<16	/* key=mode(1-4)? TBD unimplemented */
    139  1.2      chap } midictl_evt;
    140  1.2      chap 
    141  1.2      chap /*
    142  1.2      chap  * midictl_notify(void *cookie, midictl_evt evt,
    143  1.2      chap  *                uint_fast8_t chan, uint_fast16_t key)
    144  1.2      chap  */
    145  1.2      chap typedef void
    146  1.2      chap midictl_notify(void *, midictl_evt, uint_fast8_t, uint_fast16_t);
    147  1.2      chap 
    148  1.2      chap typedef struct midictl_store midictl_store;
    149  1.2      chap 
    150  1.2      chap typedef struct {
    151  1.2      chap 	uint_fast8_t accept_any_ctl_rpn:1; /* 0 ==> ignore chgs for unqueried */
    152  1.2      chap 	uint_fast8_t accept_any_nrpn:1;    /* likewise for NRPNs */
    153  1.2      chap 	uint_fast8_t base_channel; /* set >= 16 to ignore any MODE messages */
    154  1.2      chap 	void *cookie;		   /* this value will be passed to notify */
    155  1.2      chap 	midictl_notify *notify;
    156  1.2      chap 	/* */
    157  1.2      chap 	uint16_t rpn;
    158  1.2      chap 	uint16_t nrpn;
    159  1.2      chap 	midictl_store *store;
    160  1.4  jmcneill 	kmutex_t *lock;
    161  1.2      chap } midictl;
    162  1.2      chap 
    163  1.4  jmcneill extern int
    164  1.2      chap midictl_open(midictl *);
    165  1.2      chap 
    166  1.2      chap extern void
    167  1.2      chap midictl_close(midictl *);
    168  1.2      chap 
    169  1.2      chap /*
    170  1.2      chap  * Called on receipt of a Control Change message. Updates the controller,
    171  1.2      chap  * RPN, or NRPN value as appropriate. When updating a controller or RPN that
    172  1.2      chap  * is defined in the spec as boolean, all values that by definition represent
    173  1.2      chap  * false are coerced to zero. Fires the callback if a value of interest has
    174  1.2      chap  * been changed.
    175  1.2      chap  * ctlval: points to the second byte of the message (therefore, to a two-
    176  1.2      chap  * byte array: controller number and value).
    177  1.2      chap  * midictl_change(midictl *mc, uint_fast8_t chan, uint8_t *ctlval);
    178  1.2      chap  */
    179  1.2      chap extern void
    180  1.2      chap midictl_change(midictl *, uint_fast8_t, uint8_t *);
    181  1.2      chap 
    182  1.2      chap /*
    183  1.2      chap  * Read the current value of controller ctlr for channel chan.
    184  1.2      chap  * If this is the first time querying this controller on this channel,
    185  1.2      chap  * and accept_any_ctl_rpn is false, any earlier change message for it
    186  1.2      chap  * will have been ignored, so it will be given the value dflt, which is
    187  1.2      chap  * also returned, and future change messages for it will take effect.
    188  1.2      chap  * If the controller has a two-byte value and only one has been explicitly set
    189  1.2      chap  * at the time of the first query, the effect is as if the value had been
    190  1.2      chap  * first set to dflt, then the explicitly-set byte updated.
    191  1.2      chap  * midictl_read(midictl *mc, uint_fast8_t chan,
    192  1.2      chap  *              uint_fast8_t ctlr, uint_fast16_t dflt);
    193  1.2      chap  */
    194  1.2      chap extern uint_fast16_t
    195  1.2      chap midictl_read(midictl *, uint_fast8_t, uint_fast8_t, uint_fast16_t);
    196  1.2      chap 
    197  1.2      chap /*
    198  1.2      chap  * As for midictl_read, but for registered parameters or nonregistered
    199  1.2      chap  * parameters, respectively.
    200  1.2      chap  */
    201  1.2      chap extern uint_fast16_t
    202  1.2      chap midictl_rpn_read(midictl *mc, uint_fast8_t, uint_fast16_t, uint_fast16_t);
    203  1.2      chap extern uint_fast16_t
    204  1.2      chap midictl_nrpn_read(midictl *mc, uint_fast8_t, uint_fast16_t, uint_fast16_t);
    205  1.2      chap 
    206  1.2      chap #endif /* _SYS_DEV_MIDICTL_H_ */
    207