Home | History | Annotate | Line # | Download | only in dev
midictl.c revision 1.5.2.1
      1  1.5.2.1  wrstuden /* $NetBSD: midictl.c,v 1.5.2.1 2008/09/18 04:35:01 wrstuden 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.5.2.1  wrstuden __KERNEL_RCSID(0, "$NetBSD: midictl.c,v 1.5.2.1 2008/09/18 04:35:01 wrstuden 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.5.2.1  wrstuden 			  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.5.2.1  wrstuden 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