midictl.c revision 1.4.4.2 1 1.4.4.2 yamt /* $NetBSD: midictl.c,v 1.4.4.2 2006/12/30 20:47:50 yamt Exp $ */
2 1.4.4.2 yamt
3 1.4.4.2 yamt /*-
4 1.4.4.2 yamt * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 1.4.4.2 yamt * All rights reserved.
6 1.4.4.2 yamt *
7 1.4.4.2 yamt * This code is derived from software contributed to The NetBSD Foundation
8 1.4.4.2 yamt * by Chapman Flack.
9 1.4.4.2 yamt *
10 1.4.4.2 yamt * Redistribution and use in source and binary forms, with or without
11 1.4.4.2 yamt * modification, are permitted provided that the following conditions
12 1.4.4.2 yamt * are met:
13 1.4.4.2 yamt * 1. Redistributions of source code must retain the above copyright
14 1.4.4.2 yamt * notice, this list of conditions and the following disclaimer.
15 1.4.4.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
16 1.4.4.2 yamt * notice, this list of conditions and the following disclaimer in the
17 1.4.4.2 yamt * documentation and/or other materials provided with the distribution.
18 1.4.4.2 yamt * 3. All advertising materials mentioning features or use of this software
19 1.4.4.2 yamt * must display the following acknowledgement:
20 1.4.4.2 yamt * This product includes software developed by the NetBSD
21 1.4.4.2 yamt * Foundation, Inc. and its contributors.
22 1.4.4.2 yamt * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.4.4.2 yamt * contributors may be used to endorse or promote products derived
24 1.4.4.2 yamt * from this software without specific prior written permission.
25 1.4.4.2 yamt *
26 1.4.4.2 yamt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.4.4.2 yamt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.4.4.2 yamt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.4.4.2 yamt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.4.4.2 yamt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.4.4.2 yamt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.4.4.2 yamt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.4.4.2 yamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.4.4.2 yamt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.4.4.2 yamt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.4.4.2 yamt * POSSIBILITY OF SUCH DAMAGE.
37 1.4.4.2 yamt */
38 1.4.4.2 yamt #include <sys/cdefs.h>
39 1.4.4.2 yamt __KERNEL_RCSID(0, "$NetBSD: midictl.c,v 1.4.4.2 2006/12/30 20:47:50 yamt Exp $");
40 1.4.4.2 yamt
41 1.4.4.2 yamt /*
42 1.4.4.2 yamt * See midictl.h for an overview of the purpose and use of this module.
43 1.4.4.2 yamt */
44 1.4.4.2 yamt
45 1.4.4.2 yamt #if defined(_KERNEL)
46 1.4.4.2 yamt #define _MIDICTL_ASSERT(x) KASSERT(x)
47 1.4.4.2 yamt #define _MIDICTL_MALLOC(s,t) malloc((s), (t), M_WAITOK)
48 1.4.4.2 yamt #define _MIDICTL_ZMALLOC(s,t) malloc((s), (t), M_WAITOK|M_ZERO)
49 1.4.4.2 yamt #define _MIDICTL_IMZMALLOC(s,t) malloc((s), (t), M_NOWAIT|M_ZERO)
50 1.4.4.2 yamt #define _MIDICTL_PANIC(...) panic(__VA_ARGS__)
51 1.4.4.2 yamt #define _MIDICTL_FREE(s,t) free((s), (t))
52 1.4.4.2 yamt #include <sys/systm.h>
53 1.4.4.2 yamt #include <sys/types.h>
54 1.4.4.2 yamt #else
55 1.4.4.2 yamt #include <assert.h>
56 1.4.4.2 yamt #include <err.h>
57 1.4.4.2 yamt #include <inttypes.h>
58 1.4.4.2 yamt #include <stdio.h>
59 1.4.4.2 yamt #include <stdlib.h>
60 1.4.4.2 yamt #define _MIDICTL_ASSERT(x) assert(x)
61 1.4.4.2 yamt #define _MIDICTL_MALLOC(s,t) malloc((s))
62 1.4.4.2 yamt #define _MIDICTL_ZMALLOC(s,t) calloc(1,(s))
63 1.4.4.2 yamt #define _MIDICTL_IMZMALLOC(s,t) calloc(1,(s))
64 1.4.4.2 yamt #define _MIDICTL_PANIC(...) errx(1,__VA_ARGS__)
65 1.4.4.2 yamt #define _MIDICTL_FREE(s,t) free((s))
66 1.4.4.2 yamt #endif
67 1.4.4.2 yamt
68 1.4.4.2 yamt #include "midictl.h"
69 1.4.4.2 yamt
70 1.4.4.2 yamt /*
71 1.4.4.2 yamt * The upper part of this file is MIDI-aware, and deals with things like
72 1.4.4.2 yamt * decoding MIDI Control Change messages, dealing with the ones that require
73 1.4.4.2 yamt * special handling as mode messages or parameter updates, and so on.
74 1.4.4.2 yamt *
75 1.4.4.2 yamt * It relies on a "store" layer (implemented in the lower part of this file)
76 1.4.4.2 yamt * that only must be able to stash away 2-, 8-, or 16-bit quantities (which
77 1.4.4.2 yamt * it may pack into larger units as it sees fit) and find them again given
78 1.4.4.2 yamt * a class, channel, and key (controller/parameter number).
79 1.4.4.2 yamt *
80 1.4.4.2 yamt * The MIDI controllers can have 1-, 7-, or 14-bit values; the parameters are
81 1.4.4.2 yamt * also 14-bit. The 14-bit values have to be set in two MIDI messages, 7 bits
82 1.4.4.2 yamt * at a time. The MIDI layer uses store-managed 2- or 8-bit slots for the
83 1.4.4.2 yamt * smaller types, and uses the free high bit to indicate that it has explicitly
84 1.4.4.2 yamt * set the value. (Because the store is allowed to pack things, it may 'find'
85 1.4.4.2 yamt * a zero entry for a value we never set, because it shares a word with a
86 1.4.4.2 yamt * different value that has been set. We know it is not a real value because
87 1.4.4.2 yamt * the high bit is clear.)
88 1.4.4.2 yamt *
89 1.4.4.2 yamt * The 14-bit values are handled similarly: 16-bit store slots are used to hold
90 1.4.4.2 yamt * them, with the two free high bits indicating independently whether the MSB
91 1.4.4.2 yamt * and the LSB have been explicitly set--as two separate MIDI messages are
92 1.4.4.2 yamt * required. If such a control is queried when only one half has been explicitly
93 1.4.4.2 yamt * set, the result is as if it had been set to the specified default value
94 1.4.4.2 yamt * before the explicit set.
95 1.4.4.2 yamt */
96 1.4.4.2 yamt
97 1.4.4.2 yamt typedef enum { CTL1, CTL7, CTL14, RPN, NRPN } class;
98 1.4.4.2 yamt
99 1.4.4.2 yamt /*
100 1.4.4.2 yamt * assert(does_not_apply(KNFNamespaceArgumentAgainstNamesInPrototypes,
101 1.4.4.2 yamt * PrototypesOfStaticFunctionsWithinNonIncludedFile));
102 1.4.4.2 yamt */
103 1.4.4.2 yamt static void reset_all_controllers(midictl *mc, uint_fast8_t chan);
104 1.4.4.2 yamt static void enter14(midictl *mc, uint_fast8_t chan, class c,
105 1.4.4.2 yamt uint_fast16_t key, _Bool islsb, uint8_t val);
106 1.4.4.2 yamt static uint_fast16_t read14(midictl *mc, uint_fast8_t chan, class c,
107 1.4.4.2 yamt uint_fast16_t key, uint_fast16_t dflt);
108 1.4.4.2 yamt static class classify(uint_fast16_t *key, _Bool *islsb);
109 1.4.4.2 yamt static midictl_notify notify_no_one;
110 1.4.4.2 yamt
111 1.4.4.2 yamt static midictl_store *store_init(void);
112 1.4.4.2 yamt static void store_done(midictl_store *s);
113 1.4.4.2 yamt static _Bool store_locate(midictl_store *s, class c,
114 1.4.4.2 yamt uint_fast8_t chan, uint_fast16_t key);
115 1.4.4.2 yamt /*
116 1.4.4.2 yamt * store_extract and store_update operate on the bucket most recently found
117 1.4.4.2 yamt * by store_locate on this store. That works because reentrancy of midictl
118 1.4.4.2 yamt * functions is limited: they /can/ be reentered during midictl_notify
119 1.4.4.2 yamt * callbacks, but not at other arbitrary times. We never call notify /during/
120 1.4.4.2 yamt * a locate/extract/update transaction.
121 1.4.4.2 yamt */
122 1.4.4.2 yamt static uint16_t store_extract(midictl_store *s, class c,
123 1.4.4.2 yamt uint_fast8_t chan, uint_fast16_t key);
124 1.4.4.2 yamt static void store_update(midictl_store *s, class c,
125 1.4.4.2 yamt uint_fast8_t chan, uint_fast16_t key, uint16_t value);
126 1.4.4.2 yamt
127 1.4.4.2 yamt #define PN_SET 0x8000 /* a parameter number has been explicitly set */
128 1.4.4.2 yamt #define C14MSET 0x8000 /* MSB of a 14-bit val has been set */
129 1.4.4.2 yamt #define C14LSET 0x4000 /* LSB of a 14-bit val has been set */
130 1.4.4.2 yamt #define C7_SET 0x80 /* a 7-bit ctl has been set */
131 1.4.4.2 yamt #define C1_SET 2 /* a 1-bit ctl has been set */
132 1.4.4.2 yamt
133 1.4.4.2 yamt #if defined(_MIDICTL_MAIN)
134 1.4.4.2 yamt #define XS(s) [MIDICTL_##s]=#s
135 1.4.4.2 yamt char const * const evt_strings[] = {
136 1.4.4.2 yamt XS(CTLR), XS(RPN), XS(NRPN), XS(RESET), XS(NOTES_OFF),
137 1.4.4.2 yamt XS(SOUND_OFF), XS(LOCAL), XS(MODE)
138 1.4.4.2 yamt };
139 1.4.4.2 yamt #undef XS
140 1.4.4.2 yamt
141 1.4.4.2 yamt void
142 1.4.4.2 yamt dbgnotify(void *cookie, midictl_evt e, uint_fast8_t chan, uint_fast16_t key)
143 1.4.4.2 yamt {
144 1.4.4.2 yamt printf("NFY %p %s chan %u #%u\n", cookie, evt_strings[e], chan, key);
145 1.4.4.2 yamt }
146 1.4.4.2 yamt
147 1.4.4.2 yamt midictl mc = {
148 1.4.4.2 yamt .accept_any_ctl_rpn = 0,
149 1.4.4.2 yamt .accept_any_nrpn = 0,
150 1.4.4.2 yamt .base_channel = 16,
151 1.4.4.2 yamt .cookie = NULL,
152 1.4.4.2 yamt .notify = dbgnotify
153 1.4.4.2 yamt };
154 1.4.4.2 yamt
155 1.4.4.2 yamt int
156 1.4.4.2 yamt main(int argc, char **argv)
157 1.4.4.2 yamt {
158 1.4.4.2 yamt int cnt, a, b, c;
159 1.4.4.2 yamt
160 1.4.4.2 yamt midictl_open(&mc);
161 1.4.4.2 yamt do {
162 1.4.4.2 yamt cnt = scanf("%i %i %i", &a, &b, &c);
163 1.4.4.2 yamt if ( 3 == cnt ) {
164 1.4.4.2 yamt midictl_change(&mc, a, (uint8_t[]){b,c});
165 1.4.4.2 yamt }
166 1.4.4.2 yamt } while ( EOF != cnt );
167 1.4.4.2 yamt midictl_close(&mc);
168 1.4.4.2 yamt return 0;
169 1.4.4.2 yamt }
170 1.4.4.2 yamt #endif /* defined(_MIDICTL_MAIN) */
171 1.4.4.2 yamt
172 1.4.4.2 yamt void
173 1.4.4.2 yamt midictl_open(midictl *mc)
174 1.4.4.2 yamt {
175 1.4.4.2 yamt if ( NULL == mc->notify )
176 1.4.4.2 yamt mc->notify = notify_no_one;
177 1.4.4.2 yamt mc->store = store_init();
178 1.4.4.2 yamt }
179 1.4.4.2 yamt
180 1.4.4.2 yamt void
181 1.4.4.2 yamt midictl_close(midictl *mc)
182 1.4.4.2 yamt {
183 1.4.4.2 yamt store_done(mc->store);
184 1.4.4.2 yamt }
185 1.4.4.2 yamt
186 1.4.4.2 yamt void
187 1.4.4.2 yamt midictl_change(midictl *mc, uint_fast8_t chan, uint8_t *ctlval)
188 1.4.4.2 yamt {
189 1.4.4.2 yamt class c;
190 1.4.4.2 yamt uint_fast16_t key, val;
191 1.4.4.2 yamt _Bool islsb, present;
192 1.4.4.2 yamt
193 1.4.4.2 yamt switch ( ctlval[0] ) {
194 1.4.4.2 yamt /*
195 1.4.4.2 yamt * Channel mode messages:
196 1.4.4.2 yamt */
197 1.4.4.2 yamt case MIDI_CTRL_OMNI_OFF:
198 1.4.4.2 yamt case MIDI_CTRL_OMNI_ON:
199 1.4.4.2 yamt case MIDI_CTRL_POLY_OFF:
200 1.4.4.2 yamt case MIDI_CTRL_POLY_ON:
201 1.4.4.2 yamt if ( chan != mc->base_channel )
202 1.4.4.2 yamt return; /* ignored - not on base channel */
203 1.4.4.2 yamt else
204 1.4.4.2 yamt return; /* XXX ignored anyway - not implemented yet */
205 1.4.4.2 yamt case MIDI_CTRL_NOTES_OFF:
206 1.4.4.2 yamt mc->notify(mc->cookie, MIDICTL_NOTES_OFF, chan, 0);
207 1.4.4.2 yamt return;
208 1.4.4.2 yamt case MIDI_CTRL_LOCAL:
209 1.4.4.2 yamt mc->notify(mc->cookie, MIDICTL_LOCAL, chan, ctlval[1]);
210 1.4.4.2 yamt return;
211 1.4.4.2 yamt case MIDI_CTRL_SOUND_OFF:
212 1.4.4.2 yamt mc->notify(mc->cookie, MIDICTL_SOUND_OFF, chan, 0);
213 1.4.4.2 yamt return;
214 1.4.4.2 yamt case MIDI_CTRL_RESET:
215 1.4.4.2 yamt reset_all_controllers(mc, chan);
216 1.4.4.2 yamt return;
217 1.4.4.2 yamt /*
218 1.4.4.2 yamt * Control changes to be handled specially:
219 1.4.4.2 yamt */
220 1.4.4.2 yamt case MIDI_CTRL_RPN_LSB:
221 1.4.4.2 yamt mc-> rpn &= ~0x7f;
222 1.4.4.2 yamt mc-> rpn |= PN_SET | (0x7f & ctlval[1]);
223 1.4.4.2 yamt mc->nrpn &= ~PN_SET;
224 1.4.4.2 yamt return;
225 1.4.4.2 yamt case MIDI_CTRL_RPN_MSB:
226 1.4.4.2 yamt mc-> rpn &= ~0x7f<<7;
227 1.4.4.2 yamt mc-> rpn |= PN_SET | (0x7f & ctlval[1])<<7;
228 1.4.4.2 yamt mc->nrpn &= ~PN_SET;
229 1.4.4.2 yamt return;
230 1.4.4.2 yamt case MIDI_CTRL_NRPN_LSB:
231 1.4.4.2 yamt mc->nrpn &= ~0x7f;
232 1.4.4.2 yamt mc->nrpn |= PN_SET | (0x7f & ctlval[1]);
233 1.4.4.2 yamt mc-> rpn &= ~PN_SET;
234 1.4.4.2 yamt return;
235 1.4.4.2 yamt case MIDI_CTRL_NRPN_MSB:
236 1.4.4.2 yamt mc->nrpn &= ~0x7f<<7;
237 1.4.4.2 yamt mc->nrpn |= PN_SET | (0x7f & ctlval[1])<<7;
238 1.4.4.2 yamt mc-> rpn &= ~PN_SET;
239 1.4.4.2 yamt return;
240 1.4.4.2 yamt case MIDI_CTRL_DATA_ENTRY_LSB:
241 1.4.4.2 yamt islsb = 1;
242 1.4.4.2 yamt goto whichparm;
243 1.4.4.2 yamt case MIDI_CTRL_DATA_ENTRY_MSB:
244 1.4.4.2 yamt islsb = 0;
245 1.4.4.2 yamt whichparm:
246 1.4.4.2 yamt if ( 0 == ( (mc->rpn ^ mc->nrpn) & PN_SET ) )
247 1.4.4.2 yamt return; /* exactly one must be current */
248 1.4.4.2 yamt if ( mc->rpn & PN_SET ) {
249 1.4.4.2 yamt key = mc->rpn;
250 1.4.4.2 yamt c = RPN;
251 1.4.4.2 yamt } else {
252 1.4.4.2 yamt key = mc->nrpn;
253 1.4.4.2 yamt c = NRPN;
254 1.4.4.2 yamt }
255 1.4.4.2 yamt key &= 0x3fff;
256 1.4.4.2 yamt if ( 0x3fff == key ) /* 'null' parm# to lock out changes */
257 1.4.4.2 yamt return;
258 1.4.4.2 yamt enter14(mc, chan, c, key, islsb, ctlval[1]);
259 1.4.4.2 yamt return;
260 1.4.4.2 yamt case MIDI_CTRL_RPN_INCREMENT: /* XXX for later - these are a PITA to */
261 1.4.4.2 yamt case MIDI_CTRL_RPN_DECREMENT: /* get right - 'right' varies by param */
262 1.4.4.2 yamt /* see http://www.midi.org/about-midi/rp18.shtml */
263 1.4.4.2 yamt return;
264 1.4.4.2 yamt }
265 1.4.4.2 yamt
266 1.4.4.2 yamt /*
267 1.4.4.2 yamt * Channel mode, RPN, and NRPN operations have been ruled out.
268 1.4.4.2 yamt * This is an ordinary control change.
269 1.4.4.2 yamt */
270 1.4.4.2 yamt
271 1.4.4.2 yamt key = ctlval[0];
272 1.4.4.2 yamt c = classify(&key, &islsb);
273 1.4.4.2 yamt
274 1.4.4.2 yamt switch ( c ) {
275 1.4.4.2 yamt case CTL14:
276 1.4.4.2 yamt enter14(mc, chan, c, key, islsb, ctlval[1]);
277 1.4.4.2 yamt return;
278 1.4.4.2 yamt case CTL7:
279 1.4.4.2 yamt present = store_locate(mc->store, c, chan, key);
280 1.4.4.2 yamt if ( !mc->accept_any_ctl_rpn ) {
281 1.4.4.2 yamt if ( !present )
282 1.4.4.2 yamt break;
283 1.4.4.2 yamt val = store_extract(mc->store, c, chan, key);
284 1.4.4.2 yamt if ( !(val&C7_SET) )
285 1.4.4.2 yamt break;
286 1.4.4.2 yamt }
287 1.4.4.2 yamt store_update(mc->store, c, chan, key,
288 1.4.4.2 yamt C7_SET | (0x7f & ctlval[1]));
289 1.4.4.2 yamt mc->notify(mc->cookie, MIDICTL_CTLR, chan, key);
290 1.4.4.2 yamt return;
291 1.4.4.2 yamt case CTL1:
292 1.4.4.2 yamt present = store_locate(mc->store, c, chan, key);
293 1.4.4.2 yamt if ( !mc->accept_any_ctl_rpn ) {
294 1.4.4.2 yamt if ( !present )
295 1.4.4.2 yamt break;
296 1.4.4.2 yamt val = store_extract(mc->store, c, chan, key);
297 1.4.4.2 yamt if ( !(val&C1_SET) )
298 1.4.4.2 yamt break;
299 1.4.4.2 yamt }
300 1.4.4.2 yamt store_update(mc->store, c, chan, key,
301 1.4.4.2 yamt C1_SET | (ctlval[1]>63));
302 1.4.4.2 yamt mc->notify(mc->cookie, MIDICTL_CTLR, chan, key);
303 1.4.4.2 yamt return;
304 1.4.4.2 yamt case RPN:
305 1.4.4.2 yamt case NRPN:
306 1.4.4.2 yamt return; /* won't see these - sop for gcc */
307 1.4.4.2 yamt }
308 1.4.4.2 yamt }
309 1.4.4.2 yamt
310 1.4.4.2 yamt uint_fast16_t
311 1.4.4.2 yamt midictl_read(midictl *mc, uint_fast8_t chan, uint_fast8_t ctlr,
312 1.4.4.2 yamt uint_fast16_t dflt)
313 1.4.4.2 yamt {
314 1.4.4.2 yamt uint_fast16_t key, val;
315 1.4.4.2 yamt class c;
316 1.4.4.2 yamt _Bool islsb, present;
317 1.4.4.2 yamt
318 1.4.4.2 yamt key = ctlr;
319 1.4.4.2 yamt c = classify(&key, &islsb);
320 1.4.4.2 yamt switch ( c ) {
321 1.4.4.2 yamt case CTL1:
322 1.4.4.2 yamt present = store_locate(mc->store, c, chan, key);
323 1.4.4.2 yamt if ( !present ||
324 1.4.4.2 yamt !(C1_SET&(val = store_extract(mc->store, c, chan, key))) ) {
325 1.4.4.2 yamt val = C1_SET | (dflt > 63); /* convert to boolean */
326 1.4.4.2 yamt store_update(mc->store, c, chan, key, val);
327 1.4.4.2 yamt }
328 1.4.4.2 yamt return (val & 1) ? 127 : 0;
329 1.4.4.2 yamt case CTL7:
330 1.4.4.2 yamt present = store_locate(mc->store, c, chan, key);
331 1.4.4.2 yamt if ( !present ||
332 1.4.4.2 yamt !(C7_SET&(val = store_extract(mc->store, c, chan, key))) ) {
333 1.4.4.2 yamt val = C7_SET | (dflt & 0x7f);
334 1.4.4.2 yamt store_update(mc->store, c, chan, key, val);
335 1.4.4.2 yamt }
336 1.4.4.2 yamt return val & 0x7f;
337 1.4.4.2 yamt case CTL14:
338 1.4.4.2 yamt _MIDICTL_ASSERT(!islsb);
339 1.4.4.2 yamt return read14(mc, chan, c, key, dflt);
340 1.4.4.2 yamt case RPN:
341 1.4.4.2 yamt case NRPN:
342 1.4.4.2 yamt break; /* sop for gcc */
343 1.4.4.2 yamt }
344 1.4.4.2 yamt return 0; /* sop for gcc */
345 1.4.4.2 yamt }
346 1.4.4.2 yamt
347 1.4.4.2 yamt uint_fast16_t
348 1.4.4.2 yamt midictl_rpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
349 1.4.4.2 yamt uint_fast16_t dflt)
350 1.4.4.2 yamt {
351 1.4.4.2 yamt return read14(mc, chan, RPN, ctlr, dflt);
352 1.4.4.2 yamt }
353 1.4.4.2 yamt
354 1.4.4.2 yamt uint_fast16_t
355 1.4.4.2 yamt midictl_nrpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
356 1.4.4.2 yamt uint_fast16_t dflt)
357 1.4.4.2 yamt {
358 1.4.4.2 yamt return read14(mc, chan, NRPN, ctlr, dflt);
359 1.4.4.2 yamt }
360 1.4.4.2 yamt
361 1.4.4.2 yamt static void
362 1.4.4.2 yamt reset_all_controllers(midictl *mc, uint_fast8_t chan)
363 1.4.4.2 yamt {
364 1.4.4.2 yamt uint_fast16_t ctlr, key;
365 1.4.4.2 yamt class c;
366 1.4.4.2 yamt _Bool islsb, present;
367 1.4.4.2 yamt
368 1.4.4.2 yamt for ( ctlr = 0 ; ; ++ ctlr ) {
369 1.4.4.2 yamt switch ( ctlr ) {
370 1.4.4.2 yamt /*
371 1.4.4.2 yamt * exempt by http://www.midi.org/about-midi/rp15.shtml:
372 1.4.4.2 yamt */
373 1.4.4.2 yamt case MIDI_CTRL_BANK_SELECT_MSB: /* 0 */
374 1.4.4.2 yamt case MIDI_CTRL_CHANNEL_VOLUME_MSB: /* 7 */
375 1.4.4.2 yamt case MIDI_CTRL_PAN_MSB: /* 10 */
376 1.4.4.2 yamt continue;
377 1.4.4.2 yamt case MIDI_CTRL_BANK_SELECT_LSB: /* 32 */
378 1.4.4.2 yamt ctlr += 31; /* skip all these LSBs anyway */
379 1.4.4.2 yamt continue;
380 1.4.4.2 yamt case MIDI_CTRL_SOUND_VARIATION: /* 70 */
381 1.4.4.2 yamt ctlr += 9; /* skip all Sound Controllers */
382 1.4.4.2 yamt continue;
383 1.4.4.2 yamt case MIDI_CTRL_EFFECT_DEPTH_1: /* 91 */
384 1.4.4.2 yamt goto loop_exit; /* nothing more gets reset */
385 1.4.4.2 yamt /*
386 1.4.4.2 yamt * exempt for our own personal reasons:
387 1.4.4.2 yamt */
388 1.4.4.2 yamt case MIDI_CTRL_DATA_ENTRY_MSB: /* 6 */
389 1.4.4.2 yamt continue; /* doesn't go to the store */
390 1.4.4.2 yamt }
391 1.4.4.2 yamt
392 1.4.4.2 yamt key = ctlr;
393 1.4.4.2 yamt c = classify(&key, &islsb);
394 1.4.4.2 yamt
395 1.4.4.2 yamt present = store_locate(mc->store, c, chan, key);
396 1.4.4.2 yamt if ( !present )
397 1.4.4.2 yamt continue;
398 1.4.4.2 yamt store_update(mc->store, c, chan, key, 0); /* no C*SET */
399 1.4.4.2 yamt }
400 1.4.4.2 yamt loop_exit:
401 1.4.4.2 yamt mc->notify(mc->cookie, MIDICTL_RESET, chan, 0);
402 1.4.4.2 yamt }
403 1.4.4.2 yamt
404 1.4.4.2 yamt static void
405 1.4.4.2 yamt enter14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
406 1.4.4.2 yamt _Bool islsb, uint8_t val)
407 1.4.4.2 yamt {
408 1.4.4.2 yamt uint16_t stval;
409 1.4.4.2 yamt _Bool present;
410 1.4.4.2 yamt
411 1.4.4.2 yamt present = store_locate(mc->store, c, chan, key);
412 1.4.4.2 yamt stval = (present) ? store_extract(mc->store, c, chan, key) : 0;
413 1.4.4.2 yamt if ( !( stval & (C14MSET|C14LSET) ) ) {
414 1.4.4.2 yamt if ( !((NRPN==c)? mc->accept_any_nrpn: mc->accept_any_ctl_rpn) )
415 1.4.4.2 yamt return;
416 1.4.4.2 yamt }
417 1.4.4.2 yamt if ( islsb )
418 1.4.4.2 yamt stval = C14LSET | val | ( stval & ~0x7f );
419 1.4.4.2 yamt else
420 1.4.4.2 yamt stval = C14MSET | ( val << 7 ) | ( stval & ~0x3f80 );
421 1.4.4.2 yamt store_update(mc->store, c, chan, key, stval);
422 1.4.4.2 yamt mc->notify(mc->cookie, CTL14 == c ? MIDICTL_CTLR
423 1.4.4.2 yamt : RPN == c ? MIDICTL_RPN
424 1.4.4.2 yamt : MIDICTL_NRPN, chan, key);
425 1.4.4.2 yamt }
426 1.4.4.2 yamt
427 1.4.4.2 yamt static uint_fast16_t
428 1.4.4.2 yamt read14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
429 1.4.4.2 yamt uint_fast16_t dflt)
430 1.4.4.2 yamt {
431 1.4.4.2 yamt uint16_t val;
432 1.4.4.2 yamt _Bool present;
433 1.4.4.2 yamt
434 1.4.4.2 yamt present = store_locate(mc->store, c, chan, key);
435 1.4.4.2 yamt if ( !present )
436 1.4.4.2 yamt goto neitherset;
437 1.4.4.2 yamt
438 1.4.4.2 yamt val = store_extract(mc->store, c, chan, key);
439 1.4.4.2 yamt switch ( val & (C14MSET|C14LSET) ) {
440 1.4.4.2 yamt case C14MSET|C14LSET:
441 1.4.4.2 yamt return val & 0x3fff;
442 1.4.4.2 yamt case C14MSET:
443 1.4.4.2 yamt val = C14LSET | (val & ~0x7f) | (dflt & 0x7f);
444 1.4.4.2 yamt break;
445 1.4.4.2 yamt case C14LSET:
446 1.4.4.2 yamt val = C14MSET | (val & ~0x3f8) | (dflt & 0x3f8);
447 1.4.4.2 yamt break;
448 1.4.4.2 yamt neitherset:
449 1.4.4.2 yamt case 0:
450 1.4.4.2 yamt val = C14MSET|C14LSET | (dflt & 0x3fff);
451 1.4.4.2 yamt }
452 1.4.4.2 yamt store_update(mc->store, c, chan, key, val);
453 1.4.4.2 yamt return val & 0x3fff;
454 1.4.4.2 yamt }
455 1.4.4.2 yamt
456 1.4.4.2 yamt /*
457 1.4.4.2 yamt * Determine the controller class; ranges based on
458 1.4.4.2 yamt * http://www.midi.org/about-midi/table3.shtml dated 1995/1999/2002
459 1.4.4.2 yamt * and viewed 2 June 2006.
460 1.4.4.2 yamt */
461 1.4.4.2 yamt static class
462 1.4.4.2 yamt classify(uint_fast16_t *key, _Bool *islsb) {
463 1.4.4.2 yamt if ( *key < 32 ) {
464 1.4.4.2 yamt *islsb = 0;
465 1.4.4.2 yamt return CTL14;
466 1.4.4.2 yamt } else if ( *key < 64 ) {
467 1.4.4.2 yamt *islsb = 1;
468 1.4.4.2 yamt *key -= 32;
469 1.4.4.2 yamt return CTL14;
470 1.4.4.2 yamt } else if ( *key < 70 ) {
471 1.4.4.2 yamt return CTL1;
472 1.4.4.2 yamt } /* 70-84 defined, 85-90 undef'd, 91-95 def'd */
473 1.4.4.2 yamt return CTL7; /* 96-101,120- handled above, 102-119 all undef'd */
474 1.4.4.2 yamt /* treat them all as CTL7 */
475 1.4.4.2 yamt }
476 1.4.4.2 yamt
477 1.4.4.2 yamt static void
478 1.4.4.2 yamt notify_no_one(void *cookie, midictl_evt evt,
479 1.4.4.2 yamt uint_fast8_t chan, uint_fast16_t k)
480 1.4.4.2 yamt {
481 1.4.4.2 yamt }
482 1.4.4.2 yamt
483 1.4.4.2 yamt #undef PN_SET
484 1.4.4.2 yamt #undef C14MSET
485 1.4.4.2 yamt #undef C14LSET
486 1.4.4.2 yamt #undef C7_SET
487 1.4.4.2 yamt #undef C1_SET
488 1.4.4.2 yamt
489 1.4.4.2 yamt /*
490 1.4.4.2 yamt * I M P L E M E N T A T I O N O F T H E S T O R E :
491 1.4.4.2 yamt *
492 1.4.4.2 yamt * MIDI defines a metric plethora of possible controllers, registered
493 1.4.4.2 yamt * parameters, and nonregistered parameters: a bit more than 32k possible words
494 1.4.4.2 yamt * to store. The saving grace is that only a handful are likely to appear in
495 1.4.4.2 yamt * typical MIDI data, and only a handful are likely implemented by or
496 1.4.4.2 yamt * interesting to a typical client. So the store implementation needs to be
497 1.4.4.2 yamt * suited to a largish but quite sparse data set.
498 1.4.4.2 yamt *
499 1.4.4.2 yamt * A double-hashed, open address table is used here. Each slot is a uint64
500 1.4.4.2 yamt * that contains the match key (control class|channel|ctl-or-PN-number) as
501 1.4.4.2 yamt * well as the values for two or more channels. CTL14s, RPNs, and NRPNs can
502 1.4.4.2 yamt * be packed two channels to the slot; CTL7s, six channels; and CTL1s get all
503 1.4.4.2 yamt * 16 channels into one slot. The channel value used in the key is the lowest
504 1.4.4.2 yamt * channel stored in the slot. Open addressing is appropriate here because the
505 1.4.4.2 yamt * link fields in a chained approach would be at least 100% overhead, and also,
506 1.4.4.2 yamt * we don't delete (MIDICTL_RESET is the only event that logically deletes
507 1.4.4.2 yamt * things, and at the moment it does not remove anything from the table, but
508 1.4.4.2 yamt * zeroes the stored value). If wanted, the deletion algorithm for open
509 1.4.4.2 yamt * addressing could be used, with shrinking/rehashing when the load factor
510 1.4.4.2 yamt * drops below 3/8 (3/4 is the current threshold for expansion), and the
511 1.4.4.2 yamt * rehashing would relieve the fills-with-DELETED problem in most cases. But
512 1.4.4.2 yamt * for now the table never shrinks while the device is open.
513 1.4.4.2 yamt */
514 1.4.4.2 yamt
515 1.4.4.2 yamt #include <sys/malloc.h>
516 1.4.4.2 yamt
517 1.4.4.2 yamt #define INITIALLGCAPACITY 6 /* initial capacity 1<<6 */
518 1.4.4.2 yamt #define IS_USED 1<<15
519 1.4.4.2 yamt #define IS_CTL7 1<<14
520 1.4.4.2 yamt
521 1.4.4.2 yamt #define CTL1SHIFT(chan) (23+((chan)<<1))
522 1.4.4.2 yamt #define CTL7SHIFT(chan) (16+((chan)<<3))
523 1.4.4.2 yamt #define CTLESHIFT(chan) (23+((chan)<<4))
524 1.4.4.2 yamt
525 1.4.4.2 yamt static uint_fast8_t const packing[] = {
526 1.4.4.2 yamt [CTL1 ] = 16, /* 16 * 2 bits ==> 32 bits, all chns in one bucket */
527 1.4.4.2 yamt [CTL7 ] = 6, /* 6 * 8 bits ==> 48 bits, 6 chns in one bucket */
528 1.4.4.2 yamt [CTL14] = 2, /* 2 *16 bits ==> 32 bits, 2 chns in one bucket */
529 1.4.4.2 yamt [RPN ] = 2,
530 1.4.4.2 yamt [NRPN ] = 2
531 1.4.4.2 yamt };
532 1.4.4.2 yamt
533 1.4.4.2 yamt struct midictl_store {
534 1.4.4.2 yamt uint64_t *table;
535 1.4.4.2 yamt uint64_t key;
536 1.4.4.2 yamt uint32_t idx;
537 1.4.4.2 yamt uint32_t lgcapacity;
538 1.4.4.2 yamt uint32_t used;
539 1.4.4.2 yamt };
540 1.4.4.2 yamt
541 1.4.4.2 yamt static uint32_t store_idx(uint32_t lgcapacity,
542 1.4.4.2 yamt uint64_t table[static 1<<lgcapacity],
543 1.4.4.2 yamt uint64_t key, uint64_t mask);
544 1.4.4.2 yamt static void store_rehash(midictl_store *s);
545 1.4.4.2 yamt
546 1.4.4.2 yamt static midictl_store *
547 1.4.4.2 yamt store_init(void)
548 1.4.4.2 yamt {
549 1.4.4.2 yamt midictl_store *s;
550 1.4.4.2 yamt
551 1.4.4.2 yamt s = _MIDICTL_MALLOC(sizeof *s, M_DEVBUF);
552 1.4.4.2 yamt s->used = 0;
553 1.4.4.2 yamt s->lgcapacity = INITIALLGCAPACITY;
554 1.4.4.2 yamt s->table = _MIDICTL_ZMALLOC(sizeof *s->table<<s->lgcapacity, M_DEVBUF);
555 1.4.4.2 yamt return s;
556 1.4.4.2 yamt }
557 1.4.4.2 yamt
558 1.4.4.2 yamt static void
559 1.4.4.2 yamt store_done(midictl_store *s)
560 1.4.4.2 yamt {
561 1.4.4.2 yamt _MIDICTL_FREE(s->table, M_DEVBUF);
562 1.4.4.2 yamt _MIDICTL_FREE(s, M_DEVBUF);
563 1.4.4.2 yamt }
564 1.4.4.2 yamt
565 1.4.4.2 yamt static _Bool
566 1.4.4.2 yamt store_locate(midictl_store *s, class c, uint_fast8_t chan, uint_fast16_t key)
567 1.4.4.2 yamt {
568 1.4.4.2 yamt uint64_t mask;
569 1.4.4.2 yamt
570 1.4.4.2 yamt if ( s->used >= 1 << s->lgcapacity )
571 1.4.4.2 yamt _MIDICTL_PANIC("%s: repeated attempts to expand table failed, "
572 1.4.4.2 yamt "plumb ran out of space", __func__);
573 1.4.4.2 yamt
574 1.4.4.2 yamt chan = packing[c] * (chan/packing[c]);
575 1.4.4.2 yamt
576 1.4.4.2 yamt if ( CTL7 == c ) { /* only 16 bits here (key's only 7) */
577 1.4.4.2 yamt s->key = IS_USED | IS_CTL7 | (chan << 7) | key;
578 1.4.4.2 yamt mask = 0xffff;
579 1.4.4.2 yamt } else { /* use 23 bits (key could be 14) */
580 1.4.4.2 yamt s->key = (c << 20) | (chan << 16) | IS_USED | key;
581 1.4.4.2 yamt mask = 0x7fffff;
582 1.4.4.2 yamt }
583 1.4.4.2 yamt
584 1.4.4.2 yamt s->idx = store_idx(s->lgcapacity, s->table, s->key, mask);
585 1.4.4.2 yamt
586 1.4.4.2 yamt if ( !(s->table[s->idx] & IS_USED) )
587 1.4.4.2 yamt return 0;
588 1.4.4.2 yamt
589 1.4.4.2 yamt return 1;
590 1.4.4.2 yamt }
591 1.4.4.2 yamt
592 1.4.4.2 yamt static uint16_t
593 1.4.4.2 yamt store_extract(midictl_store *s, class c, uint_fast8_t chan,
594 1.4.4.2 yamt uint_fast16_t key)
595 1.4.4.2 yamt {
596 1.4.4.2 yamt chan %= packing[c];
597 1.4.4.2 yamt switch ( c ) {
598 1.4.4.2 yamt case CTL1:
599 1.4.4.2 yamt return 3 & (s->table[s->idx]>>CTL1SHIFT(chan));
600 1.4.4.2 yamt case CTL7:
601 1.4.4.2 yamt return 0xff & (s->table[s->idx]>>CTL7SHIFT(chan));
602 1.4.4.2 yamt case CTL14:
603 1.4.4.2 yamt case RPN:
604 1.4.4.2 yamt case NRPN:
605 1.4.4.2 yamt break;
606 1.4.4.2 yamt }
607 1.4.4.2 yamt return 0xffff & (s->table[s->idx]>>CTLESHIFT(chan));
608 1.4.4.2 yamt }
609 1.4.4.2 yamt
610 1.4.4.2 yamt static void
611 1.4.4.2 yamt store_update(midictl_store *s, class c, uint_fast8_t chan,
612 1.4.4.2 yamt uint_fast16_t key, uint16_t value)
613 1.4.4.2 yamt {
614 1.4.4.2 yamt uint64_t orig;
615 1.4.4.2 yamt
616 1.4.4.2 yamt orig = s->table[s->idx];
617 1.4.4.2 yamt if ( !(orig & IS_USED) ) {
618 1.4.4.2 yamt orig = s->key;
619 1.4.4.2 yamt ++ s->used;
620 1.4.4.2 yamt }
621 1.4.4.2 yamt
622 1.4.4.2 yamt chan %= packing[c];
623 1.4.4.2 yamt
624 1.4.4.2 yamt switch ( c ) {
625 1.4.4.2 yamt case CTL1:
626 1.4.4.2 yamt orig &= ~(((uint64_t)3)<<CTL1SHIFT(chan));
627 1.4.4.2 yamt orig |= ((uint64_t)(3 & value)) << CTL1SHIFT(chan);
628 1.4.4.2 yamt break;
629 1.4.4.2 yamt case CTL7:
630 1.4.4.2 yamt orig &= ~(((uint64_t)0xff)<<CTL7SHIFT(chan));
631 1.4.4.2 yamt orig |= ((uint64_t)(0xff & value)) << CTL7SHIFT(chan);
632 1.4.4.2 yamt break;
633 1.4.4.2 yamt case CTL14:
634 1.4.4.2 yamt case RPN:
635 1.4.4.2 yamt case NRPN:
636 1.4.4.2 yamt orig &= ~(((uint64_t)0xffff)<<CTLESHIFT(chan));
637 1.4.4.2 yamt orig |= ((uint64_t)value) << CTLESHIFT(chan);
638 1.4.4.2 yamt break;
639 1.4.4.2 yamt }
640 1.4.4.2 yamt
641 1.4.4.2 yamt s->table[s->idx] = orig;
642 1.4.4.2 yamt if ( s->used * 4 >= 3 << s->lgcapacity )
643 1.4.4.2 yamt store_rehash(s);
644 1.4.4.2 yamt }
645 1.4.4.2 yamt
646 1.4.4.2 yamt static uint32_t
647 1.4.4.2 yamt store_idx(uint32_t lgcapacity, uint64_t table[static 1<<lgcapacity],
648 1.4.4.2 yamt uint64_t key, uint64_t mask)
649 1.4.4.2 yamt {
650 1.4.4.2 yamt uint32_t val;
651 1.4.4.2 yamt uint32_t k, h1, h2;
652 1.4.4.2 yamt int32_t idx;
653 1.4.4.2 yamt
654 1.4.4.2 yamt k = key;
655 1.4.4.2 yamt
656 1.4.4.2 yamt h1 = ((k * 0x61c88646) >> (32-lgcapacity)) & ((1<<lgcapacity) - 1);
657 1.4.4.2 yamt h2 = ((k * 0x9e3779b9) >> (32-lgcapacity)) & ((1<<lgcapacity) - 1);
658 1.4.4.2 yamt h2 |= 1;
659 1.4.4.2 yamt
660 1.4.4.2 yamt for ( idx = h1 ;; idx -= h2 ) {
661 1.4.4.2 yamt if ( idx < 0 )
662 1.4.4.2 yamt idx += 1<<lgcapacity;
663 1.4.4.2 yamt val = (uint32_t)(table[idx] & mask);
664 1.4.4.2 yamt if ( val == k )
665 1.4.4.2 yamt break;
666 1.4.4.2 yamt if ( !(val & IS_USED) )
667 1.4.4.2 yamt break;
668 1.4.4.2 yamt }
669 1.4.4.2 yamt
670 1.4.4.2 yamt return idx;
671 1.4.4.2 yamt }
672 1.4.4.2 yamt
673 1.4.4.2 yamt static void
674 1.4.4.2 yamt store_rehash(midictl_store *s)
675 1.4.4.2 yamt {
676 1.4.4.2 yamt uint64_t *newtbl, mask;
677 1.4.4.2 yamt uint32_t newlgcap, oidx, nidx;
678 1.4.4.2 yamt
679 1.4.4.2 yamt newlgcap = 1 + s->lgcapacity;
680 1.4.4.2 yamt newtbl = _MIDICTL_IMZMALLOC(sizeof *newtbl << newlgcap, M_DEVBUF);
681 1.4.4.2 yamt
682 1.4.4.2 yamt /*
683 1.4.4.2 yamt * Because IMZMALLOC can't sleep, it might have returned NULL.
684 1.4.4.2 yamt * We rehash when there is some capacity left in the table, so
685 1.4.4.2 yamt * just leave it alone; we'll get another chance on the next insertion.
686 1.4.4.2 yamt * Nothing to panic about unless the load factor really hits 1.
687 1.4.4.2 yamt */
688 1.4.4.2 yamt if ( NULL == newtbl )
689 1.4.4.2 yamt return;
690 1.4.4.2 yamt
691 1.4.4.2 yamt for ( oidx = 1<<s->lgcapacity ; oidx --> 0 ; ) {
692 1.4.4.2 yamt if ( !(s->table[oidx] & IS_USED) )
693 1.4.4.2 yamt continue;
694 1.4.4.2 yamt if ( s->table[oidx] & IS_CTL7 )
695 1.4.4.2 yamt mask = 0xffff;
696 1.4.4.2 yamt else
697 1.4.4.2 yamt mask = 0x3fffff;
698 1.4.4.2 yamt nidx = store_idx(newlgcap, newtbl, s->table[oidx]&mask, mask);
699 1.4.4.2 yamt newtbl[nidx] = s->table[oidx];
700 1.4.4.2 yamt }
701 1.4.4.2 yamt
702 1.4.4.2 yamt _MIDICTL_FREE(s->table, M_DEVBUF);
703 1.4.4.2 yamt s->table = newtbl;
704 1.4.4.2 yamt s->lgcapacity = newlgcap;
705 1.4.4.2 yamt }
706 1.4.4.2 yamt
707 1.4.4.2 yamt #if defined(_MIDICTL_MAIN)
708 1.4.4.2 yamt void
709 1.4.4.2 yamt dumpstore(void)
710 1.4.4.2 yamt {
711 1.4.4.2 yamt uint64_t val;
712 1.4.4.2 yamt uint32_t i, remain;
713 1.4.4.2 yamt midictl_store *s;
714 1.4.4.2 yamt char const *lbl;
715 1.4.4.2 yamt uint_fast16_t key;
716 1.4.4.2 yamt uint_fast8_t chan;
717 1.4.4.2 yamt class c;
718 1.4.4.2 yamt
719 1.4.4.2 yamt s = mc.store;
720 1.4.4.2 yamt
721 1.4.4.2 yamt printf("store capacity %u, used %u\n", 1<<s->lgcapacity, s->used);
722 1.4.4.2 yamt remain = s->used;
723 1.4.4.2 yamt
724 1.4.4.2 yamt for ( i = 1<<s->lgcapacity; i --> 0; ) {
725 1.4.4.2 yamt if ( !(s->table[i] & IS_USED) )
726 1.4.4.2 yamt continue;
727 1.4.4.2 yamt -- remain;
728 1.4.4.2 yamt if ( s->table[i] & IS_CTL7 ) {
729 1.4.4.2 yamt c = CTL7;
730 1.4.4.2 yamt chan = 0xf & (s->table[i]>>7);
731 1.4.4.2 yamt key = 0x7f & s->table[i];
732 1.4.4.2 yamt } else {
733 1.4.4.2 yamt c = 0x7 & (s->table[i]>>20);
734 1.4.4.2 yamt chan = 0xf & (s->table[i]>>16);
735 1.4.4.2 yamt key = 0x3fff & s->table[i];
736 1.4.4.2 yamt }
737 1.4.4.2 yamt switch ( c ) {
738 1.4.4.2 yamt case CTL1:
739 1.4.4.2 yamt lbl = "CTL1";
740 1.4.4.2 yamt val = s->table[i] >> CTL1SHIFT(0);
741 1.4.4.2 yamt break;
742 1.4.4.2 yamt case CTL7:
743 1.4.4.2 yamt lbl = "CTL7";
744 1.4.4.2 yamt val = s->table[i] >> CTL7SHIFT(0);
745 1.4.4.2 yamt break;
746 1.4.4.2 yamt case CTL14:
747 1.4.4.2 yamt lbl = "CTL14";
748 1.4.4.2 yamt val = s->table[i] >> CTLESHIFT(0);
749 1.4.4.2 yamt break;
750 1.4.4.2 yamt case RPN:
751 1.4.4.2 yamt lbl = "RPN";
752 1.4.4.2 yamt val = s->table[i] >> CTLESHIFT(0);
753 1.4.4.2 yamt break;
754 1.4.4.2 yamt case NRPN:
755 1.4.4.2 yamt lbl = "NRPN";
756 1.4.4.2 yamt val = s->table[i] >> CTLESHIFT(0);
757 1.4.4.2 yamt break;
758 1.4.4.2 yamt default:
759 1.4.4.2 yamt lbl = "???";
760 1.4.4.2 yamt chan = 0;
761 1.4.4.2 yamt key = 0;
762 1.4.4.2 yamt val = s->table[i];
763 1.4.4.2 yamt }
764 1.4.4.2 yamt printf("[%7u] %5s chans %x-%x key %5u: %"PRIx64"\n",
765 1.4.4.2 yamt i, lbl, chan, chan+packing[c]-1, key, val);
766 1.4.4.2 yamt }
767 1.4.4.2 yamt
768 1.4.4.2 yamt if ( 0 != remain )
769 1.4.4.2 yamt printf("remain == %u ??\n", remain);
770 1.4.4.2 yamt }
771 1.4.4.2 yamt #endif
772