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