root/dev/midisyn.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. midisyn_open
  2. midisyn_close
  3. midisyn_getinfo
  4. midisyn_ioctl
  5. midisyn_findvoice
  6. midisyn_attach
  7. midisyn_freevoice
  8. midisyn_allocvoice
  9. midisyn_output
  10. midisyn_note_to_freq
  11. midisyn_finetune

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

/* [<][>][^][v][top][bottom][index][help] */