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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: opl.c,v 1.43 2019/05/08 13:40:18 isaki Exp $   */
    2 
    3 /*
    4  * Copyright (c) 1998, 2008 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), and by Andrew Doran.
    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.43 2019/05/08 13:40:18 isaki 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/kmem.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/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(struct opl_softc *sc)
  142 {
  143         int i;
  144 
  145         KASSERT(sc->dev != NULL);
  146         KASSERT(sc->lock != NULL);
  147 
  148         mutex_enter(sc->lock);
  149         i = opl_find(sc);
  150         mutex_exit(sc->lock);
  151         if (i == 0) {
  152                 aprint_error("\nopl: find failed\n");
  153                 return;
  154         }
  155 
  156         mutex_enter(sc->lock);
  157         opl_reset(sc);
  158         mutex_exit(sc->lock);
  159 
  160         sc->syn.mets = &opl3_midi;
  161         size_t len = strlen(sc->syn.name);
  162         snprintf(sc->syn.name + len, sizeof(sc->syn.name) - len,
  163             "Yamaha OPL%d", sc->model);
  164         sc->syn.data = sc;
  165         sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE;
  166         sc->syn.lock = sc->lock;
  167         midisyn_init(&sc->syn);
  168 
  169         /* Set up voice table */
  170         for (i = 0; i < OPL3_NVOICE; i++)
  171                 sc->voices[i] = voicetab[i];
  172 
  173         aprint_normal(": model OPL%d", sc->model);
  174 
  175         /* Set up panpot */
  176         sc->panl = OPL_VOICE_TO_LEFT;
  177         sc->panr = OPL_VOICE_TO_RIGHT;
  178         if (sc->model == OPL_3 &&
  179             device_cfdata(sc->dev)->cf_flags & OPL_FLAGS_SWAP_LR) {
  180                 sc->panl = OPL_VOICE_TO_RIGHT;
  181                 sc->panr = OPL_VOICE_TO_LEFT;
  182                 aprint_normal(": LR swapped");
  183         }
  184 
  185         aprint_normal("\n");
  186         aprint_naive("\n");
  187 
  188         sc->sc_mididev =
  189             midi_attach_mi(&midisyn_hw_if, &sc->syn, sc->dev);
  190 }
  191 
  192 int
  193 opl_detach(struct opl_softc *sc, int flags)
  194 {
  195         int rv = 0;
  196 
  197         if (sc->sc_mididev != NULL)
  198                 rv = config_detach(sc->sc_mididev, flags);
  199 
  200         return(rv);
  201 }
  202 
  203 static void
  204 opl_command(struct opl_softc *sc, int offs, int addr, int data)
  205 {
  206         DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n",
  207                      sc, offs, addr, data));
  208 
  209         KASSERT(!sc->lock || mutex_owned(sc->lock));
  210 
  211         offs += sc->offs;
  212         bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr);
  213         if (sc->model == OPL_2)
  214                 delay(10);
  215         else
  216                 delay(6);
  217         bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data);
  218         if (sc->model == OPL_2)
  219                 delay(30);
  220         else
  221                 delay(6);
  222 }
  223 
  224 int
  225 opl_match(bus_space_tag_t iot, bus_space_handle_t ioh, int offs)
  226 {
  227         struct opl_softc *sc;
  228         int rv;
  229 
  230         sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
  231         sc->iot = iot;
  232         sc->ioh = ioh;
  233         sc->offs = offs;
  234         rv = opl_find(sc);
  235         kmem_free(sc, sizeof(*sc));
  236         return rv;
  237 }
  238 
  239 int
  240 opl_find(struct opl_softc *sc)
  241 {
  242         u_int8_t status1, status2;
  243 
  244         DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh));
  245         sc->model = OPL_2;      /* worst case assumption */
  246 
  247         /* Reset timers 1 and 2 */
  248         opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
  249                     OPL_TIMER1_MASK | OPL_TIMER2_MASK);
  250         /* Reset the IRQ of the FM chip */
  251         opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
  252 
  253         /* get status bits */
  254         status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
  255 
  256         opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */
  257         opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */
  258                     OPL_TIMER1_START | OPL_TIMER2_MASK);
  259         delay(1000);            /* wait for timer to expire */
  260 
  261         /* get status bits again */
  262         status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
  263 
  264         opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
  265                     OPL_TIMER1_MASK | OPL_TIMER2_MASK);
  266         opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
  267 
  268         DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2));
  269 
  270         if ((status1 & OPL_STATUS_MASK) != 0 ||
  271             (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1))
  272                 return (0);
  273 
  274         switch(status1) {
  275         case 0x00:
  276         case 0x0f:
  277                 sc->model = OPL_3;
  278                 break;
  279         case 0x06:
  280                 sc->model = OPL_2;
  281                 break;
  282         default:
  283                 return (0);
  284         }
  285 
  286         DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n",
  287                     sc->model, (int)sc->ioh));
  288         return (1);
  289 }
  290 
  291 /*
  292  * idea: opl_command does a lot of busywaiting, and the driver typically sets
  293  *       a lot of registers each time a voice-attack happens. some kind of
  294  *       caching to remember what was last written to each register could save
  295  *       a lot of cpu. It would have to be smart enough not to interfere with
  296  *       any necessary sequences of register access expected by the hardware...
  297  */
  298 void
  299 opl_set_op_reg(struct opl_softc *sc, int base, int voice, int op, u_char value)
  300 {
  301         struct opl_voice *v = &sc->voices[voice];
  302 
  303         KASSERT(mutex_owned(sc->lock));
  304 
  305         opl_command(sc, v->iooffs, base + v->op[op], value);
  306 }
  307 
  308 void
  309 opl_set_ch_reg(struct opl_softc *sc, int base, int voice, u_char value)
  310 {
  311         struct opl_voice *v = &sc->voices[voice];
  312 
  313         KASSERT(mutex_owned(sc->lock));
  314 
  315         opl_command(sc, v->iooffs, base + v->voiceno, value);
  316 }
  317 
  318 
  319 void
  320 opl_load_patch(struct opl_softc *sc, int v)
  321 {
  322         const struct opl_operators *p = sc->voices[v].patch;
  323 
  324         KASSERT(mutex_owned(sc->lock));
  325 
  326         opl_set_op_reg(sc, OPL_AM_VIB,          v, 0, p->ops[OO_CHARS+0]);
  327         opl_set_op_reg(sc, OPL_AM_VIB,          v, 1, p->ops[OO_CHARS+1]);
  328         opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 0, p->ops[OO_KSL_LEV+0]);
  329         opl_set_op_reg(sc, OPL_KSL_LEVEL,       v, 1, p->ops[OO_KSL_LEV+1]);
  330         opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 0, p->ops[OO_ATT_DEC+0]);
  331         opl_set_op_reg(sc, OPL_ATTACK_DECAY,    v, 1, p->ops[OO_ATT_DEC+1]);
  332         opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]);
  333         opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]);
  334         opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 0, p->ops[OO_WAV_SEL+0]);
  335         opl_set_op_reg(sc, OPL_WAVE_SELECT,     v, 1, p->ops[OO_WAV_SEL+1]);
  336         opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]);
  337 }
  338 
  339 uint32_t
  340 opl_get_block_fnum(midipitch_t mp)
  341 {
  342         midihz18_t hz18;
  343         uint32_t block;
  344         uint32_t f_num;
  345 
  346         /*
  347          * We can get to about note 30 before needing to switch from block 0.
  348          * Thereafter, switch block every octave; that will keep f_num in the
  349          * upper end of its range, making the most bits available for
  350          * resolution.
  351          */
  352         block = ( mp - MIDIPITCH_FROM_KEY(19) ) / MIDIPITCH_OCTAVE;
  353         if ( block > 7 )        /* subtract wrapped */
  354                 block = 0;
  355         /*
  356          * Could subtract block*MIDIPITCH_OCTAVE here, or >>block later. Later.
  357          */
  358 
  359         hz18 = MIDIPITCH_TO_HZ18(mp);
  360         hz18 >>= block;
  361 
  362         /*
  363          * The formula in the manual is f_num = ((hz<<19)/fs)>>(block-1) (though
  364          * block==0 implies >>-1 which is a C unspecified result). As we already
  365          * have hz<<18 and I omitted the -1 when shifting above, what's left to
  366          * do now is multiply by 4 and divide by fs, the sampling frequency of
  367          * the chip. fs is the master clock frequency fM / 288, fM is 14.32 MHz
  368          * so fs is a goofy number around 49.7kHz. The 5th convergent of the
  369          * continued fraction matches 4/fs to 9+ significant figures. Doing the
  370          * shift first (above) ensures there's room in hz18 to multiply by 9.
  371          */
  372 
  373         f_num = (9 * hz18) / 111875;
  374         return ((block << 10) | f_num);
  375 }
  376 
  377 
  378 void
  379 opl_reset(struct opl_softc *sc)
  380 {
  381         int i;
  382 
  383         KASSERT(mutex_owned(sc->lock));
  384 
  385         for (i = 1; i <= OPL_MAXREG; i++)
  386                 opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
  387 
  388         opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT);
  389         opl_command(sc, OPL_L, OPL_PERCUSSION, 0);
  390         if (sc->model == OPL_3) {
  391                 opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE);
  392                 opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION);
  393         }
  394 
  395         for (i = 0; i < MIDI_MAX_CHANS; i++)
  396                 sc->pan[i] = OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT;
  397 }
  398 
  399 int
  400 oplsyn_open(midisyn *ms, int flags)
  401 {
  402         struct opl_softc *sc = ms->data;
  403 
  404         KASSERT(mutex_owned(sc->lock));
  405 
  406         DPRINTFN(2, ("oplsyn_open: %d\n", flags));
  407 
  408 #ifndef AUDIO_NO_POWER_CTL
  409         if (sc->powerctl)
  410                 sc->powerctl(sc->powerarg, 1);
  411 #endif
  412         opl_reset(ms->data);
  413         if (sc->spkrctl)
  414                 sc->spkrctl(sc->spkrarg, 1);
  415         return (0);
  416 }
  417 
  418 void
  419 oplsyn_close(midisyn *ms)
  420 {
  421         struct opl_softc *sc = ms->data;
  422 
  423         DPRINTFN(2, ("oplsyn_close:\n"));
  424 
  425         KASSERT(mutex_owned(sc->lock));
  426 
  427         /*opl_reset(ms->data);*/
  428         if (sc->spkrctl)
  429                 sc->spkrctl(sc->spkrarg, 0);
  430 #ifndef AUDIO_NO_POWER_CTL
  431         if (sc->powerctl)
  432                 sc->powerctl(sc->powerarg, 0);
  433 #endif
  434 }
  435 
  436 #if 0
  437 void
  438 oplsyn_getinfo(void *addr, struct synth_dev *sd)
  439 {
  440         struct opl_softc *sc = addr;
  441 
  442         sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3";
  443         sd->type = SYNTH_TYPE_FM;
  444         sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB
  445                 : SYNTH_SUB_FM_TYPE_OPL3;
  446         sd->capabilities = 0;
  447 }
  448 #endif
  449 
  450 void
  451 oplsyn_reset(void *addr)
  452 {
  453         struct opl_softc *sc = addr;
  454 
  455         KASSERT(mutex_owned(sc->lock));
  456 
  457         DPRINTFN(3, ("oplsyn_reset:\n"));
  458         opl_reset(sc);
  459 }
  460 
  461 int
  462 opl_calc_vol(int regbyte, int16_t level_cB)
  463 {
  464         int level = regbyte & OPL_TOTAL_LEVEL_MASK;
  465 
  466         /*
  467          * level is a six-bit attenuation, from 0 (full output)
  468          * to -48dB (but without the minus sign) in steps of .75 dB.
  469          * We'll just add level_cB, after scaling it because it's
  470          * in centibels instead and has the customary minus sign.
  471          */
  472 
  473         level += ( -4 * level_cB ) / 30;
  474 
  475         if (level > OPL_TOTAL_LEVEL_MASK)
  476                 level = OPL_TOTAL_LEVEL_MASK;
  477         if (level < 0)
  478                 level = 0;
  479 
  480         return level & OPL_TOTAL_LEVEL_MASK;
  481 }
  482 
  483 #define OPLACT_ARTICULATE 1
  484 #define OPLACT_PITCH      2
  485 #define OPLACT_LEVEL      4
  486 
  487 void
  488 oplsyn_attackv(midisyn *ms,
  489                uint_fast16_t voice, midipitch_t mp, int16_t level_cB)
  490 {
  491         oplsyn_setv(ms, voice, mp, level_cB,
  492                     OPLACT_ARTICULATE | OPLACT_PITCH | OPLACT_LEVEL);
  493 }
  494 
  495 static void
  496 oplsyn_repitchv(midisyn *ms, uint_fast16_t voice, midipitch_t mp)
  497 {
  498         oplsyn_setv(ms, voice, mp, 0, OPLACT_PITCH);
  499 }
  500 
  501 static void
  502 oplsyn_relevelv(midisyn *ms, uint_fast16_t voice, int16_t level_cB)
  503 {
  504         oplsyn_setv(ms, voice, 0, level_cB, OPLACT_LEVEL);
  505 }
  506 
  507 static void
  508 oplsyn_setv(midisyn *ms,
  509             uint_fast16_t voice, midipitch_t mp, int16_t level_cB, int act)
  510 {
  511         struct opl_softc *sc = ms->data;
  512         struct opl_voice *v;
  513         const struct opl_operators *p;
  514         u_int32_t block_fnum;
  515         int mult;
  516         int c_mult, m_mult;
  517         u_int32_t chan;
  518         u_int8_t chars0, chars1, ksl0, ksl1, fbc;
  519         u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
  520         u_int8_t vol0, vol1;
  521 
  522         KASSERT(mutex_owned(sc->lock));
  523 
  524         DPRINTFN(3, ("%s: %p %d %u %d\n", __func__, sc, voice,
  525                      mp, level_cB));
  526 
  527 #ifdef DIAGNOSTIC
  528         if (voice >= sc->syn.nvoice) {
  529                 printf("%s: bad voice %d\n", __func__, voice);
  530                 return;
  531         }
  532 #endif
  533         v = &sc->voices[voice];
  534 
  535         if ( act & OPLACT_ARTICULATE ) {
  536                 /* Turn off old note */
  537                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, 0xff);
  538                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, 0xff);
  539                 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    0);
  540 
  541                 chan = MS_GETCHAN(&ms->voices[voice]);
  542                 p = &opl2_instrs[ms->pgms[chan]];
  543                 v->patch = p;
  544                 opl_load_patch(sc, voice);
  545 
  546                 fbc = p->ops[OO_FB_CONN];
  547                 if (sc->model == OPL_3) {
  548                         fbc &= ~OPL_STEREO_BITS;
  549                         fbc |= sc->pan[chan];
  550                 }
  551                 opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc);
  552         } else
  553                 p = v->patch;
  554 
  555         if ( act & OPLACT_LEVEL ) {
  556                 /* 2 voice */
  557                 ksl0 = p->ops[OO_KSL_LEV+0];
  558                 ksl1 = p->ops[OO_KSL_LEV+1];
  559                 if (p->ops[OO_FB_CONN] & 0x01) {
  560                         vol0 = opl_calc_vol(ksl0, level_cB);
  561                         vol1 = opl_calc_vol(ksl1, level_cB);
  562                 } else {
  563                         vol0 = ksl0;
  564                         vol1 = opl_calc_vol(ksl1, level_cB);
  565                 }
  566                 r40m = (ksl0 & OPL_KSL_MASK) | vol0;
  567                 r40c = (ksl1 & OPL_KSL_MASK) | vol1;
  568 
  569                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 0, r40m);
  570                 opl_set_op_reg(sc, OPL_KSL_LEVEL,   voice, 1, r40c);
  571         }
  572 
  573         if ( act & OPLACT_PITCH ) {
  574                 mult = 1;
  575                 if ( mp > MIDIPITCH_FROM_KEY(114) ) { /* out of mult 1 range */
  576                         mult = 4;       /* will cover remaining MIDI range */
  577                         mp -= 2*MIDIPITCH_OCTAVE;
  578                 }
  579 
  580                 block_fnum = opl_get_block_fnum(mp);
  581 
  582                 chars0 = p->ops[OO_CHARS+0];
  583                 chars1 = p->ops[OO_CHARS+1];
  584                 m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult;
  585                 c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult;
  586 
  587                 if ( 4 == mult ) {
  588                         if ( 0 == m_mult )  /* The OPL uses 0 to represent .5 */
  589                                 m_mult = 2; /* but of course 0*mult above did */
  590                         if ( 0 == c_mult )  /* not DTRT */
  591                                 c_mult = 2;
  592                 }
  593 
  594                 if ((m_mult > 15) || (c_mult > 15)) {
  595                         printf("%s: frequency out of range %u (mult %d)\n",
  596                                __func__, mp, mult);
  597                         return;
  598                 }
  599                 r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult;
  600                 r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult;
  601 
  602                 rA0  = block_fnum & 0xFF;
  603                 rB0  = (block_fnum >> 8) | OPL_KEYON_BIT;
  604 
  605                 v->rB0 = rB0;
  606 
  607                 opl_set_op_reg(sc, OPL_AM_VIB,      voice, 0, r20m);
  608                 opl_set_op_reg(sc, OPL_AM_VIB,      voice, 1, r20c);
  609 
  610                 opl_set_ch_reg(sc, OPL_FNUM_LOW,    voice,    rA0);
  611                 opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice,    rB0);
  612         }
  613 }
  614 
  615 void
  616 oplsyn_releasev(midisyn *ms, uint_fast16_t voice, uint_fast8_t vel)
  617 {
  618         struct opl_softc *sc = ms->data;
  619         struct opl_voice *v;
  620 
  621         KASSERT(mutex_owned(sc->lock));
  622 
  623         DPRINTFN(1, ("%s: %p %d\n", __func__, sc, voice));
  624 
  625 #ifdef DIAGNOSTIC
  626         if (voice >= sc->syn.nvoice) {
  627                 printf("oplsyn_noteoff: bad voice %d\n", voice);
  628                 return;
  629         }
  630 #endif
  631         v = &sc->voices[voice];
  632         opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT);
  633 }
  634 
  635 int
  636 oplsyn_ctlnotice(midisyn *ms,
  637                  midictl_evt evt, uint_fast8_t chan, uint_fast16_t key)
  638 {
  639 
  640         DPRINTFN(1, ("%s: %p %d\n", __func__, ms->data, chan));
  641 
  642         switch (evt) {
  643         case MIDICTL_RESET:
  644                 oplsyn_panhandler(ms, chan);
  645                 return 1;
  646 
  647         case MIDICTL_CTLR:
  648                 switch (key) {
  649                 case MIDI_CTRL_PAN_MSB:
  650                         oplsyn_panhandler(ms, chan);
  651                         return 1;
  652                 }
  653                 return 0;
  654         default:
  655                 return 0;
  656         }
  657 }
  658 
  659 /* PROGRAM CHANGE midi event: */
  660 void
  661 oplsyn_programchange(midisyn *ms, uint_fast8_t chan, uint_fast8_t prog)
  662 {
  663         /* sanity checks */
  664         if (chan >= MIDI_MAX_CHANS)
  665                 return;
  666 
  667         ms->pgms[chan] = prog;
  668 }
  669 
  670 void
  671 oplsyn_loadpatch(midisyn *ms, struct sysex_info *sysex, struct uio *uio)
  672 {
  673 #if 0
  674         struct opl_softc *sc = ms->data;
  675         struct sbi_instrument ins;
  676 
  677         DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc));
  678 
  679         memcpy(&ins, sysex, sizeof *sysex);
  680         if (uio->uio_resid >= sizeof ins - sizeof *sysex)
  681                 return EINVAL;
  682         uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio);
  683         /* XXX */
  684 #endif
  685 }
  686 
  687 static void
  688 oplsyn_panhandler(midisyn *ms, uint_fast8_t chan)
  689 {
  690         struct opl_softc *sc = ms->data;
  691         uint_fast16_t setting;
  692 
  693         setting = midictl_read(&ms->ctl, chan, MIDI_CTRL_PAN_MSB, 8192);
  694         setting >>= 7; /* we used to treat it as MSB only */
  695         sc->pan[chan] =
  696             (setting <= OPL_MIDI_CENTER_MAX ? sc->panl : 0) |
  697             (setting >= OPL_MIDI_CENTER_MIN ? sc->panr : 0);
  698 }

Cache object: 2b980c38742de9194e2ca9d456f7da85


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