The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/midisyn.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: midisyn.c,v 1.13 2003/12/04 13:57:30 keihan Exp $      */
    2 
    3 /*
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Lennart Augustsson (augustss@NetBSD.org).
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: midisyn.c,v 1.13 2003/12/04 13:57:30 keihan Exp $");
   41 
   42 #include <sys/param.h>
   43 #include <sys/ioctl.h>
   44 #include <sys/fcntl.h>
   45 #include <sys/vnode.h>
   46 #include <sys/select.h>
   47 #include <sys/proc.h>
   48 #include <sys/malloc.h>
   49 #include <sys/systm.h>
   50 #include <sys/syslog.h>
   51 #include <sys/kernel.h>
   52 #include <sys/audioio.h>
   53 #include <sys/midiio.h>
   54 #include <sys/device.h>
   55 
   56 #include <dev/audio_if.h>
   57 #include <dev/midi_if.h>
   58 #include <dev/midivar.h>
   59 #include <dev/midisynvar.h>
   60 
   61 #ifdef AUDIO_DEBUG
   62 #define DPRINTF(x)      if (midisyndebug) printf x
   63 #define DPRINTFN(n,x)   if (midisyndebug >= (n)) printf x
   64 int     midisyndebug = 0;
   65 #else
   66 #define DPRINTF(x)
   67 #define DPRINTFN(n,x)
   68 #endif
   69 
   70 int     midisyn_findvoice(midisyn *, int, int);
   71 void    midisyn_freevoice(midisyn *, int);
   72 int     midisyn_allocvoice(midisyn *, u_int32_t, u_int32_t);
   73 u_int32_t midisyn_note_to_freq(int);
   74 u_int32_t midisyn_finetune(u_int32_t, int, int, int);
   75 
   76 int     midisyn_open(void *, int, 
   77                      void (*iintr)(void *, int),
   78                      void (*ointr)(void *), void *arg);
   79 void    midisyn_close(void *);
   80 int     midisyn_output(void *, int);
   81 void    midisyn_getinfo(void *, struct midi_info *);
   82 int     midisyn_ioctl(void *, u_long, caddr_t, int, struct proc *);
   83 
   84 struct midi_hw_if midisyn_hw_if = {
   85         midisyn_open,
   86         midisyn_close,
   87         midisyn_output,
   88         midisyn_getinfo,
   89         midisyn_ioctl,
   90 };
   91 
   92 static const int midi_lengths[] = { 3,3,3,3,2,2,3,1 };
   93 /* Number of bytes in a MIDI command, including status */
   94 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
   95 
   96 int
   97 midisyn_open(void *addr, int flags, void (*iintr)(void *, int),
   98              void (*ointr)(void *), void *arg)
   99 {
  100         midisyn *ms = addr;
  101 
  102         DPRINTF(("midisyn_open: ms=%p ms->mets=%p\n", ms, ms->mets));
  103         if (ms->mets->open)
  104                 return (ms->mets->open(ms, flags));
  105         else
  106                 return (0);
  107 }
  108 
  109 void
  110 midisyn_close(void *addr)
  111 {
  112         midisyn *ms = addr;
  113         struct midisyn_methods *fs;
  114         int v;
  115 
  116         DPRINTF(("midisyn_close: ms=%p ms->mets=%p\n", ms, ms->mets));
  117         fs = ms->mets;
  118         for (v = 0; v < ms->nvoice; v++)
  119                 if (ms->voices[v].inuse) {
  120                         fs->noteoff(ms, v, 0, 0);
  121                         midisyn_freevoice(ms, v);
  122                 }
  123         if (fs->close)
  124                 fs->close(ms);
  125 }
  126 
  127 void
  128 midisyn_getinfo(void *addr, struct midi_info *mi)
  129 {
  130         midisyn *ms = addr;
  131 
  132         mi->name = ms->name;
  133         mi->props = 0;
  134 }
  135 
  136 int
  137 midisyn_ioctl(void *maddr, u_long cmd, caddr_t addr, int flag, struct proc *p)
  138 {
  139         midisyn *ms = maddr;
  140 
  141         if (ms->mets->ioctl)
  142                 return (ms->mets->ioctl(ms, cmd, addr, flag, p));
  143         else
  144                 return (EINVAL);
  145 }
  146 
  147 int
  148 midisyn_findvoice(midisyn *ms, int chan, int note)
  149 {
  150         u_int cn;
  151         int v;
  152 
  153         if (!(ms->flags & MS_DOALLOC))
  154                 return (chan);
  155         cn = MS_CHANNOTE(chan, note);
  156         for (v = 0; v < ms->nvoice; v++)
  157                 if (ms->voices[v].chan_note == cn && ms->voices[v].inuse)
  158                         return (v);
  159         return (-1);
  160 }
  161 
  162 void
  163 midisyn_attach(struct midi_softc *sc, midisyn *ms)
  164 {
  165         if (ms->flags & MS_DOALLOC) {
  166                 ms->voices = malloc(ms->nvoice * sizeof (struct voice), 
  167                                     M_DEVBUF, M_WAITOK|M_ZERO);
  168                 ms->seqno = 1;
  169                 if (ms->mets->allocv == 0)
  170                         ms->mets->allocv = &midisyn_allocvoice;
  171         }
  172         sc->hw_if = &midisyn_hw_if;
  173         sc->hw_hdl = ms;
  174         DPRINTF(("midisyn_attach: ms=%p\n", sc->hw_hdl));
  175 }
  176 
  177 void
  178 midisyn_freevoice(midisyn *ms, int voice)
  179 {
  180         if (!(ms->flags & MS_DOALLOC))
  181                 return;
  182         ms->voices[voice].inuse = 0;
  183 }
  184 
  185 int
  186 midisyn_allocvoice(midisyn *ms, u_int32_t chan, u_int32_t note)
  187 {
  188         int bestv, v;
  189         u_int bestseq, s;
  190 
  191         if (!(ms->flags & MS_DOALLOC))
  192                 return (chan);
  193         /* Find a free voice, or if no free voice is found the oldest. */
  194         bestv = 0;
  195         bestseq = ms->voices[0].seqno + (ms->voices[0].inuse ? 0x40000000 : 0);
  196         for (v = 1; v < ms->nvoice; v++) {
  197                 s = ms->voices[v].seqno;
  198                 if (ms->voices[v].inuse)
  199                         s += 0x40000000;
  200                 if (s < bestseq) {
  201                         bestseq = s;
  202                         bestv = v;
  203                 }
  204         }
  205         DPRINTFN(10,("midisyn_allocvoice: v=%d seq=%d cn=%x inuse=%d\n",
  206                      bestv, ms->voices[bestv].seqno, 
  207                      ms->voices[bestv].chan_note,
  208                      ms->voices[bestv].inuse));
  209 #ifdef AUDIO_DEBUG
  210         if (ms->voices[bestv].inuse)
  211                 DPRINTFN(1,("midisyn_allocvoice: steal %x\n", 
  212                             ms->voices[bestv].chan_note));
  213 #endif
  214         ms->voices[bestv].chan_note = MS_CHANNOTE(chan, note);
  215         ms->voices[bestv].seqno = ms->seqno++;
  216         ms->voices[bestv].inuse = 1;
  217         return (bestv);
  218 }
  219 
  220 int
  221 midisyn_output(void *addr, int b)
  222 {
  223         midisyn *ms = addr;
  224         u_int8_t status, chan;
  225         int voice = 0;          /* initialize to keep gcc quiet */
  226         struct midisyn_methods *fs;
  227         u_int32_t note, vel;
  228 
  229         DPRINTF(("midisyn_output: ms=%p b=0x%02x\n", ms, b));
  230         fs = ms->mets;
  231         if (ms->pos < 0) {
  232                 /* Doing SYSEX */
  233                 DPRINTF(("midisyn_output: sysex 0x%02x\n", b));
  234                 if (fs->sysex)
  235                         fs->sysex(ms, b);
  236                 if (b == MIDI_SYSEX_END)
  237                         ms->pos = 0;
  238                 return (0);
  239         }
  240         if (ms->pos == 0 && !MIDI_IS_STATUS(b))
  241                 ms->pos++;      /* repeat last status byte */
  242         ms->buf[ms->pos++] = b;
  243         status = ms->buf[0];
  244         if (ms->pos < MIDI_LENGTH(status))
  245                 return (0);
  246         /* Decode the MIDI command */
  247         chan = MIDI_GET_CHAN(status);
  248         note = ms->buf[1];
  249         if (ms->flags & MS_FREQXLATE)
  250                 note = midisyn_note_to_freq(note);
  251         vel = ms->buf[2];
  252         switch (MIDI_GET_STATUS(status)) {
  253         case MIDI_NOTEOFF:
  254                 voice = midisyn_findvoice(ms, chan, ms->buf[1]);
  255                 if (voice >= 0) {
  256                         fs->noteoff(ms, voice, note, vel);
  257                         midisyn_freevoice(ms, voice);
  258                 }
  259                 break;
  260         case MIDI_NOTEON:
  261                 voice = fs->allocv(ms, chan, ms->buf[1]);
  262                 fs->noteon(ms, voice, note, vel);
  263                 break;
  264         case MIDI_KEY_PRESSURE:
  265                 if (fs->keypres) {
  266                         voice = midisyn_findvoice(ms, voice, ms->buf[1]);
  267                         if (voice >= 0)
  268                                 fs->keypres(ms, voice, note, vel);
  269                 }
  270                 break;
  271         case MIDI_CTL_CHANGE:
  272                 if (fs->ctlchg)
  273                         fs->ctlchg(ms, chan, ms->buf[1], vel);
  274                 break;
  275         case MIDI_PGM_CHANGE:
  276                 if (fs->pgmchg)
  277                         fs->pgmchg(ms, chan, ms->buf[1]);
  278                 break;
  279         case MIDI_CHN_PRESSURE:
  280                 if (fs->chnpres) {
  281                         voice = midisyn_findvoice(ms, chan, ms->buf[1]);
  282                         if (voice >= 0)
  283                                 fs->chnpres(ms, voice, note);
  284                 }
  285                 break;
  286         case MIDI_PITCH_BEND:
  287                 if (fs->pitchb) {
  288                         voice = midisyn_findvoice(ms, chan, ms->buf[1]);
  289                         if (voice >= 0)
  290                                 fs->pitchb(ms, chan, note, vel);
  291                 }
  292                 break;
  293         case MIDI_SYSTEM_PREFIX:
  294                 if (fs->sysex)
  295                         fs->sysex(ms, status);
  296                 ms->pos = -1;
  297                 return (0);
  298         }
  299         ms->pos = 0;
  300         return (0);
  301 }
  302 
  303 /*
  304  * Convert a MIDI note to the corresponding frequency.
  305  * The frequency is scaled by 2^16.
  306  */
  307 u_int32_t
  308 midisyn_note_to_freq(int note)
  309 {
  310         int o, n, f;
  311 #define BASE_OCTAVE 5
  312         static const u_int32_t notes[] = {
  313                 17145893, 18165441, 19245614, 20390018, 21602472, 22887021,
  314                 24247954, 25689813, 27217409, 28835840, 30550508, 32367136
  315         };
  316 
  317 
  318         o = note / 12;
  319         n = note % 12;
  320 
  321         f = notes[n];
  322 
  323         if (o < BASE_OCTAVE)
  324                 f >>= (BASE_OCTAVE - o);
  325         else if (o > BASE_OCTAVE)
  326                 f <<= (o - BASE_OCTAVE);
  327         return (f);
  328 }
  329 
  330 u_int32_t
  331 midisyn_finetune(u_int32_t base_freq, int bend, int range, int vibrato_cents)
  332 {
  333         static const u_int16_t semitone_tuning[24] = 
  334         {
  335 /*   0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, 
  336 /*   8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, 
  337 /*  16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
  338         };
  339         static const u_int16_t cent_tuning[100] =
  340         {
  341 /*   0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, 
  342 /*   8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, 
  343 /*  16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134, 
  344 /*  24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181, 
  345 /*  32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228, 
  346 /*  40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275, 
  347 /*  48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323, 
  348 /*  56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371, 
  349 /*  64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419, 
  350 /*  72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467, 
  351 /*  80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515, 
  352 /*  88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, 
  353 /*  96 */ 10570, 10576, 10582, 10589
  354         };
  355         u_int32_t amount;
  356         int negative, semitones, cents, multiplier;
  357 
  358         if (range == 0)
  359                 return base_freq;
  360 
  361         if (base_freq == 0)
  362                 return base_freq;
  363 
  364         if (range >= 8192)
  365                 range = 8192;
  366 
  367         bend = bend * range / 8192;
  368         bend += vibrato_cents;
  369 
  370         if (bend == 0)
  371                 return base_freq;
  372 
  373         if (bend < 0) {
  374                 bend = -bend;
  375                 negative = 1;
  376         } else 
  377                 negative = 0;
  378 
  379         if (bend > range)
  380                 bend = range;
  381 
  382         multiplier = 1;
  383         while (bend > 2399) {
  384                 multiplier *= 4;
  385                 bend -= 2400;
  386         }
  387 
  388         semitones = bend / 100;
  389         if (semitones > 99)
  390                 semitones = 99;
  391         cents = bend % 100;
  392 
  393         amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents]
  394                 / 10000;
  395 
  396         if (negative)
  397                 return (base_freq * 10000 / amount);    /* Bend down */
  398         else
  399                 return (base_freq * amount / 10000);    /* Bend up */
  400 }
  401 

Cache object: 30441c9a122031ad3310a92a78dce8e6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.