
Creative Sound Blaster or 100% Compatible sound output library.
(C) 2008-2011 Jonathan Campbell.
Compiles with Open Watcom.

What it supports:
   Any Sound Blaster or Sound Blaster compatible interface that communicates
   on ISA I/O ports 0x2x0-0x2xF (where X=2,4,6, or 8) using ISA DMA channels
   0, 1, or 3 and 16-bit DMA on 0, 1, 3, 5, 6, or 7.

   Also supports and recognizes various known emulations of the Sound Blaster,
   including:

      - Gallant/SC400 Crystal Semiconductor CS4232-based cards
             - They emulate a SB16 with a SBPRO mixer, and a Windows Sound System
               interface on 0x530 or 0xE30.
             - Their Sound Blaster emulation also has a proprietary "plug & play"
               software configuration command set, supported by this library

      - Yamaha OPL3-SAx Sound Blaster emulation

NOTICE: The sndsb.lib library by itself does not contain support for ISA Plug &
        Play Sound Blaster cards. The isapnp library is kind of large and
        building this library to depend on it only serves to add bloat to your
        program (especially if you will be targeting pre-486 hardware where
        PnP type hardware is very unlikely to be found).

        If you do want your program to support PnP type cards (especially if
        your code is intended for 486 and higher hardware) then you can link
        into your program sndsbpnp.lib and isapnp.lib to enable autodetection
        of ISA Plug & Play based Sound Blaster hardware.

WARNING: Sound Blaster PnP support is written only to read back the
	 resources assigned. Cards whos resources have not been assigned
	 will be ignored.

	 In the DOS world, the task of PnP resource assignment is
	 generally given to a device driver or DOS utility that carries
	 out configuration (such as: Creative PnP utilities).

	 If you really want to, look at the PNPCFG.EXE utility provided
	 here as an example of a minimalist Sound Blaster PnP resource
	 assignment program. Then if you really want to, go ahead and
	 write your program to auto-configure the card if necessary.
	 I strongly recommend though that if you do that, you allow the
	 user to turn it off, since the PnP device is likely sharing the
	 system with perhaps several other ISA devices that could easily
	 conflict with the one you're trying to auto-config!

TABLE OF SUPPORTED CARDS
------------------------

    YES = Card is supported, verified by actual h/w testing
  HWEMU = If listed with YES or LIKELY, the hardware itself responds to I/O ports
          like a Sound Blaster even though the chipset is something else entirely
 LIKELY = Card is supported, because the interface is Sound Blaster compatible,
          but I have not yet tested and verified that it works. If listed with
          SWEMU, then the software emulation is likely Sound Blaster compatible
          even though the actual hardware is not.
  MAYBE = Card might be Sound Blaster compatible, I don't really know
    PNP = Card is ISA Plug & Play compatible, if listed with YES or LIKELY the
          card will work with this library IF you first run an ISA PnP configuration
          utilty to assign it's resources and bring it online.
  PNPNC = Card is ISA Plug & Play compatible, but needs no configuration utility
          to enable Sound Blaster or Sound Blaster emulation
  SWEMU = Card is NOT Sound Blaster compatible, but comes with a DOS TSR that abuses
          EMM386.EXE and/or Virtual 8086 mode to emulate a Sound Blaster
   BIOS = Card is Sound Blaster compatible by emulation using motherboard audio,
          and can be enabled/disabled through the BIOS setup menu
    PCI = Card connects through PCI bus
   MORE = Card is Sound Blaster compatible and has additional functions that might
          be of interest
     NO = Card is NOT Sound Blaster compatible

  Finer details on every possible card I've tested is listed in the sndsb library
  source code.

Creative Sound Blaster 1.5 (CT1320C)                        LIKELY
Creative Sound Blaster 2.0 (CT1350)                         YES
Creative Sound Blaster Pro (CT1330)                         LIKELY
Creative Sound Blaster Pro 2 (CT16x0)                       YES
Creative Sound Blaster 16                                   YES
Creative Sound Blaster 16 ViBRA                             YES
Creative Sound Blaster 16 ViBRA PnP (CTL00F0)               YES PNP
Creative Sound Blaster 16 ViBRA PnP (CTL0070)               YES PNP
Creative Sound Blaster AWE64 PnP (CTL00C3)                  YES PNP MORE
Creative Sound Blaster AWE64 Gold PnP (CTL00B2)             YES PNP MORE
Creative Sound Blaster Live! Value                          PCI YES SWEMU
Gallant SC-6000, Crystal Semiconductor CS4232               YES HWEMU
VIA EPIA (????) [LOOK IT UP]                                YES BIOS HWEMU [*VIA EPIA]
Yamaha OPL3-SAx                                             YES HWEMU PNPNC [*1]
Gravis Ultrasound MAX & SBOS 4.x                            YES SWEMU [*GUS]
Gravis Ultrasound MAX & MEGA-EM                             YES SWEMU [*GUS]
Media Vision Pro Audio Spectrum 16 (PAS16 650-0018)         YES

[*GUS] Gravis Ultrasound: The GUS basically pretends to be a Sound Blaster and other
                          components by trapping certain I/O ports and reflecting to
                          a TSR by NMI. Most often the ports overlap the GUS's.
                          Emulation is terrible, especially MEGA-EM that only emulates
                          a Sound Blaster 1.xx DSP and will literally hang the machine
                          if you use any DSP command outside the supported set. DMA
                          timing is terrible. Rather than a continuous stream as by
                          Sound Blaster you see instead the DMA speed by and finish
                          far before the audio finishes playing. If you're a DOS
                          program depending on the DMA to match timing, you're
                          not going to work too well. Also does not emulate auto-init.

[*1] Yamaha OPL3-SAx: it is listed as PNPNC because the only one I have to test against
                      is embedded on the motherboard of a laptop who's BIOS takes care
                      of ISA PnP resource allocation. In fact the BIOS lists the sound
                      card as one of the system nodes that can be enumerated using the
                      PnP BIOS entry point.

[*VIA EPIA] VIA EPIA: For whatever reason, despite the BIOS-supported emulation, I am
                      unable to actually hear the sound output through the line out
                      jack. The card seems to require a proprietary initialization
                      procedure to enable the output. Other than that, DMA and IRQ
                      activity suggests that it works fine.

PRO AUDIO SPECTRUM ISSUES
-------------------------

Apparently if the Pro Audio Spectrum chip and the Sound Blaster emulation have different
IRQ settings, SNDSB will not be able to use or detect the IRQ. If this happens, try
running INSTALL.EXE and reconfiguring the card to put both onto the same IRQ (IRQ 5
recommended).  [PAS16 test]

DSP VERSIONS
------------

  - DSP 1.xx

      The code talks to the card in a manner compatible with the original Sound Blaster.

  - DSP 2.00

      Sound Blaster 2.0 compatible operation. In this version Creative added auto-init
      playback which means the software only needs to acknowledge the interrupt instead
      of reprogramming the DSP to start another block.

  - DSP 2.01

      Creative added the "high speed DAC" mode to enable playback up to 44100Hz mono
      (22050Hz stereo). On a real Sound Blaster 2.0 card I own, the DSP appears to have
      timing problems where in non-high speed mode any other use of the ISA bus can
      cause audible slowing down.

  - DSP 3.xx

      Sound Blaster Pro compatible output. Uses the mixer chip to enable stereo, which
      should also work on clone cards, but will remain monural on Sound Blaster 16 cards
      because Creative removed the control for some reason. Steroe playback on SB16 cards
      require DSP 4.xx playback mode.

  - DSP 4.xx

      Sound Blaster 16 compatible output. This enables 16-bit audio playback. Stereo
      playback on SB16 requires this mode, Pro stereo does not work. SB16 specific DSP
      commands also allow "flipped sign" playback.

  ADPCM playback only works with monural 8-bit audio. Direct DAC mode will only function
  properly with 8-bit monural audio.

WARNINGS
--------

Goldplay & Direct DAC modes:
  - These modes work by using the CPU and the IRQ 0 timer interrupt
    to play sound. If your machine is slow enough, the timer ISR
    can overwhelm the CPU and effectively make the UI unresponsive.
    This can happen for 16-bit builds on a slow enough configuration,
    but it is especially a problem with 32-bit builds due to the
    overhead involved with the 32-bit DOS extender.
    
    This program has a "watchdog timer" implemented into it's timer ISR
    to try and deal with timer overrun. In most cases if the ISR consumes
    all CPU the watchdog will time out, stop playing, and restore the
    tick rate to 18.2/sec so that the UI becomes usable again and you can
    safely stop playback and/or exit to DOS. But it is not 100% perfect,
    and what can happen instead is that the Sound Blaster ISR can get
    triggered in an infinite loop by a General Protection Fault (IRQ 5
    and the GP# fault overlap thanks to politics between Intel and IBM),
    or the DOS extender can crash to DOS with an error message about
    overrunning the stack (with the timer and keyboard unresponsive!).

    When you enable Direct DAC or Goldplay mode in the 32-bit version,
    a warning message will remind you (once) of this potential pitfall,
    and allow you to cancel the selection.
    
    The final warning is that this method should never be used in an
    environment where everything is totally virtualized, especially from
    within a Windows DOS box. Windows 95/98 have problems as it is dealing
    with DOS games that reprogram the timer beyond 100Hz.
    
    Remember, if you play with Direct DAC mode or Goldplay mode, and the
    program hangs or crashes, don't blame me---you were warned!
    
    NOTES: Sun/Oracle virtualbox. Does not work, produces low frequency
           "warble". Also seems to cap the timer rate at about 4KHz, no
	   matter what rate this program is trying to run at.

    NOTES: DOSBox 0.74. Does not work, produces low frequency "warble"
           though timer rate is correct. If you must hear Goldplay mode
	   in action use the dosbox-x "branch" source code I posted in
	   the Vogons forums, which contains a fix to make Goldplay mode
	   work correctly in DOSBox (as well as allow many older demos
	   to play music audibly).

    NOTES: Direct DAC mode also affects recording. The same ISR timer
           technique is used to issue DSP command 0x20 (Direct ADC input)
	   and then read the result from the DSP. Experience says this
	   technique maxes out at 11KHz, if overdriven the ISR might
	   overrun the stack and crash.
    
Goldplay mode, an explanation:

    In the demoscene from about 1991 to 1993 there was a short-lived
    audio/tracker library called Goldplay that supported Sound Blaster
    and Sound Blaster Pro in addition to Covox, Disney sound source
    and other legacy one-sample-at-a-time sound output methods. The
    libary was written to hook the timer interrupt and reprogram the
    timer to run at the sample rate needed to play audio, then write
    one sample from the interrupt.
    
    The obvious problem the programmer(s?) faced was that the code was
    written for audio output methods that needed the CPU to write to them
    at a constant rate, because the devices themselves had no way to pull
    in audio by themselves. So naturally the timer interrupt was a way
    to accomplish that. But then what do you do about the Sound Blaster,
    which uses DMA and for stereo output does not offer a way to manually
    write audio samples?
    
    Many demos at the time opted for the method of programming the timer
    ISR to twice the sample rate, then alternately writing DSP command 0x10
    and the audio sample to play. But DSP command 0x10 cannot run faster than
    22050Hz, and cannot play stereo.
    
    Goldplay programmers apparently decided to support Sound Blaster then
    using a simple hack. The library tells the DSP the block size is 65535
    samples, then tells the DMA controller the buffer is 1 sample wide!
    This means that during playback the DMA controller is transmitting the
    same sample over the ISA bus. Then, from the timer ISR, the library
    just overwrites that one byte with the latest sample to transmit. The DMA
    controller sends the new byte next cycle, and the DSP gets "sound".
    
    The obvious problem of course is that the timer is very likely not running
    at the same rate as the DSP, and this trick usually results in slightly
    scratchy sound as a result of samples getting duplicated or dropped.
    
    Such a trick was possible, because systems at the time did not cache CPU
    I/O (286s), or did cache CPU I/O but had logic to keep the cache coherent
    between the DMA controller and the CPU (386, 486, Pentium motherboards).
    On today's hardware the PCI bus logic and CPU memory controller would
    have a lot of difficulty pulling a stunt like that, which is why you don't
    really see that kind of trickery anymore.
    
    For testing purposes, the test program emulates that hacked method of
    playback just to see if it's possible. So far, testing shows that it is,
    even in configurations the Goldplay library would have never used (such
    as "Goldplay mode" with 16-bit stereo PCM).
    
    NOTE: Even though the Goldplay library never recorded audio, this program
          can also be used to test whether one can record audio from the DSP
	  in this manner. Apparently it's possible, on real hardware! Switch
	  on Goldplay mode and then select "record" to see in action.

ADPCM auto-init:

    On actual Creative hardware there are DSP commands to play sound data
    compressed using Creative's proprietary ADPCM compression method.
    On Sound Blaster 2.0 and higher DSPs, there are additional commands to
    play the data in an auto-init fashion. Most clones and emulators know
    the original ADPCM commands, but generally do not respond to the
    auto-init versions. If you enable auto-init ADPCM and playback causes
    nothing to happen, then your card/emulator does not recognize it.
    
    DOSBox 0.74:     Supports and decodes ADPCM, does not recognize
                     auto-init ADPCM
    VirtualBox:      Does not support ADPCM at all
    Virtual PC:      Does not support ADPCM at all
    Yamaha OPL3-SAx: Supports 4-bit ADPCM, cycles DMA for 2.6/2-bit silently,
                     does not recognize auto-init ADPCM

ADPCM reset step per IRQ:

    DOSBox 0.74 emulates Sound Blaster ADPCM playback perfectly, except for
    one difference observed on genuine Creative hardware: Once per IRQ, even
    in auto-init mode, the DSP resets the step value, while DOSBox does not.
    A program that is unaware of the reset will produce audio that generally
    sounds OK but can audibly "flutter" depending on how often the IRQ
    occurs. This fluttering effect is caused by the ADPCM data compressed
    with one step size, and the SB decoding with the wrong step size, until
    ADPCM limits knock them back into sync.

    So when Creative documents the DSP commands as having a "reference byte"
    version and a version that "decodes using accumulated reference byte"
    consider they only mention the reference byte for good reason: the DSP
    does not preserve any other ADPCM state. Probably to make decoding from
    an arbitrary point in VOC files more predictable, I suppose.

    You can test for proper behavior by loading an 8-bit monural WAV file,
    setting the audio to 2.6 or 2 bit ADPCM, and playing it. On real hardware,
    it should sound fine, while in DOSBox, it should audibly flutter like
    a badly tuned FM radio. Switching off ADPCM reset per block should
    cause the opposite: DOSBox sounds fine, while on real Creative hardware
    it should audibly flutter.
    
    NOTE: The code has been tweaked to produce the best ADPCM output by ear
          on real SB16 hardware. Creative's ADPCM compression overall though
	  is crap, so in the end it's difficult to tell whether the flutter
	  happens because of errors in my code or because resetting the
	  step size leaves little to no room to properly encode the waveform
	  at the reset point. All I know is that the reset values in my code
	  seem to produce the least amount of audible flutter, even though
	  nothing I can do eliminates it completely.
	  
	  One way to eliminate flutter is to change the IRQ interval to
	  the large setting, so that the DSP plays a larger amount of data
	  before resetting at the next block.

Sound Blaster Pro stereo:

    When Creative first implemented stereo in the Pro cards, they added a bit
    to a mixer register that enables/disables it. The program sends a time
    constant representing twice the sample rate, then flips on stereo, and...
    stereo playback happens.
    
    Most clone cards made afterwards emulate this bit quite well, even the
    cards that implement SB16 commands such as the Gallant SC-6000 chipsets.

    But Creative for some reason removed that function on the Sound Blaster 16
    cards and designed them instead to require the DSP 4.xx 0xBx-0xCx DSP
    commands to play back in stereo. The result is that DOS programs written
    around the Pro and it's stereo bit produce scratchy monural audio on the
    SB16, while ironically producing correct stereo output on clone cards!

    In this program, DSP mode 3.xx attempts to play stereo using DSP 3.x
    commands and the stereo bit, while DSP 4.xx uses the SB16 command set
    and does not set the stereo bit. If you have DSP 3.xx mode set and stereo
    audio sounds funny, then you have true Creative SB16 hardware and you
    need to reconfigure to DSP 4.xx mode.

ISA Plug & Play compatibility:

    If your SB16 is the ISA PnP variety, it will be automatically detected.
    However if neither the BIOS nor any DOS utilities have assigned resources,
    this program will not be able to make use of the card.
    
    To resolve the issue, try:
    
      - Using the PNPCFG program provided to assign resources.
      - Use DOS utilities provided by the manufacturer to assign resources.
        Creative for example offers a DOS utility to test and assign resources
	to their Sound Blaster cards (both PnP and legacy versions)
      - If your BIOS offers the option, see if the setup menu offers ISA
        PnP resource assignment. Some BIOSes will automatically (try) to
        assign resources. One BIOS I test against likes to assign my SB16
        ViBRAX/V to IRQ 2 and DMA channel 0!

    ISA PnP compatability verified with:
      Sound Blaster 16 ViBRAC
      Sound Blaster 16 ViBRAX/V
      Sound Blaster AWE 32
      Sound Blaster AWE 64 Gold
      Microsoft Virtual PC Sound Blaster 16 emulation

    Some cards, for whatever reason, do not appear to have working 16-bit DMA
    transfer capability. Attempting to play 16-bit audio when the 16-bit DMA
    channel is 5, 6, or 7 will result in nothing at all. If that happens, try
    assigning both 8- and 16-bit DMA channels to DMA 0, 1, or 3.
    
Non-ISA Plug & Play card software configuration:

    Some SB16 cards (or clones) are not ISA Plug & Play compatible, but do
    have some proprietary method of configuring DMA and IRQ resources. For
    these cards the PNPCFG utility will not work. You will instead need to
    identify the card, and then run the appropriate tool to initialize them:
    
    Sound Blaster 16 (non PnP)
      - Run the TEST program. Select the card. Note that if it has not been
        assigned resources the DMA and IRQ fields will read -1. Go to the
	device menu, and select Configure card. The program should indicate
	you are using a non-PnP SB16 and should offer options to configure
	IRQ and DMA channel settings. When you are finished, hit ENTER.
	
	NOTE: IRQ and DMA settings are changeable, while the base I/O address
	      is NOT changeable. This method will also NOT work with PnP
	      versions of Sound Blaster 16 hardware, nor will it work within
	      Microsoft Virtual PC 2007 (emulated PnP SB16).
	
	NOTE: This is the recommended way to reconfigure Sound Blaster 16
	      support in DOSBox, VirtualBox, and Bochs emulators as they
	      emulate Sound Blaster 16 functions but without ISA PnP.

    Gallant SC6600/Crystal CS4321 "SC-4000" cards
      - Uses a jumper to configure the base I/O address, but all other
        resources are assigned by non-standard DSP commands. The card
	emulates a weird hybrid of Sound Blaster functions: a Pro-style mixer
	and a DSP that reports itself as a Pro (v3.5) yet it also supports
	SB16 DSP commands and 16-bit playback. The card also maps the CS4321
	crystal codec to a configurable WSS address (usually 530h).
	
	Run the TEST program. Select the card. Note that if it has not been
	assigned resources the DMA and IRQ fields will read -1. Go to the
	device menu, and select Configure card. The program should indicate
	you are using a SC-6000 card and offer options to change IRQ, DMA,
	and WSS I/O port resources. When you are finished, hit ENTER.

PCI motherboard issues:

    Some motherboards block or only allow certain IRQ and DMA channels to
    work across the PCI-ISA bridge. Normally the IRQs blocked are IRQ 9, 10,
    11, 13, 14, and 15 depending on whether your BIOS has assigned them to
    motherboard resources or PCI peripheral devices, while IRQ 3, 4, 5, 6,
    and 7 are normally left open. BIOSes that assign IRQs to either PCI or
    ISA normally allow you to change the assignment manually in the setup
    menu.

The 32-bit protected mode version has SB IRQ problems when configured to IRQ 8, 9, 10, etc...

    On some 486/Pentium boards and ViBRA SB16 cards there seem to be
    some horrible reliability problems between the BIOS, the DOS extender, and
    the upper IRQs. The IRQ may work the first few times but after that nothing
    fires and the Sound Blaster DSP stops playback waiting around for our ISR
    to return acknowledgement.
    
    UPDATE: Independent testing reveals that it is a problem with the DOS4/GW
            DOS extender. The issue mentioned above is reproducible on a lot
	    of other hardware such as a Dell Pentium III test machine.
    
    There are several ways to handle this:
      - Stop using DOS4/GW and run the program using open source DOS extender
        DOS32a, which doesn't seem to have this problem.
      - Use the 16-bit real mode versions. On the same systems they do not
        appear to have any problems.
      - Use a PNP configuration utility to move the IRQ down to 5, 7, etc.

16-bit real mode large model hack, the SB IRQ indicator:

    For reasons beyond my comprehension, the 16-bit large model builds had
    a mysterious bug where half the time the subroutine would fail to redraw
    the IRQ indicator. This was visible on screen as erratic jumpy movement
    of the 'x' in the indicator. At one point, this indicator was responsible
    for several severe memory corruption issues that would eventually crash
    the machine!
    
    So, the 16-bit large model version redraws it instead from the main loop.
    This means though that if the main loop is unable to function, the IRQ
    indicator will not function and will be unable to show you if the DSP
    is still signalling interrupts.
    
    16-bit real mode small model, and 32-bit protected mode builds, are
    able to retain redrawing the indicator from the Sound Blaster ISR. Even
    if the main UI hangs, you will still be able to see IRQ activity in the
    upper left corner of your screen.

Flip sign mode:

    In the DOS/Windows world there are two de-facto "standard" PCM formats
    widely used. One is 8-bit unsigned PCM, using byte values 0 to 255 (with
    128 at center) to represent the waveform. The other is 16-bit signed PCM,
    with -32768 to 32767 (with 0 at center). The SB16 DSP commands 0xBx-0xCx
    have bitfields to indicate 16-bit playback, as well as whether the audio
    data is signed or unsigned. In most cases, it is told to play either
    unsigned 8-bit or signed 16-bit data, and clone cards support that command
    as well. What clones and emulators get wrong though, are situations where
    the DOS program instead instructs the DSP to play signed 8-bit PCM, or
    unsigned 16-bit PCM.

    Note that the same DSP command is used for playback and recording.
    
    When enabled, the program will flip the sign bit before sending to the
    card, and then tell the SB16 DSP that it is the opposite signed/unsigned
    mode. If your card fully supports the DSP commands, it should make no
    audible change in the sound. If your card is a clone or an emulator that
    is not aware of the bits, you will hear loud static.
    
    DOSBox 0.74: Fully supported
    Bochs: Not fully supported. Loud static.
    Gallant SC-6000 clone: Fully supported

ESS 688 auto-init does not fire IRQ:

    ESS chipsets work perfectly fine with auto-init and single-cycle modes,
    EXCEPT that for whatever reason, the chipset does not fire the IRQ if
    playing or recording 16-bit PCM and using auto-init DSP mode.

    If designing a game to use this library, this may be something to keep
    in mind if you are considering having music playback or synthesis occur
    from an IRQ---you cannot rely on using the SB IRQ to do this on ESS
    chipsets.

BUGS
----

1]  Direct DAC and Goldplay modes (anything using the timer ISR to play)
    can overwhelm the CPU and effectively freeze the UI, forcing the user
    to push reset button.

    FIXED. Timer ISR has watchdog counter. When it hits zero, it forcibly
    stops playback and resets timer to 18.2/sec tick rate. The UI, if
    functional, will otherwise reset the watchdog and therefore allow the
    audio to keep playing. This way, if your CPU is too slow, the program
    will auto-recover within 5-10 seconds so that you can safely stop
    playback and/or exit the program.

2]  Audio playback occassionally skips 1-4 seconds forward. Audio recording
    occassionally repeats a 1-4 second section to disk.

    FIXED. The DMA counter readback code failed to consider the 8237 does
    not necessarily latch the value during reading, causing reads to
    occassionally give bad or incorrect readback values that confuse the
    DMA tracking logic and cause it to over-refill the buffer.

    The 8237 library has been updated to read the counter twice, and re-read
    until the value counts down as expected.

3]  The IRQ indicator would randomly draw or not draw in the 16-bit real mode
    large build. It would also cause random memory corruption that would
    eventually crash the computer.

    FIXED, and FIXED. Changing the method by which "SB-IRQ" was written
    fixed the memory corruption issue, though it doesn't explain the random
    corruption, and it still didn't fix the random updating problem. Instead,
    the code was written to have the main loop do the IRQ state update.
    16-bit small model, and 32-bit flat mode builds retain the code to redraw
    IRQ state from within the ISR.

4]  On a Pentium motherboard (with Award bios dated 1995) having PCI, ISA slots
    and Pentium 133MHz MMX processor, the 32-bit build cannot reliably service
    Sound Blaster DSP interrupt if IRQ is assigned to IRQ 8 or higher.
    Playback will work for awhile, then stop. A raw dump of the mixer shows
    byte 0x82 set to 0x41 (which means the DSP is waiting for acknowledgement,
    and therefore the IRQ was not serviced). 16-bit builds are not affected
    by this bug.
    
    NOT FIXED. I noticed the problem is reproducible on a lot more than just
    that one motherboard, and testing reveals that it is a problem with the
    DOS4/GW DOS extender. You can resolve the issue by replacing the DOS
    extender with one that does not have this problem, such as DOS32a
    (http://www.sf.net/projects/dos32a).

5]  Goldplay record/playback mode doesn't work when EMM386.EXE is resident and
    active.

    FIXED. It turns out pointing DMA at the Sound Blaster context structure
    was a bad idea. It happens to work in non-EMM386.EXE situations because
    the struct usually ended up below 16MB. But EMM386.EXE does not virtualize
    locations above 1MB, so DMA was effectively playing some unrelated data.
    Goldplay mode now allocates a separate (16-byte long) DMA buffer.

6]  Selecting "Device" -> "Trigger IRQ" when playing or selecting 16-bit audio
    causes computer to lock up. 32-bit builds trigger a crash dump in DOS32a
    and DOS4G/W.

    FIXED. The Sound Blaster DSP expects one form of acknowledgement for 8-bit
    I/O, and another form for 16-bit I/O. The code used the 8-bit version at
    all times. If that is done, the Sound Blaster DSP re-fires the IRQ
    expecting the ISR to take care of 16-bit I/O. Since the program never does,
    the IRQ re-fires until the stack overflows and the program crashes.

7]  Audio plays twice as fast or skips every other second when playing audio
    on Gravis Ultrasound SBOS/MEGA-EM installations.

    SBOS compatibility:
       FIXED [16-bit real mode small model].
    
       FIXED??? [16-bit real mode large model]. At least it seemed to fix
       itself, or at least stopped skipping ahead with noise every time the
       DMA pointer crossed the end of the buffer. Perhaps the phase of the moon
       changed during testing, who the fuck knows? >:[

       FIXED, sort of [32-bit protected mode]. The test program now hooks the
       NMI interrupt from protected mode so it can reflect it back to real
       mode. However, the NMI handler doesn't seem to be able to trigger the
       SB IRQ in protected mode, so playback will stall after playing a short
       piece of the audio.
 
       The above NMI hack will work with DOS4/GW and DOS32a. However if
       EMM386.EXE is resident and active, DOS4/GW will hard crash and reboot
       the system upon receipt of an NMI interrupt. If your program needs
       EMM386.EXE to be active, consider using DOS32a instead.

       If EMM386.EXE is not active, and the test program does not hook the
       NMI, DOS4/GW simply does not reflect the interrupt and the program
       will not reliably detect the virtual sound card.
       
    MEGA-EM compatibility:
       FIXED [16-bit real mode small model].
       
       NOT FIXED [16-bit real mode large model]. Despite extremely careful
       DMA controller programming, running this program seems to invoke
       EMM386.EXE's panic screen complaining about the program attemping
       to do a 64KB DMA transfer (WHAT?!). Adding D=64 to the EMM386.EXE
       device line in your CONFIG.SYS seems to resolve the issue.
       
       NOT FIXED [32-bit protected mode]. NMI interrupt causes DOS extenders to
       panic. Hooking the NMI interrupt from protected mode to reflect back to
       real mode doesn't resolve DOS4G/W causing a hard reset on NMI, but
       when run under DOS32a the NMI emulation magic apparently fails to work,
       and the test program fails to see the emulated sound card.
    
    While effort has been made to support SBOS and MEGA-EM emulation, I
    consider full compatibility a low priority. I have no patience for
    twitchy TSRs that have stability issues, shitty Sound Blaster emulation,
    and bizarre DMA bugs.
    
8]  When playing audio through SBOS, switching to ADPCM mode causes the
    program to hang and crash.

    NOT FIXED. I have no patience with SBOS and I do not forsee any need
    to use ADPCM mode with it.
    
    If you must use ADPCM playback with the Ultrasound, use MEGA-EM, which
    at least does a reasonable job faking the ADPCM playback without causing
    a hard crash.
    
9]  When playing ADPCM audio with MEGA-EM, the audio sounds buzzy and
    distorted, or tinny and quiet like static.
    
    NOT FIXED. MEGA-EM attempts to fake ADPCM playback, but the programmers
    obviously had no documentation on what exactly the ADPCM format did
    (back then, who did?).

Gravis SBOS bugs this code has to deal with:

  - The people who wrote SBOS evidently failed to take into
    consideration the interpolation used by the GF1 chip,
    thus there are audible pops and buzzing at the boundaries
    of DSP blocks not because of any errors but because of
    the GF1 interpolating into undefined samples

  - SBOS's use of INT 02h (NMI) causes DOS4/GW to hard reset
    and DOS32a to crash to the DOS prompt with an exception
    report. You can avoid the hard crash with DOS32a at least
    by hooking INT 02h from protected mode to reflect to real
    mode, but the NMI handler doesn't seem to be able to issue
    the SB IRQ back into your protected mode program
    
  - I also noticed their NMI handler occasionally seems to not
    carry out the DMA transfer at all. Instead it does the transfer
    within the NMI handler. For programs that rely on the DMA pointer
    to advance audio this is bad news, and something to watch for.

DSP alias port
--------------

A long time ago I stumbled upon an old demo written by the Eletromotive
force (EMF_ID.ZIP) that I thought was interesting, but could never get
the Sound Blaster mode working. Every time I tried, the demo hung after
prompting for Sound Blaster setup.

It wasn't until I ran it in DOSBox that I eventually figured out what
was wrong: the demo relied on using the ALIAS of the DSP port, meaning
that it read status from and wrote DSP commands to port 0x22D instead
of 0x22C. I immediately plugged in an old Sound Blaster (DSP 2.0) and
confirmed that all I/O ports do in fact appear on both the original
and the alias ports, as if the card only decodes 4 bits and pays attention
to the top 3 while ignoring the LSB.

If you have an old Sound Blaster card, you might enable DSP alias port
mode to instruct the library to use port 0x22D to see if it actually
works. If it works, you have an original Sound Blaster that aliases
it's I/O ports.

List of cards and whether or not ports alias:
---------------------------------------------
Sound Blaster (DSP 1.x)                 PROBABLY
Sound Blaster (DSP 2.01)                YES
Sound Blaster Pro (DSP 3.x)             PROBABLY NOT
Sound Blaster 16 (DSP 4.x)              NO
ESS Plug and Play AudioDrive            YES (DSP PORTS ONLY)

Backwards mode
--------------

Besides the EMF_ID fix mentioned above (in DSP alias port), the demo
also appears to use DMA decrement mode. What that means is that, instead
of pointing the DMA controller at the first byte and rendering audio
forwards, it instead points the DMA controller at the last byte and
renders audio backwards, then tells the DMA controller to decrement
the address after every byte (instead of incrementing) so that the
backwards audio is played forwards.

If you want to play files backwards or want to test whether your
motherboard supports DMA decrement mode, you can go into the
"parameters" page and set "direction" to "backwards". if you hear
the audio perfectly in reverse, then your motherboard supports the
"decrement" bit of the DMA controller's mode register.

I consider it an additional test of robustness if you set both DMA
and the DSP into single-cycle non-auto-init mode and playback does not
exhibit any glitches.

WARNING: Backwards mode should be used with 8-bit PCM only! 16-bit PCM
         backwards playback is NOT RECOMMENDED, especially if your
         sound card is configured to use an 8-bit DMA channel to carry
         it (byte order is backwards and LOUD STATIC will result!).

         If you are using a 16-bit DMA channel, then theoretically it
         MIGHT work, but there are no guarantees. To consider why it
         might work, think about how the DMA controller uses the low
         15 bits to determine the memory address, then imagine how
         the DMA controller loads 16 bits from memory (PROBABLY in
         the correct byte order!) and sends it to the sound card.

* TODO, NOT YET IMPLEMENTED *

 - Recording in backwards mode (use backwards DMA to record, then write
   data FORWARDS to the WAV file)
 - ADPCM playback with DMA backwards mode (compress to ADPCM backwards,
   then write compressed ADPCM backwards!)

What is "nagging the DSP?
-------------------------

I recently patched up DOSBox-X to support the Triton "Crystal Dream" demo's
Sound Blaster support. In the process of doing so, I learned a few funny
things about both DOSBox source code and the Sound Blaster.

First, the Crystal Dream demo uses the Goldplay technique, where the
Sound Blaster is told the DSP block size is 65536 bytes, but the ISA DMA
controller is put into auto-init mode and told the DMA transfer length
is 1 byte (2 bytes if stereo). But what Crystal Dream does beyond that
is interesting in it's own right.

First of all, my initial assumption that the demo was hooking the wrong
IRQ was wrong. I looked at the interrupt vector table while it was running
and I saw that it hooked IRQ 0, and IRQ 1, but didn't hook any other
interrupts. Which means that, when the Sound Blaster signals an IRQ,
the demo doesn't respond to that IRQ at all.

At the same time, the demo uses the single-cycle DSP playback commands,
which means that at some point, the DSP will finish the block and the
demo needs to start another one to keep playing. So how does it keep
the audio going this way despite no IRQ handler?

It turns out, digging into the IRQ 0 hook it sets up, the demo starts
audio by sending DSP command 0x14 at the start. Then, the IRQ 0 handler
not only renders music but also polls the DSP write status port 0x22C.
If the DSP reports itself busy, the demo resets a counter, else when
the DSP is not busy, it decrements the counter. When the counter gets
low enough, the demo uses the IRQ 0 interrupt to send another DSP
command block (0x14,xx,xx). The fact that the Sound Blaster has not
yet finished playing the last block at this point is irrelevent.
So, about 10-20 times a second, the demo is constantly interrupting
DSP playback to start DSP playback, and the audio keeps going.

Now on actual hardware apparently, this works perfectly fine. In fact,
the advantage of the technique is that it allows audio without any
small pops or crackles normally associated with the CPU and interrupt
system taking too long to start another block, even on the original
Sound Blaster. The other advantage is that, by doing it all from IRQ
0 and effectively interrupting the DSP constantly the DSP never fires
the IRQ normally associated with completing a block, so the demo never
has to concern itself with IRQ detection logic (never mind it assumes
DMA channel 1). When I coded support code for this in DOSBox's emulation,
I coined it "nagging the DSP", because the demo is constantly nagging
the DSP to keep playing in a rude manner (but it works!)

To test this case, the sndsb library and test program allow you to
enable that mode to see how well your Sound Blaster handles that kind
of playback. To actually trigger the behavior, you will need to enable
DSP nag mode, and switch DSP playback into single-cycle mode (where
by default it is in autoinit mode).

DSP hispeed mode on SB 2.x and SB Pro
-------------------------------------

On these cards, DSP hispeed mode, normally needed for >= 23KHz mono or
>= 12KHz stereo, puts the DSP into a mode that does not respond to
commands, thus it is said to be "blocking". If you want to see whether
or not it is blocking, you can use /hinoblk to make the library act as
if it's not, then observe whether the program temporarily hangs when
attempting to stop DMA.

DSP auto-init vs DMA auto-init
------------------------------

Despite similar sounding names the two options control entirely different
things. DMA auto-init concerns itself with the auto-init bit on the ISA
DMA controller, which if set, causes the DMA controller to automatically
restart a DMA block when it reaches the end.

DSP auto-init concerns which set of DSP commands are used to start playback.
The Sound Blaster family has two sets: single cycle, and auto-init.

Single-cycle commands play a block of audio, then fire an IRQ and stop.
Continuing playback requires the CPU to send another command to start
playback again.

Auto-init commands are usually only sent once. Once the command is sent,
the DSP keeps playing (sending an IRQ every so many bytes) until it is told
to stop. This is the recommended way to play audio on Sound Blaster hardware,
although the original Sound Blaster does not support auto-init DSP modes,
and many clones and emulations do not handle it well either.

Sound Blaster 16 auto-init/FIFO modes
-------------------------------------

Sound Blaster 16 cards (DSP 4.xx) support a new set of commands that
includes bits to specify whether the DSP plays the audio as single-cycle
or auto-init, as well as whether or not it will enable the FIFO.
Under normal circumstances, you would not use the FIFO for single-cycle
and use the FIFO in auto-init. The option is given to you however to see
what happens if you, say, switch off the FIFO in auto-init, or enable
the FIFO in single-cycle.

Note that clones implementing SB16 DSP commands support only the most
common commands and do not support the uncommon combinations mentioned
above. SC-6000 cards for example support FIFO & auto-init but do not
support single-cycle or non-FIFO auto-init forms of the command.

Most clones do not emulate the SB16 anyway, even those produced in the
late years (1996-1999) of the ISA bus and DOS support.

If you're wondering by the way what happens, single-cycle DSP playback
with the FIFO enabled tends to miss some samples. The DSP acts as if
it completes the block early with data still in the FIFO, and then
forgets the contents of the FIFO. Auto-init without FIFO apparently
has no effect, but I would bet that if the ISA bus was busy with
another device the lack of FIFO might cause some audible effects.

ESS 688, changing the IRQ and PnP BIOS conflicts
------------------------------------------------

If you change the IRQ from this test program, understand that if the
ESS chipset is listed by the PnP BIOS, the original IRQ (now wrong)
will be used from the PnP BIOS enumeration and IRQ will appear not
to work. To avoid this, run the test program with /nopnp every time
after changing the IRQ.

ESS chipsets and the ESS control register raw mode
--------------------------------------------------

For debugging purposes, the program allows you to poke at the ESS
registers as raw byte values. Understand that doing this may cause
temporary issues with the hardware or cause problems and hangs with
the software. Poke at the registers at your own risk.

By default, only registers 0xA0-0xB9 are shown for ESS 688 chipsets.
Registers 0x00-0x9F do not exist, and on ESS 688 chipsets, the DSP
will not return any data for registers 0xBA-0xBF so they are blocked
off. If you want to make sure that the registers exist, type 'p' to
trigger a re-detection cycle. Know that for undefined registers, the
program may hang temporarily waiting for DSP timeouts.

ESS 688 undocumented registers
------------------------------

Perhaps this is simply lack of documentation in the ES1869 datasheet,
but there are additional registers not listed.

0xA0               Unknown (only 4 bits are changeable)
0xA3               Unknown (all 8 bits changeable)
0xA6               Left (master? PCM?) volume
0xA7               Right (master? PCM?) volume
0xA8               Unknown (but bit 0 appears to enable/disable audio output)
0xA9               Unknown (all 8 bits changeable)
0xAA               Master volume? (also changed when you write 0xAB)
0xAB               Master volume? (writing this also changes 0xAA)
0xAC               Unknown (all 8 bits changeable)
0xAD               Unknown (all 8 bits changeable)
0xAE               Unknown (all 8 bits changeable)
0xAF               Unknown (all 8 bits changeable)

0xB0               Unknown (always reads 0xB0, writes change register 0xA0 instead)
0xB3               Unknown (only bit 0 is changeable)

ESS 1869 undocumented registers (as seen on a Compaq branded ESS 1887)
----------------------------------------------------------------------

0xA0               Unknown (only 2:0 bits are changeable)
0xA3               Unknown (all 8 bits changeable)
0xA6               Zero (not changeable)
0xA7               Zero (not changeable)
0xA8               This actually is documented, but some weird behavior observed
                     with bits 1:0. In the datasheet, bit 0 is a mono/stereo
                     select. Actual behavior with 1:0:

                     00 = only one audio channel played
                     01 = normal stereo playback
                     02 = chip output is difference between L-R rather than sum.
                          perhaps a good way to hear the Dobly "surround" channel of movie audio,
                          or to filter out the vocals of most music, or to hear just how destructive
                          your MP3 encoder is to audio you "can't hear".
                     03 = normal stereo playback
0xA9               Unknown, bits 6:4 and 2:0 are writable, bits 3 and 7 have a mind of their own
0xAA-0xAF          Zero (not changeable)
0xB0               Unknown (always reads 0xB0, writes change register 0xA0 instead)
0xB3               Unknown (only bit 0 is changeable)

ESS sample & filter clock divider behavior
------------------------------------------

This isn't mentioned in ESS's datasheets, but if you set the sample rate
divider to 0xFF (or 0x7F) the DAC stops (does not cycle samples) and will
stay that way until you enter another divider. It doesn't appear to harm
the chip in any way.

Note that 0x00 is also a valid clock divider (in which case the DAC just
plays the audio really slow).

The divider for their lowpass filter appears to have the same behavior.
Setting the divider to 0x00 turns the audio into a very low bandwidth
signal (as you'd expect) while 0xFF silences output entirely.

