Sound Blaster 16: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(34 intermediate revisions by 8 users not shown)
Line 1:
{{In Progress}}
 
The Sound Blaster series is a family of sound cards made by Creative. For many years they were the standard audio cards on IBM PC's.
 
Line 12 ⟶ 10:
! Port
! Description
|-
| 0x224 || DSP Mixer port
|-
| 0x225 || DSP Mixer data port
|-
| 0x226 || DSP Reset
Line 17 ⟶ 19:
| 0x22A || DSP Read
|-
| 0x22C || DSP Write (Read this port for Write Status)
|-
| 0x22E || DSP Read Status (Read this port to acknowledge 8-bit interrupt)
Line 26 ⟶ 28:
 
{| {{wikitable}}
! Command for DSP Write
! Description
! Output/input for command
|-
| 0x410x40 || Set Outputtime Sampleconstant Rate|| 8 bit value
|-
| 0x41 || Set Output Sample Rate || high bit/low bit
| 0xB6 || Auto transfer mode
|-
| 0xD50xD1 || StopTurn playingspeaker on ||
|-
| 0xE10xD3 || GetTurn DSPspeaker versionoff ||
|-
| 0xD0 || Stop playing 8 bit channel ||
|-
| 0xD4 || Resume playback of 8 bit channel ||
|-
| 0xD5 || Stop playing 16 bit channel ||
|-
| 0xD6 || Resume playback of 16 bit channel ||
|-
| 0xE1 || Get DSP version || major version/minor version
|-
|}
 
{| {{wikitable}}
When the samples have been played, an interrupt will be fired, and the OS/Driver will have the chance to refill the buffer, or to issue a Stop command.
! Command for Mixer port
! Description
! Mixer data port
|-
| 0x22 || Master volume || 0xLR L=left volume R=right volume min=0x0 max=0xF (default value is 0xCC or 0x11)
|-
| 0x80 || Set IRQ || See below
|-
|}
 
There are two modes for transfering data. First is single mode - data from buffer are played, interrupt is fired and playing is stopped. It make lower quality of sound. Second is auto mode - data from buffer are playing forever and interrupt is fired after play buffer. You should use interrupt for re-filling buffer.
Because you only have a single DMA buffer to transfer data, it is recommended that you issue the Play PCM command with a sample count of half of the data buffer. This will fire an interrupt when the buffer is half played, allowing you to refill the segment that was just played, while the DSP continues playing the other half, and so on.
 
==Operations==
===Reading and writing===
Until you write to the DSP write port, check the DSP write port for 0x00. Until reading the DSP read port, check the DSP status port for 0x80.
 
==Detecting=Reseting DSP (detecting DSP)===
# Send 1 to DSP reset port
Detecting DSP is really easy. You must send to DSP reset port 1, wait 3 microseconds, send to DSP reset 0 and read DSP read port. If in it is 0xAA, DSP exist. Some SB-compatible cards returned 0xAA on first check but on second check they reported their specific version.
# Wait 3 microseconds
# Send 0 to DSP reset port
# Now should be in DSP read port 0xAA.
Some SB-compatible cards returned 0xAA on first check but on second check they reported their specific version.
 
==Playing=Setting soundIRQ===
# Send 0x80 to Mixer port
# Detect DSP
# Send value of your IRQ to Mixer data port
# Load sound data to memory
0x01=IRQ 2 0x02=IRQ 5 0x04=IRQ 7 0x08=IRQ 10 Usually is used IRQ 5. You can read this port too for get actual IRQ.
# Program ISA DMA
# Set output sample rate(0x40/frequency)
# Write DMA transfer type to DSP(command)
# Write data lenght to DSP(Low byte/High byte)
 
===Programming DMA===
You can get more info about programming DMA on page [http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html] .
 
Programming 8 bit transfers throught channel 1 (channel number is 1):
# Disable channel by writing to port 0x0A value 0x05 (channel number + 0x04)
# Write value to flip-flop port 0x0C (any value e.g. 1)
# Send transfer mode to 0x0B (0x48 for single mode/0x58 for auto mode + channel number)
# Send page number to 0x83(page port of channel 1) For example if you have sound data at 0x100450, page is 0x10.
# Send low bits of position to port 0x02(addr. port of channel 1) For example(see above) is 0x50.
# Send high bits of position to port 0x02(addr. port of channel 1) For example(see above) is 0x04.
# Send low bits of length of data to port 0x03(count port of channel 1) For example if is length 0x0FFF, send 0xFF
# Send high bits of length of data to port 0x03(count port of channel 1) For example if is length 0x0FFF, send 0x0F
# Enable channel by writing channel number to port 0x0A
 
Programming 16 bit transfers throught channel 5 (channel number is 1 too):
# Disable channel by writing to port 0xD4 value 0x05 (channel number + 0x04)
# Write value to flip-flop port 0xD8 (any value e.g. 1)
# Send transfer mode to 0xD6 (0x48 for single mode/0x58 for auto mode + channel number)
# Send page number to 0x8B(page port of channel 5) For example if you have sound data at 0x100450, page is 0x10.
# Send low bits of position to port 0xC4(addr. port of channel 5) For example(see above) is 0x50.
# Send high bits of position to port 0xC4(pos. port of channel 5) For example(see above) is 0x04.
# Send low bits of length of data to port 0xC6(count port of channel 5) For example if is length 0x0FFF, send 0xFF
# Send high bits of length of data to port 0xC6(count port of channel 5) For example if is length 0x0FFF, send 0x0F
# Enable channel by writing channel number to port 0xD4
 
===Writing transfer mode to DSP===
 
Usually values are 0xB0 for 16 bit playing sound or 0xC0 for 8 bit playing sound.
 
{| {{wikitable}}
! PortBit 7-4
! Bit 3
! Description
! Bit 2
! Bit 1
! Bit 0
|-
| 0xB=16 bit transfer 0xC=8 bit transfer || 0=playing sound 1=recording sound || 0 || 0=FIFO off 1=FIFO on || 0
| 0xC4 || Address
|-
|}
| 0xC6 || Count
 
===Writing type of sound data to DSP===
 
You must write type of sound data after write transfer mode.
 
{| {{wikitable}}
! Bit 7
! Bit 6
! Bit 5
! Bit 4
! Bit 3
! Bit 2
! Bit 1
! Bit 0
|-
| 0 || 0 || 0=mono 1=stereo || 0=unsigned 1=signed || 0 || 0 || 0 || 0
| 0x8B || Page
|-
| 0xD4 || Single mask
|-
| 0xD6 || Transfer mode
|-
| 0xD8 || Clear pointer
|-
|}
 
==Playing sound==
# Reset DSP
# Load sound data to memory
# Set master volume
# Turn speaker on
# Program ISA DMA to transfer
# Set time constant. Notice that the Sound Blaster 16 is able to use sample rates instead of time constants using command 0x41 instead of 0x40. <br> You can calculate the time constant like this: Time constant = 65536 - (256000000 / (channels * sampling rate))
# Set output sample rate
# Write transfer mode to DSP
# Write type of sound data
# Write data length to DSP(Low byte/High byte) (You must calculate LENGTH-1 e.g. if is your real length 0x0FFF, you must send 0xFE and 0x0F)
 
==Code==
<sourcesyntaxhighlight lang="asm">
%macro OUTB 2
mov dx, %1
Line 99 ⟶ 172:
int 15h ;wait
OUTB 0x226, 0 ;reset port
 
;turn speaker on
OUTB 0x22C, 0xD1
 
;DMA channel 1
Line 114 ⟶ 190:
OUTB 0x22C, 0x40 ;set time constant
OUTB 0x22C, 165 ;10989 Hz
OUTB 0x22C, 0x140xC0 ;mode DAC 8 bit sound
OUTB 0x22C, 0xFE0x00 ;COUNTmono LOWand BITunsigned (EXAMPLEsound 0x0FFF) - SET THIS VALUE FOR YOUdata
OUTB 0x22C, 0x0F0xFE ;COUNT HIGHLOW BIT - COUNT LENGTH-1 (EXAMPLE 0x0FFF SO 0x0FFE) - SET THIS VALUE FOR YOU
OUTB 0x22C, 0x0F ;COUNT HIGH BIT - COUNT LENGTH-1 (EXAMPLE 0x0FFF SO 0x0FFE) - SET THIS VALUE FOR YOU
 
;now transfer start - don't forget to handle irq
</syntaxhighlight>
 
==QEMU support==
QEMU is one of the few hypervisors/emulators that support this sound card.
To run QEMU with Sound Blaster 16 emulation, use the <code>-soundhw sb16</code> option.
 
'''Warning''': recent versions of QEMU (>= 4.0) have a broken support for
this sound card. See bug: [https://bugs.launchpad.net/qemu/+bug/1873769].
Briefly, when QEMU's GTK UI is used and audio is playing, you'll experience
the QEMU window freezing. In addition, there will be flickering in the audio
as well.
 
===Workarounds===
 
# Use an older version of QEMU. With QEMU 2.11 the problem simply does not exist.
;now transfer start - dont forget to handle irq
# Use [https://virt-manager.org virt-manager] which connects to QEMU using Spice. The problem does not exist in this case because QEMU's GTK UI is not used. BUT, configuring QEMU to emulate Sound Blaster 16 through virt-manager requires some tricky settings:
</source>
## Add any sound card to the VM
## In virt-manager's Edit -> Preferences menu check the "Enable XML editing" box.
## Open VM's hardware and after selecting the sound card, click on the XML tab and replace its contents with:<syntaxhighlight lang="xml"><sound model="sb16"/></syntaxhighlight>
# Run the OS using QEMU's <code>-curses</code> option or use QEMU's <code>-kernel</code> and <code>-nographic</code> (serial console): in this case, there will be no "freeze", but there still be some flickering in the audio.
 
==See Also==