Sound Blaster 16: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (Reverted edits by Klakap (talk) to last revision by Alliumnsk)
m (Reverted edits by Dennis95 (talk) to last revision by Klakap)
Line 1: 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.
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: Line 10:
! Port
! Port
! Description
! Description
|-
| 0x224 || DSP Mixer port
|-
| 0x225 || DSP Mixer data port
|-
|-
| 0x226 || DSP Reset
| 0x226 || DSP Reset
Line 17: Line 19:
| 0x22A || DSP Read
| 0x22A || DSP Read
|-
|-
| 0x22C || DSP Write (Read this port for Write Status)
| 0x22C || DSP Write
|-
|-
| 0x22E || DSP Read Status (Read this port to acknowledge 8-bit interrupt)
| 0x22E || DSP Read Status (Read this port to acknowledge 8-bit interrupt)
Line 26: Line 28:


{| {{wikitable}}
{| {{wikitable}}
! Command
! Command for DSP Write
! Description
! Description
! Output/input for command
|-
|-
| 0x41 || Set Output Sample Rate
| 0x40 || Set time constant || 8 bit value
|-
|-
| 0x41 || Set Output Sample Rate || high bit/low bit
| 0xB6 || Auto transfer mode
|-
|-
| 0xD5 || Stop playing
| 0xD1 || Turn speaker on ||
|-
|-
| 0xE1 || Get DSP version
| 0xD3 || Turn speaker off ||
|-
| 0xD0 || Stop playing 8 bit channel ||
|-
| 0xD5 || Stop playing 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 DSP==
===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 sound==
===Setting IRQ===
# 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(command/High byte/Low byte)
# Write DMA transfer type to DSP(command)
# Write data lenght to DSP(Low byte/High byte)


===Programming DMA===
===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 lenght of data to port 0x03(count port of channel 1) For example if is lenght 0x0FFF, send 0xFF
# Send high bits of lenght of data to port 0x03(count port of channel 1) For example if is lenght 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 lenght of data to port 0xC6(count port of channel 5) For example if is lenght 0x0FFF, send 0xFF
# Send high bits of lenght of data to port 0xC6(count port of channel 5) For example if is lenght 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}}
{| {{wikitable}}
! Port
! Bit 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
# Set output sample rate
# Write transfer mode to DSP
# Write type of sound data
# Write data lenght to DSP(Low byte/High byte) (You must calculate LENGHT-1 e.g. if is your real lenght 0x0FFF, you must send 0xFE and 0x0F)


==Code==
==Code==
<source lang="C">
<source lang="asm">
%macro OUTB 2
//Digital Sound Processor ports
mov dx, %1
#define DSP_RESET 0x226
mov al, %2
#define DSP_READ 0x22A
out dx, al
#define DSP_WRITE 0x22C
%endmacro
#define DSP_BUFFER 0x22A

#define DSP_STATUS 0x22E
%macro INB 1
#define DSP_INTERRUPT 0x22F
mov dx, %1
in al, dx
%endmacro


//Digital Sound Processor commands
#define DSP_CMD_OUTPUT_RATE 0x41
#define DSP_CMD_TRANSFER_MODE 0xB6
#define DSP_CMD_STOP 0xD5
#define DSP_CMD_VERSION 0xE1


;SOUND BLASTER 16 driver in real mode
//DMA ports
#define DMA_ADDRES 0xC4
#define DMA_COUNT 0xC6
#define DMA_PAGE 0x8B
#define DMA_SINGLE_MASK 0xD4
#define DMA_TRANSFER_MODE 0xD6
#define DMA_CLEAR_POINTER 0xD8


;reset sound blaster
void reset_DSP(void) {
OUTB 0x226, 1 ;reset port
outb(DSP_RESET, 1);
mov ah, 86h
sleep(3); //wait 3 microseconds
mov cx, 0x0000
outb(DSP_RESET, 0);
mov dx, 0xFFFF
int 15h ;wait
if(read_DSP()==0xAA) {
OUTB 0x226, 0 ;reset port
sound_blaster=TRUE;
}
}


;turn speaker on
void sb16_init(void) {
OUTB 0x22C, 0xD1
reset_DSP();


;DMA channel 1
//if DSP doesnt exist
OUTB 0x0A, 5 ;disable channel 1 (number of channel + 0x04)
if(sound_blaster==FALSE) {
OUTB 0x0C, 1 ;flip flop
return;
OUTB 0x0B, 0x49 ;transfer mode
}
OUTB 0x83, 0x01 ;PAGE TRANSFER (EXAMPLE POSITION IN MEMORY 0x[01]0F04) - SET THIS VALUE FOR YOU
OUTB 0x02, 0x04 ;POSITION LOW BIT (EXAMPLE POSITION IN MEMORY 0x010F[04]) - SET THIS VALUE FOR YOU
OUTB 0x02, 0x0F ;POSITON HIGH BIT (EXAMPLE POSITION IN MEMORY 0x01[0F]04) - SET THIS VALUE FOR YOU
OUTB 0x03, 0xFF ;COUNT LOW BIT (EXAMPLE 0x0FFF) - SET THIS VALUE FOR YOU
OUTB 0x03, 0x0F ;COUNT HIGH BIT (EXAMPLE 0x0FFF) - SET THIS VALUE FOR YOU
OUTB 0x0A, 1 ;enable channel 1


;program sound blaster 16
//get DSP version
OUTB 0x22C, 0x40 ;set time constant
write_DSP(DSP_CMD_VERSION);
OUTB 0x22C, 165 ;10989 Hz
sb16_version_major=read_DSP();
OUTB 0x22C, 0xC0 ;8 bit sound
sb16_version_minor=read_DSP();
OUTB 0x22C, 0x00 ;mono and unsigned sound data
OUTB 0x22C, 0xFE ;COUNT LOW BIT - COUNT LENGHT-1 (EXAMPLE 0x0FFF SO 0x0FFE) - SET THIS VALUE FOR YOU
OUTB 0x22C, 0x0F ;COUNT HIGH BIT - COUNT LENGHT-1 (EXAMPLE 0x0FFF SO 0x0FFE) - SET THIS VALUE FOR YOU


;now transfer start - dont forget to handle irq
}
</source>
</source>



Revision as of 21:36, 21 May 2020

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.

Introduction

The Sound Blaster 16 is the successor to the Sound Blaster Pro audio card found in many older computers. It was first brought out in 1992. The main improvement over the Pro is its 16-bit digital audio sampling (hence the name). Most SB16 cards are PCI compatible, as Creative made this improvement shortly after releasing the card, upgrading from ISA.

Digital Signal Processor

The DSP built into the Sound Blaster 16 supports playing and recording audio in 8-bit and 16-bit PCM encoded samples, along with playing several other formats (ADPCM, etc.). The base I/O register address can be found using the PCI bus for PCI models, or by detecting the presence of an older ISA Sound Blaster by issuing a Get Version command to one of several common I/O port addresses (0x220, 0x240, etc.) and waiting for a response.

Port Description
0x224 DSP Mixer port
0x225 DSP Mixer data port
0x226 DSP Reset
0x22A DSP Read
0x22C DSP Write
0x22E DSP Read Status (Read this port to acknowledge 8-bit interrupt)
0x22F DSP 16-bit Interrupt Acknowledge (Read this port to acknowledge 16-bit interrupt) (DSP Version 4.0+ Only)
Command for DSP Write Description Output/input for command
0x40 Set time constant 8 bit value
0x41 Set Output Sample Rate high bit/low bit
0xD1 Turn speaker on
0xD3 Turn speaker off
0xD0 Stop playing 8 bit channel
0xD5 Stop playing 16 bit channel
0xE1 Get DSP version major version/minor version
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.

Operations

Reseting DSP (detecting DSP)

  1. Send 1 to DSP reset port
  2. Wait 3 microseconds
  3. Send 0 to DSP reset port
  4. 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.

Setting IRQ

  1. Send 0x80 to Mixer port
  2. Send value of your IRQ to Mixer data port

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.

Programming DMA

You can get more info about programming DMA on page [1] .

Programming 8 bit transfers throught channel 1 (channel number is 1):

  1. Disable channel by writing to port 0x0A value 0x05 (channel number + 0x04)
  2. Write value to flip-flop port 0x0C (any value e.g. 1)
  3. Send transfer mode to 0x0B (0x48 for single mode/0x58 for auto mode + channel number)
  4. Send page number to 0x83(page port of channel 1) For example if you have sound data at 0x100450, page is 0x10.
  5. Send low bits of position to port 0x02(addr. port of channel 1) For example(see above) is 0x50.
  6. Send high bits of position to port 0x02(addr. port of channel 1) For example(see above) is 0x04.
  7. Send low bits of lenght of data to port 0x03(count port of channel 1) For example if is lenght 0x0FFF, send 0xFF
  8. Send high bits of lenght of data to port 0x03(count port of channel 1) For example if is lenght 0x0FFF, send 0x0F
  9. Enable channel by writing channel number to port 0x0A

Programming 16 bit transfers throught channel 5 (channel number is 1 too):

  1. Disable channel by writing to port 0xD4 value 0x05 (channel number + 0x04)
  2. Write value to flip-flop port 0xD8 (any value e.g. 1)
  3. Send transfer mode to 0xD6 (0x48 for single mode/0x58 for auto mode + channel number)
  4. Send page number to 0x8B(page port of channel 5) For example if you have sound data at 0x100450, page is 0x10.
  5. Send low bits of position to port 0xC4(addr. port of channel 5) For example(see above) is 0x50.
  6. Send high bits of position to port 0xC4(pos. port of channel 5) For example(see above) is 0x04.
  7. Send low bits of lenght of data to port 0xC6(count port of channel 5) For example if is lenght 0x0FFF, send 0xFF
  8. Send high bits of lenght of data to port 0xC6(count port of channel 5) For example if is lenght 0x0FFF, send 0x0F
  9. 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.

Bit 7-4 Bit 3 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

Writing type of sound data to DSP

You must write type of sound data after write transfer mode.

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

Playing sound

  1. Reset DSP
  2. Load sound data to memory
  3. Set master volume
  4. Turn speaker on
  5. Program ISA DMA to transfer
  6. Set time constant
  7. Set output sample rate
  8. Write transfer mode to DSP
  9. Write type of sound data
  10. Write data lenght to DSP(Low byte/High byte) (You must calculate LENGHT-1 e.g. if is your real lenght 0x0FFF, you must send 0xFE and 0x0F)

Code

  %macro OUTB 2
    mov dx, %1
    mov al, %2
    out dx, al
  %endmacro

  %macro INB 1
    mov dx, %1
    in al, dx
  %endmacro


  ;SOUND BLASTER 16 driver in real mode

  ;reset sound blaster
  OUTB 0x226, 1 ;reset port
  mov ah, 86h
  mov cx, 0x0000
  mov dx, 0xFFFF
  int 15h ;wait
  OUTB 0x226, 0 ;reset port

  ;turn speaker on
  OUTB 0x22C, 0xD1

  ;DMA channel 1
  OUTB 0x0A, 5 ;disable channel 1 (number of channel + 0x04)
  OUTB 0x0C, 1 ;flip flop
  OUTB 0x0B, 0x49 ;transfer mode
  OUTB 0x83, 0x01 ;PAGE TRANSFER (EXAMPLE POSITION IN MEMORY 0x[01]0F04) - SET THIS VALUE FOR YOU
  OUTB 0x02, 0x04 ;POSITION LOW BIT (EXAMPLE POSITION IN MEMORY 0x010F[04]) - SET THIS VALUE FOR YOU
  OUTB 0x02, 0x0F ;POSITON HIGH BIT (EXAMPLE POSITION IN MEMORY 0x01[0F]04) - SET THIS VALUE FOR YOU
  OUTB 0x03, 0xFF ;COUNT LOW BIT (EXAMPLE 0x0FFF) - SET THIS VALUE FOR YOU
  OUTB 0x03, 0x0F ;COUNT HIGH BIT (EXAMPLE 0x0FFF) - SET THIS VALUE FOR YOU
  OUTB 0x0A, 1 ;enable channel 1

  ;program sound blaster 16
  OUTB 0x22C, 0x40 ;set time constant
  OUTB 0x22C, 165 ;10989 Hz
  OUTB 0x22C, 0xC0 ;8 bit sound
  OUTB 0x22C, 0x00 ;mono and unsigned sound data
  OUTB 0x22C, 0xFE ;COUNT LOW BIT - COUNT LENGHT-1 (EXAMPLE 0x0FFF SO 0x0FFE) - SET THIS VALUE FOR YOU
  OUTB 0x22C, 0x0F ;COUNT HIGH BIT - COUNT LENGHT-1 (EXAMPLE 0x0FFF SO 0x0FFE) - SET THIS VALUE FOR YOU

  ;now transfer start - dont forget to handle irq

See Also

External Links