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