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