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/ic/opl.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: opl.c,v 1.34 2008/04/28 20:23:51 martin 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  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * The OPL3 (YMF262) manual can be found at
   34  * ftp://ftp.yamahayst.com/Fax_Back_Doc/sound/YMF262.PDF
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: opl.c,v 1.34 2008/04/28 20:23:51 martin Exp $");
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/errno.h>
   43 #include <sys/ioctl.h>
   44 #include <sys/syslog.h>
   45 #include <sys/device.h>
   46 #include <sys/select.h>
   47 #include <sys/malloc.h>
   48 
   49 #include <sys/cpu.h>
   50 #include <sys/bus.h>
   51 
   52 #include <sys/audioio.h>
   53 #include <sys/midiio.h>
   54 #include <dev/audio_if.h>
   55 
   56 #include <dev/midi_if.h>
   57 #include <dev/midivar.h>
   58 #include <dev/midisynvar.h>
   59 
   60 #include <dev/ic/oplreg.h>
   61 #include <dev/ic/oplvar.h>
   62 
   63 #ifdef AUDIO_DEBUG
   64 #define DPRINTF(x)      if (opldebug) printf x
   65 #define DPRINTFN(n,x)   if (opldebug >= (n)) printf x
   66 int     opldebug = 0;
   67 #else
   68 #define DPRINTF(x)
   69 #define DPRINTFN(n,x)
   70 #endif
   71 
   72 struct real_voice {
   73         u_int8_t voice_num;
   74         u_int8_t voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
   75         u_int8_t iooffs; /* I/O port (left or right side) */
   76         u_int8_t op[4]; /* Operator offsets */
   77 };
   78 
   79 const struct opl_voice voicetab[] = {
   80 /*       No    I/O offs OP1     OP2     OP3   OP4       */
   81 /*      ---------------------------------------------   */
   82         { 0,   OPL_L,   {0x00,  0x03,   0x08, 0x0b}, NULL, 0, },
   83         { 1,   OPL_L,   {0x01,  0x04,   0x09, 0x0c}, NULL, 0, },
   84         { 2,   OPL_L,   {0x02,  0x05,   0x0a, 0x0d}, NULL, 0, },
   85 
   86         { 3,   OPL_L,   {0x08,  0x0b,   0x00, 0x00}, NULL, 0, },
   87         { 4,   OPL_L,   {0x09,  0x0c,   0x00, 0x00}, NULL, 0, },
   88         { 5,   OPL_L,   {0x0a,  0x0d,   0x00, 0x00}, NULL, 0, },
   89 
   90         { 6,   OPL_L,   {0x10,  0x13,   0x00, 0x00}, NULL, 0, },
   91         { 7,   OPL_L,   {0x11,  0x14,   0x00, 0x00}, NULL, 0, },
   92         { 8,   OPL_L,   {0x12,  0x15,   0x00, 0x00}, NULL, 0, },
   93 
   94         { 0,   OPL_R,   {0x00,  0x03,   0x08, 0x0b}, NULL, 0, },
   95         { 1,   OPL_R,   {0x01,  0x04,   0x09, 0x0c}, NULL, 0, },
   96         { 2,   OPL_R,   {0x02,  0x05,   0x0a, 0x0d}, NULL, 0, },
   97         { 3,   OPL_R,   {0x08,  0x0b,   0x00, 0x00}, NULL, 0, },
   98         { 4,   OPL_R,   {0x09,  0x0c,   0x00, 0x00}, NULL, 0, },
   99         { 5,   OPL_R,   {0x0a,  0x0d,   0x00, 0x00}, NULL, 0, },
  100 
  101         { 6,   OPL_R,   {0x10,  0x13,   0x00, 0x00}, NULL, 0, },
  102         { 7,   OPL_R,   {0x11,  0x14,   0x00, 0x00}, NULL, 0, },
  103         { 8,   OPL_R,   {0x12,  0x15,   0x00, 0x00}, NULL, 0, }
  104 };
  105 
  106 static void opl_command(struct opl_softc *, int, int, int);
  107 void opl_reset(struct opl_softc *);
  108 void opl_freq_to_fnum (int freq, int *block, int *fnum);
  109 
  110 int oplsyn_open(midisyn *ms, int);
  111 void oplsyn_close(midisyn *);
  112 void oplsyn_reset(void *);
  113 void oplsyn_attackv(midisyn *, uint_fast16_t, midipitch_t, int16_t);
  114 static void oplsyn_repitchv(midisyn *, uint_fast16_t, midipitch_t);
  115 static void oplsyn_relevelv(midisyn *, uint_fast16_t, int16_t);
  116 static void oplsyn_setv(midisyn *, uint_fast16_t, midipitch_t, int16_t, int);
  117 void oplsyn_releasev(midisyn *, uint_fast16_t, uint_fast8_t);
  118 int oplsyn_ctlnotice(midisyn *, midictl_evt, uint_fast8_t, uint_fast16_t);
  119 void oplsyn_programchange(midisyn *, uint_fast8_t, uint_fast8_t);
  120 void oplsyn_loadpatch(midisyn *, struct sysex_info *, struct uio *);
  121 static void oplsyn_panhandler(midisyn *, uint_fast8_t);
  122 
  123 void opl_set_op_reg(struct opl_softc *, int, int, int, u_char);
  124 void opl_set_ch_reg(struct opl_softc *, int, int, u_char);
  125 void opl_load_patch(struct opl_softc *, int);
  126 u_int32_t opl_get_block_fnum(midipitch_t mp);
  127 int opl_calc_vol(int regbyte, int16_t level_cB);
  128 
  129 struct midisyn_methods opl3_midi = {
  130         .open      = oplsyn_open,
  131         .close     = oplsyn_close,
  132         .attackv   = oplsyn_attackv,
  133         .repitchv  = oplsyn_repitchv,
  134         .relevelv  = oplsyn_relevelv,
  135         .releasev  = oplsyn_releasev,
  136         .pgmchg    = oplsyn_programchange,
  137         .ctlnotice = oplsyn_ctlnotice,
  138 };
  139 
  140 void
  141 opl_attach(sc)
  142         struct opl_softc *sc;
  143 {
  144         int i;
  145 
  146         if (!opl_find(sc)) {
  147                 printf("\nopl: find failed\n");
  148                 return;
  149         }
  150 
  151         sc->syn.mets = &opl3_midi;
  152         snprintf(sc->syn.name, sizeof(sc->syn.name), "%sYamaha OPL%d",
  153             sc->syn.name, sc->model);
  154         sc->syn.data = sc;
  155         sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE;
  156         midisyn_attach(&sc->mididev, &sc->syn);
  157 
  158         /* Set up voice table */
  159         for (i = 0; i < OPL3_NVOICE; i++)
  160                 sc->voices[i] = voicetab[i];
  161 
  162         opl_reset(sc);
  163 
  164         printf(": model OPL%d", sc->model);
  165 
  166         /* Set up panpot */
  167         sc->panl = OPL_VOICE_TO_LEFT;
  168         sc->panr = OPL_VOICE_TO_RIGHT;
  169         if (sc->model == OPL_3 &&
  170             device_cfdata(sc->mididev.dev)->cf_flags & OPL_FLAGS_SWAP_LR) {
  171                 sc->panl = OPL_VOICE_TO_RIGHT;
  172                 sc->panr = OPL_VOICE_TO_LEFT;
  173                 printf(": LR swapped");
  174         }
  175 
  176         printf("\n");
  177 
  178         sc->sc_mididev =
  179             midi_attach_mi(&midisyn_hw_if, &sc->syn, sc->mididev.dev);
  180 }
  181 
  182 int
  183 opl_detach(sc, flags)
  184         struct opl_softc *sc;
  185         int flags;
  186 {
  187         int rv = 0;
  188 
  189         if (sc->sc_mididev != NULL)
  190                 rv = config_detach(sc->sc_mididev, flags);
  191 
  192         return(rv);
  193 }
  194 
  195 static void
  196 opl_command(sc, offs, addr, data)
  197         struct opl_softc *sc;
  198         int offs;
  199         int addr, data;
  200 {
  201         DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n",
  202                      sc, offs, addr, data));
  203         offs += sc->offs;
  204         bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr);
  205         if (sc->model == OPL_2)
  206                 delay(10);
  207         else
  208                 delay(6);
  209         bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data);
  210         if (sc->model == OPL_2)
  211                 delay(30);
  212         else
  213                 delay(6);
  214 }
  215 
  216 int
  217 opl_match(bus_space_tag_t iot, bus_space_handle_t ioh, int offs)
  218 {
  219         struct opl_softc *sc;
  220         int rv;
  221 
  222         sc = malloc(sizeof(*sc), M_TEMP, M_WAITOK|M_ZERO);
  223         sc->iot = iot;
  224         sc->ioh = ioh;
  225         sc->offs = offs;
  226         rv = opl_find(sc);
  227         free(sc, M_TEMP);
  228         return rv;
  229 }
  230 
  231 int
  232 opl_find(sc)
  233         struct opl_softc *sc;
  234 {
  235         u_int8_t status1, status2;
  236 
  237         DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh));
  238         sc->model = OPL_2;      /* worst case assumption */
  239 
  240         /* Reset timers 1 and 2 */
  241         opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
  242                     OPL_TIMER1_MASK | OPL_TIMER2_MASK);
  243         /* Reset the IRQ of the FM chip */
  244         opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
  245 
  246         /* get status bits */
  247         status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
  248 
  249         opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */
  250         opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */
  251                     OPL_TIMER1_START | OPL_TIMER2_MASK);
  252         delay(1000);            /* wait for timer to expire */
  253 
  254         /* get status bits again */
  255         status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
  256 
  257         opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
  258                     OPL_TIMER1_MASK | OPL_TIMER2_MASK);
  259         opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
  260 
  261         DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2));
  262 
  263         if ((status1 & OPL_STATUS_MASK) != 0 ||
  264             (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1))
  265                 return (0);
  266 
  267         switch(status1) {
  268         case 0x00:
  269         case 0x0f:
  270                 sc->model = OPL_3;
  271                 break;
  272         case 0x06:
  273                 sc->model = OPL_2;
  274                 break;
  275         default:
  276                 return (0);
  277         }
  278 
  279         DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n",
  280                     sc->model, (int)sc->ioh));
  281         return (1);
  282 }
  283 
  284 /*
  285  * idea: opl_command does a lot of busywaiting, and the driver typically sets
  286  *       a lot of registers each time a voice-attack happens. some kind of
  287  *       caching to remember what was last written to each register could save
  288  *       a lot of cpu. It would have to be smart enough not to interfere with
  289  *       any necessary sequences of register access expected by the hardware...
  290  */
  291 void
  292 opl_set_op_reg(sc, base, voice, op, value)
  293         struct opl_softc *sc;
  294         int base;
  295         int voice;
  296         int op;
  297         u_char value;
  298 {
  299         struct opl_voice *v = &sc->voices[voice];
  300         opl_command(sc, v->iooffs, base + v->op[op], value);
  301 }
  302 
  303 void
  304 opl_set_ch_reg(sc, base, voice, value)
  305         struct opl_softc *sc;
  306         int base;
  307         int voice;
  308         u_char value;
  309 {
  310         struct opl_voice *v = &sc->voices[voice];
  311         opl_command(sc, v->iooffs, base + v->voiceno, value);
  312 }
  313 
  314 
  315 void
  316 opl_load_patch(sc, v)
  317         struct opl_softc *sc;
  318         int v;
  319 {
  320         const struct opl_operators *p = sc->voices[v].patch;
  321 
  322         opl_set_op_reg(sc, OPL_AM_VIB,          v, 0, p->ops[OO_CHARS+0]);
  323         opl_set_op_reg(sc, OPL_AM_VIB,          v, 1, p->ops[OO_CHARS+1]);
  324         opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 0, p->ops[OO_KSL_LEV+0]);
  325         opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 1, p->ops[OO_KSL_LEV+1]);
  326         opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 0, p->ops[OO_ATT_DEC+0]);
  327         opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 1, p->ops[OO_ATT_DEC+1]);
  328         opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]);
  329         opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]);
  330         opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 0, p->ops[OO_WAV_SEL+0]);
  331         opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 1, p->ops[OO_WAV_SEL+1]);
  332         opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]);
  333 }
  334 
  335 uint32_t
  336 opl_get_block_fnum(midipitch_t mp)
  337 {
  338         midihz18_t hz18;
  339         uint32_t block;
  340         uint32_t f_num;
  341         
  342         /*
  343          * We can get to about note 30 before needing to switch from block 0.
  344          * Thereafter, switch block every octave; that will keep f_num in the
  345          * upper end of its range, making the most bits available for
  346          * resolution.
  347          */
  348         block = ( mp - MIDIPITCH_FROM_KEY(19) ) / MIDIPITCH_OCTAVE;
  349         if ( block > 7 )        /* subtract wrapped */
  350                 block = 0;
  351         /*
  352          * Could subtract block*MIDIPITCH_OCTAVE here, or >>block later. Later.
  353          */
  354         
  355         hz18 = MIDIPITCH_TO_HZ18(mp);
  356         hz18 >>= block;
  357         
  358         /*
  359          * The formula in the manual is f_num = ((hz<<19)/fs)>>(block-1) (though
  360          * block==0 implies >>-1 which is a C unspecified result). As we already
  361          * have hz<<18 and I omitted the -1 when shifting above, what's left to
  362          * do now is multiply by 4 and divide by fs, the sampling frequency of
  363          * the chip. fs is the master clock frequency fM / 288, fM is 14.32 MHz
  364          * so fs is a goofy number around 49.7kHz. The 5th convergent of the
  365          * continued fraction matches 4/fs to 9+ significant figures. Doing the
  366          * shift first (above) ensures there's room in hz18 to multiply by 9.
  367          */
  368         
  369         f_num = (9 * hz18) / 111875; 
  370         return ((block << 10) | f_num);
  371 }
  372 
  373 
  374 void
  375 opl_reset(sc)
  376         struct opl_softc *sc;
  377 {
  378         int i;
  379 
  380         for (i = 1; i <= OPL_MAXREG; i++)
  381                 opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
  382 
  383         opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT);
  384         opl_command(sc, OPL_L, OPL_PERCUSSION, 0);
  385         if (sc->model == OPL_3) {
  386                 opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE);
  387                 opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION);
  388         }
  389 
  390         for (i = 0; i < MIDI_MAX_CHANS; i++)
  391                 sc->pan[i] = OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT;
  392 }
  393 
  394 int
  395 oplsyn_open(midisyn *ms, int flags)
  396 {
  397         struct opl_softc *sc = ms->data;
  398 
  399         DPRINTFN(2, ("oplsyn_open: %d\n", flags));
  400 
  401 #ifndef AUDIO_NO_POWER_CTL
  402         if (sc->powerctl)
  403                 sc->powerctl(sc->powerarg, 1);
  404 #endif
  405         opl_reset(ms->data);
  406         if (sc->spkrctl)
  407                 sc->spkrctl(sc->spkrarg, 1);
  408         return (0);
  409 }
  410 
  411 void
  412 oplsyn_close(ms)
  413         midisyn *ms;
  414 {
  415         struct opl_softc *sc = ms->data;
  416 
  417         DPRINTFN(2, ("oplsyn_close:\n"));
  418 
  419         /*opl_reset(ms->data);*/
  420         if (sc->spkrctl)
  421                 sc->spkrctl(sc->spkrarg, 0);
  422 #ifndef AUDIO_NO_POWER_CTL
  423         if (sc->powerctl)
  424                 sc->powerctl(sc->powerarg, 0);
  425 #endif
  426 }
  427 
  428 #if 0
  429 void
  430 oplsyn_getinfo(addr, sd)
  431         void *addr;
  432         struct synth_dev *sd;
  433 {
  434         struct opl_softc *sc = addr;
  435 
  436         sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3";
  437         sd->type = SYNTH_TYPE_FM;
  438         sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB
  439                 : SYNTH_SUB_FM_TYPE_OPL3;
  440         sd->capabilities = 0;
  441 }
  442 #endif
  443 
  444 void
  445 oplsyn_reset(addr)
  446         void *addr;
  447 {
  448         struct opl_softc *sc = addr;
  449         DPRINTFN(3, ("oplsyn_reset:\n"));
  450         opl_reset(sc);
  451 }
  452 
  453 int
  454 opl_calc_vol(int regbyte, int16_t level_cB)
  455 {
  456         int level = regbyte & OPL_TOTAL_LEVEL_MASK;
  457         
  458         /*
  459          * level is a six-bit attenuation, from 0 (full output)
  460          * to -48dB (but without the minus sign) in steps of .75 dB.
  461          * We'll just add level_cB, after scaling it because it's
  462          * in centibels instead and has the customary minus sign.
  463          */
  464 
  465         level += ( -4 * level_cB ) / 30;
  466 
  467         if (level > OPL_TOTAL_LEVEL_MASK)
  468                 level = OPL_TOTAL_LEVEL_MASK;
  469         if (level < 0)
  470                 level = 0;
  471 
  472         return level & OPL_TOTAL_LEVEL_MASK;
  473 }
  474 
  475 #define OPLACT_ARTICULATE 1
  476 #define OPLACT_PITCH      2
  477 #define OPLACT_LEVEL      4
  478 
  479 void
  480 oplsyn_attackv(midisyn *ms,
  481                uint_fast16_t voice, midipitch_t mp, int16_t level_cB)
  482 {
  483         oplsyn_setv(ms, voice, mp, level_cB,
  484                     OPLACT_ARTICULATE | OPLACT_PITCH | OPLACT_LEVEL);
  485 }
  486 
  487 static void
  488 oplsyn_repitchv(midisyn *ms, uint_fast16_t voice, midipitch_t mp)
  489 {
  490         oplsyn_setv(ms, voice, mp, 0, OPLACT_PITCH);
  491 }
  492 
  493 static void
  494 oplsyn_relevelv(midisyn *ms, uint_fast16_t voice, int16_t level_cB)
  495 {
  496         oplsyn_setv(ms, voice, 0, level_cB, OPLACT_LEVEL);
  497 }
  498 
  499 static void
  500 oplsyn_setv(midisyn *ms,
  501             uint_fast16_t voice, midipitch_t mp, int16_t level_cB, int act)
  502 {
  503         struct opl_softc *sc = ms->data;
  504         struct opl_voice *v;
  505         const struct opl_operators *p;
  506         u_int32_t block_fnum;
  507         int mult;
  508         int c_mult, m_mult;
  509         u_int32_t chan;
  510         u_int8_t chars0, chars1, ksl0, ksl1, fbc;
  511         u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
  512         u_int8_t vol0, vol1;
  513 
  514         DPRINTFN(3, ("%s: %p %d %u %d\n", __func__, sc, voice,
  515                      mp, level_cB));
  516 
  517 #ifdef DIAGNOSTIC
  518         if (voice >= sc->syn.nvoice) {
  519                 printf("%s: bad voice %d\n", __func__, voice);
  520                 return;
  521         }
  522 #endif
  523         v = &sc->voices[voice];
  524 
  525         if ( act & OPLACT_ARTICULATE ) {
  526                 /* Turn off old note */
  527                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, 0xff);
  528                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, 0xff);
  529                 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    0);
  530 
  531                 chan = MS_GETCHAN(&ms->voices[voice]);
  532                 p = &opl2_instrs[ms->pgms[chan]];
  533                 v->patch = p;
  534                 opl_load_patch(sc, voice);
  535 
  536                 fbc = p->ops[OO_FB_CONN];
  537                 if (sc->model == OPL_3) {
  538                         fbc &= ~OPL_STEREO_BITS;
  539                         fbc |= sc->pan[chan];
  540                 }
  541                 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc);
  542         } else
  543                 p = v->patch;
  544 
  545         if ( act & OPLACT_LEVEL ) {
  546                 /* 2 voice */
  547                 ksl0 = p->ops[OO_KSL_LEV+0];
  548                 ksl1 = p->ops[OO_KSL_LEV+1];
  549                 if (p->ops[OO_FB_CONN] & 0x01) {
  550                         vol0 = opl_calc_vol(ksl0, level_cB);
  551                         vol1 = opl_calc_vol(ksl1, level_cB);
  552                 } else {
  553                         vol0 = ksl0;
  554                         vol1 = opl_calc_vol(ksl1, level_cB);
  555                 }
  556                 r40m = (ksl0 & OPL_KSL_MASK) | vol0;
  557                 r40c = (ksl1 & OPL_KSL_MASK) | vol1;
  558 
  559                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, r40m);
  560                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, r40c);
  561         }
  562         
  563         if ( act & OPLACT_PITCH ) {
  564                 mult = 1;
  565                 if ( mp > MIDIPITCH_FROM_KEY(114) ) { /* out of mult 1 range */
  566                         mult = 4;       /* will cover remaining MIDI range */
  567                         mp -= 2*MIDIPITCH_OCTAVE;
  568                 }
  569 
  570                 block_fnum = opl_get_block_fnum(mp);
  571 
  572                 chars0 = p->ops[OO_CHARS+0];
  573                 chars1 = p->ops[OO_CHARS+1];
  574                 m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult;
  575                 c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult;
  576 
  577                 if ( 4 == mult ) {
  578                         if ( 0 == m_mult )  /* The OPL uses 0 to represent .5 */
  579                                 m_mult = 2; /* but of course 0*mult above did */
  580                         if ( 0 == c_mult )  /* not DTRT */
  581                                 c_mult = 2;
  582                 }
  583 
  584                 if ((m_mult > 15) || (c_mult > 15)) {
  585                         printf("%s: frequency out of range %u (mult %d)\n",
  586                                __func__, mp, mult);
  587                         return;
  588                 }
  589                 r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult;
  590                 r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult;
  591 
  592                 rA0  = block_fnum & 0xFF;
  593                 rB0  = (block_fnum >> 8) | OPL_KEYON_BIT;
  594 
  595                 v->rB0 = rB0;
  596 
  597                 opl_set_op_reg(sc, OPL_AM_VIB,      voice, 0, r20m);
  598                 opl_set_op_reg(sc, OPL_AM_VIB,      voice, 1, r20c);
  599 
  600                 opl_set_ch_reg(sc, OPL_FNUM_LOW,    voice,    rA0);
  601                 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    rB0);
  602         }
  603 }
  604 
  605 void
  606 oplsyn_releasev(midisyn *ms, uint_fast16_t voice, uint_fast8_t vel)
  607 {
  608         struct opl_softc *sc = ms->data;
  609         struct opl_voice *v;
  610 
  611         DPRINTFN(1, ("%s: %p %d\n", __func__, sc, voice));
  612 
  613 #ifdef DIAGNOSTIC
  614         if (voice >= sc->syn.nvoice) {
  615                 printf("oplsyn_noteoff: bad voice %d\n", voice);
  616                 return;
  617         }
  618 #endif
  619         v = &sc->voices[voice];
  620         opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT);
  621 }
  622 
  623 int
  624 oplsyn_ctlnotice(midisyn *ms,
  625                  midictl_evt evt, uint_fast8_t chan, uint_fast16_t key)
  626 {
  627 
  628         DPRINTFN(1, ("%s: %p %d\n", __func__, ms->data, chan));
  629         
  630         switch (evt) {
  631         case MIDICTL_RESET:
  632                 oplsyn_panhandler(ms, chan);
  633                 return 1;
  634         
  635         case MIDICTL_CTLR:
  636                 switch (key) {
  637                 case MIDI_CTRL_PAN_MSB:
  638                         oplsyn_panhandler(ms, chan);
  639                         return 1;
  640                 }
  641                 return 0;
  642         default:
  643                 return 0;
  644         }
  645 }
  646 
  647 /* PROGRAM CHANGE midi event: */
  648 void
  649 oplsyn_programchange(midisyn *ms, uint_fast8_t chan, uint_fast8_t prog)
  650 {
  651         /* sanity checks */
  652         if (chan >= MIDI_MAX_CHANS)
  653                 return;
  654 
  655         ms->pgms[chan] = prog;
  656 }
  657 
  658 void
  659 oplsyn_loadpatch(midisyn *ms, struct sysex_info *sysex,
  660     struct uio *uio)
  661 {
  662 #if 0
  663         struct opl_softc *sc = ms->data;
  664         struct sbi_instrument ins;
  665 
  666         DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc));
  667 
  668         memcpy(&ins, sysex, sizeof *sysex);
  669         if (uio->uio_resid >= sizeof ins - sizeof *sysex)
  670                 return EINVAL;
  671         uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio);
  672         /* XXX */
  673 #endif
  674 }
  675 
  676 static void
  677 oplsyn_panhandler(midisyn *ms, uint_fast8_t chan)
  678 {
  679         struct opl_softc *sc = ms->data;
  680         uint_fast16_t setting;
  681         
  682         setting = midictl_read(&ms->ctl, chan, MIDI_CTRL_PAN_MSB, 8192);
  683         setting >>= 7; /* we used to treat it as MSB only */
  684         sc->pan[chan] =
  685             (setting <= OPL_MIDI_CENTER_MAX ? sc->panl : 0) |
  686             (setting >= OPL_MIDI_CENTER_MIN ? sc->panr : 0);
  687 }

Cache object: 57e9f31302e4d5f9322ec67895602323


[ 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.