midictl.h revision 1.1.2.2 1 /* $NetBSD: midictl.h,v 1.1.2.2 2006/06/06 21:54:56 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 * A strict division of labor limits complexity. This module knows as little
69 * about the meanings of different MIDI parameters and controllers as possible
70 * to do its job: it knows which controllers are overloaded to serve as
71 * channel mode messages, and which are overloaded to provide access to the
72 * RPN and NRPN space. It knows which controllers are 14-bit, 7-bit, or 1-bit
73 * according to the table online at midi.org. (All parameters are treated as
74 * 14-bit.) It does not know or care about the specified default values;
75 * client code is expected to know those defaults for whatever controls it
76 * actually implements, and supply them when calling midictl_*read(). That
77 * avoids the need for a large table of specified values for things most
78 * clients will never read. A header file defining the official defaults could
79 * be useful for clients to include for use when calling midictl_*read, but
80 * is not part of this module. Reset All Controllers is simply handled by
81 * forgetting controllers have been written at all, so the next read by
82 * the client will return the client's supplied default.
83 *
84 * An incoming MIDI stream may refer to many controllers and parameters the
85 * client does not implement. To limit memory use, messages are ignored by
86 * default if they target a controller or parameter the client has never
87 * read. To indicate which controllers/parameters it supports, the client
88 * should simply read them when starting.
89 *
90 * Where the task is to generically process some MIDI stream without losing
91 * data, accept_any_ctl_rpn can be set to 1 in the midictl structure, and
92 * state will be kept for any incoming controller or RPN update. The separate
93 * flag accept_any_nrpn enables the same behavior for nonregistered parameters.
94 *
95 * Whenever a change is made to any value for which state is being kept, the
96 * notify function will be called with MIDICTL_CTLR, MIDICTL_RPN, or
97 * MIDICTL_NRPN, the channel, and the controller, rp, or nrp number,
98 * respectively. The controller number will never refer to the LSB of a 14-bit
99 * controller. The new /value/ is not included; if the change is of interest,
100 * the client reads the value and thereby supplies the default (which can still
101 * be needed if the update is to half of a 14-bit value). The notify function
102 * is also called, with appropriate evt codes, on receipt of channel mode
103 * messages.
104 *
105 * Reset All Controllers:
106 *
107 * The Reset All Controllers message will cause this module to forget settings
108 * for all controllers on the affected channel other than those specifically
109 * excepted by MIDI RP-015. Registered and nonregistered parameters are not
110 * affected. The notify function is then called with evt = MIDICTL_RESET.
111 *
112 * The client's response to MIDICTL_RESET should include reading all
113 * controllers it cares about, to ensure (if the accept_any_ctl_rpn flag is not
114 * set) that they will continue to be tracked. The client must also reset to
115 * defaults the following pieces of channel state that are not managed by this
116 * module, but required by RP-015 to be reset:
117 * Pitch Bend
118 * Channel Pressure
119 * Key Pressure (for all keys on channel)
120 * The client does NOT reset the current Program.
121 */
122 #include <sys/midiio.h>
123 #include <sys/stdint.h>
124
125 /*
126 * Events that may be reported via a midictl_notify function:
127 */
128 typedef enum {
129 MIDICTL_CTLR, /* key=ctlr */
130 MIDICTL_RPN, /* key=rpn */
131 MIDICTL_NRPN, /* key=nrpn */
132 MIDICTL_RESET, /* Reset All Controllers received */
133 MIDICTL_NOTES_OFF, /* All Notes Off received */
134 MIDICTL_SOUND_OFF, /* All Sound Off received */
135 MIDICTL_LOCAL, /* if (key) localIsOn; else localIsOff */
136 MIDICTL_MODE /* key=mode(1-4)? TBD unimplemented */
137 } midictl_evt;
138
139 /*
140 * midictl_notify(void *cookie, midictl_evt evt,
141 * uint_fast8_t chan, uint_fast16_t key)
142 */
143 typedef void
144 midictl_notify(void *, midictl_evt, uint_fast8_t, uint_fast16_t);
145
146 typedef struct midictl_store midictl_store;
147
148 typedef struct {
149 uint_fast8_t accept_any_ctl_rpn:1; /* 0 ==> ignore chgs for unqueried */
150 uint_fast8_t accept_any_nrpn:1; /* likewise for NRPNs */
151 uint_fast8_t base_channel; /* set >= 16 to ignore any MODE messages */
152 void *cookie; /* this value will be passed to notify */
153 midictl_notify *notify;
154 /* */
155 uint16_t rpn;
156 uint16_t nrpn;
157 midictl_store *store;
158 } midictl;
159
160 extern void
161 midictl_open(midictl *);
162
163 extern void
164 midictl_close(midictl *);
165
166 /*
167 * Called on receipt of a Control Change message. Updates the controller,
168 * RPN, or NRPN value as appropriate. When updating a controller or RPN that
169 * is defined in the spec as boolean, all values that by definition represent
170 * false are coerced to zero. Fires the callback if a value of interest has
171 * been changed.
172 * ctlval: points to the second byte of the message (therefore, to a two-
173 * byte array: controller number and value).
174 * midictl_change(midictl *mc, uint_fast8_t chan, uint8_t *ctlval);
175 */
176 extern void
177 midictl_change(midictl *, uint_fast8_t, uint8_t *);
178
179 /*
180 * Read the current value of controller ctlr for channel chan.
181 * If this is the first time querying this controller on this channel,
182 * and accept_any_ctl_rpn is false, any earlier change message for it
183 * will have been ignored, so it will be given the value dflt, which is
184 * also returned, and future change messages for it will take effect.
185 * If the controller has a two-byte value and only one has been explicitly set
186 * at the time of the first query, the effect is as if the value had been
187 * first set to dflt, then the explicitly-set byte updated.
188 * midictl_read(midictl *mc, uint_fast8_t chan,
189 * uint_fast8_t ctlr, uint_fast16_t dflt);
190 */
191 extern uint_fast16_t
192 midictl_read(midictl *, uint_fast8_t, uint_fast8_t, uint_fast16_t);
193
194 /*
195 * As for midictl_read, but for registered parameters or nonregistered
196 * parameters, respectively.
197 */
198 extern uint_fast16_t
199 midictl_rpn_read(midictl *mc, uint_fast8_t, uint_fast16_t, uint_fast16_t);
200 extern uint_fast16_t
201 midictl_nrpn_read(midictl *mc, uint_fast8_t, uint_fast16_t, uint_fast16_t);
202
203 #endif /* _SYS_DEV_MIDICTL_H_ */
204