Written for the PC-GPE by Mark Feldman
e-mail address : [email protected]
[email protected]
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ THIS FILE MAY NOT BE DISTRIBUTED
³
³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Disclaimer ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
I assume no responsibility whatsoever for any effect that this file,
the
information contained therein or the use thereof has on you, your sanity,
computer, spouse, children, pets or anything else related to you or
your
existance. No warranty is provided nor implied with this information.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Introduction ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The SoundBlaster is capable of both FM and digitised sounds. The FM
wave
is fully Adlib compatible, so check the ADLIB.TXT file for info
on how to program it. This file will concentrate on recording and playback
of digital samples through the SoundBlaster CT-DSP 1321 chip.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ The SoundBlaster DSP I/O Ports ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The DSP (Digital Sound Processor) chip is programmed through 4 ports
which
are determined by the SoundBlaster base address jumper setting:
RESET 2x6h
READ DATA 2xAh
WRITE COMMAND/DATA output
WRITE BUFFER STATUS input 2xCh
DATA AVAILABLE 2xEh
where x = 1 for base address jumper setting 210h
x = 2 for base address jumper setting
220h
.
.
x = 6 for base address jumper setting
260h
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Resetting the DSP ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
You have to reset the DSP before you program it. This is done with the
following procedure :
1) Write a 1 to the SoundBlaster RESET port (2x6h)
2) Wait for 3 micro-seconds
3) Write a 0 to the SoundBlaster RESET port (2x6h)
4) Read the byte from the DATA AVAILABLE (2xEh) port until bit 7 =
1
5) Poll for a ready byte (AAh) from the READ DATA port (2xAh). Before
reading the READ DATA port it is avdvisable.
The DSP usually takes somewhere around 100 micro-seconds to reset itself.
If it fails to do within a reasonable time (say 200 micro-seconds)
then
an error has occurred, possibly an incorrect I/O address is being used.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Writing to the DSP ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
A value can be written to the DSP with the following procedure :
1) Read the DSP's WRITE BUFFER STATUS port (2xCh) until bit 7 = 0
2) Write the value to the WRITE COMMAND/DATA port (2xCh)
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Reading the DSP ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
A value can be read from the DSP with the following procedure :
1) Read the DSP's DATA AVAILABLE port (2xEh) until bit 7 = 1
2) Read the data from the READ DATA port (2xAh)
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Turning the speaker on and controlling DMA ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
Speaker and DMA control are handled by writing one of the following
bytes
to the DSP:
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ Value Description ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ D0h DMA Stop
³
³ D1h Turn speaker on ³
³ D3h Turn speaker off ³
³ D4h DMA Continue ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
DMA is discussed below. The DMA commands shown here can be used to pause
the sample during DMA playback playback.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Writing to the DAC ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The DAC (Digital to Analog Converter) is the part of the card which
converts
a sample number (ie 0 -> 255) to a sound level. To generate a square
sound
wave at maximum volume (for example) you could alternate writing 0's
and
255's to the DAC.
Programming the DAC in direct mode involves the main program setting
the
DAC to a desired value. Only 8 bit DAC is available in direct mode.
To set
the DAC level you write the value 10h to the DSP followed by the sample
number (0 -> 255). Note that no sound will be heard unless the speaker
has
been turned on. In direct mode the main program is responsible for
the
timing between samples, the DAC can output sound samples as fast as
the
calling program can change it. Typically the timer interrupt is reprogrammed
and used to generate the timing required for a sample playback. Info
on
programming the PIT chip can be found in the PIT.TXT file.
The DAC can also be programmed to accept values sent to it via the DMA
chip. Draeden has written an excellent article on programming the DMA
chip
(see DMA_VLA.TXT) so only a brief example of it's use will be given
here.
The important thing to remember is that the DMA chip cannot transfer
data
which crosses between page breaks. If the data does cross page breaks
then
it will have to be split up into several transfers, with one page per
transfer.
Setting the playback frequency for the DMA transfer is done by writing
the value 40h to the DSP followed by TIME_CONSTANT, where
TIME_CONSTANT = 256 - 1000000 / frequency
There are several types of DMA transfers available. The following table
lists them:
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³DMA_TYPE_VALUE Description
Frequency Range ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 14h
8 bit
4KHz -> 23 KHz ³
³ 74h
4 bit ADPCM
4KHz -> 12 KHz ³
³ 75h
4 bit ADPCM with 4KHz -> 12 KHz
³
³
reference byte
³
³ 76h
2.6 bit ADPCM
4KHz -> 13 KHz ³
³ 77h
2.6 bit ADPCM with 4KHz -> 13 KHz
³
³
reference byte
³
³ 16h
2 bit ADPCM
4KHz -> 11 KHz ³
³ 17h
2 bit ADPCM with 4KHz -> 11 KHz
³
³
reference byte
³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ADPCM stands for Adaptive Pulse Code Modulation, a sound compression
technique where the difference between successive samples is stored
rather
than their actual values. In the modes with reference bytes, the first
byte is the actual starting value. Having modes with and without reference
bytes means you can output successive blocks without the need for a
reference byte at the start of each one.
The procedure for doing a DMA transfer is as follows:
1) Load the sound data into memory
2) Set up the DMA chip for the tranfer
3) Set the DSP TIME_CONSTANT to the sampling rate
4) Write DMA_TYPE_VALUE value to the DSP
5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
DATA_LENGTH = number of bytes to send - 1
Note that the DMA chip must be programmed before the BSP.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Reading from the ADC ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
Reading samples from the ADC (Analog to Digital Converter) can also
be
done in either direct or DMA mode.
To read a sample in direct mode write the value 20h to the DSP and then
read the value from the DSP. Simple as that!
To set up the DSP for a DMA transfer, follow this procedure :
1) Get a memory buffer ready to hold the sample
2) Set up the DMA chip for the transfer
3) Set the DSP TIME_CONSTANT to the sampling rate
4) Write the value 24h to the DSP
5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
DATA_LENGTH = number of bytes to read - 1
Note that the DMA chip must be programmed before the BSP.
DMA reads only support 8 bit mode, compressed modes are done by software
and
stored in the voc file. I haven't tried to figure out how the compression
is
done. If someone does figure it out I'd like to know about it!
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Programming the DMA Chip ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
As mentioned before, Draeden has written a very good article on the
dma
chip, but here is a brief run down on what you would need to do to
program
the DMA channel 1 for the DSP in real mode:
1) Calculate the 20 bit address of the memory buffer you are using
where Base Address = Segment * 16 + Offset
eg 1234h:5678h = 179B8h
2) Send the value 05h to port 0Ah (mask off channel 1)
3) Send the value 00h to port 0Ch (clear the internal DMA flip/flop)
4) Send the value 49h to port 0Bh (for playback) or
45h to port 0Bh (for recording)
5) Write the LSB (bits 0 -> 7) of the 20 bit memory address to port
02h
6) Write the MSB (bits 8 -> 15) of the 20 bit memory address to ort
02h
7) Write the Page (bits 16 -> 19) of the 20 bit memory address to port
83h
8) Send the LSB of DATA_LENGTH to port 03h
9) Send the MSB of DATA_LENGTH to port 03h
10) Send the value 01h to port 0Ah (enable channel 1)
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ End of DMA Interrupt ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
When a DMA transfer is complete an interrupt is generated. The actual
interrupt number depends on the SoundBlaster card's IRQ jumper setting:
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ IRQ Jumper
³
³ Setting Interrupt ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 2
0Ah ³
³ 3
0Bh ³
³ 5
0Dh ³
³ 7
0Fh ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
To service one of these interrupts you must perform these 3 tasks:
1) Acknowledge the DSP interrupt by reading the DATA AVAILABLE port
(2xEh)
once.
2) If there are more blocks to transfer then set them up
3) Output value 20h (EOI) to the interrupt controller port 20h
Of course, as with any hardware interrupt you must also leave the
state of the system (registers etc..) the way it was when the interrupt
was called.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ A Simple DSP Pascal Unit ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
{
DSP.PAS - A demo SoundBlaster DSP unit for real mode
By Mark Feldman
}
Unit DSP;
Interface
{ ResetDSP returns true if reset was successful
base should be 1 for base address 210h, 2 for 220h etc... }
function ResetDSP(base : word) : boolean;
{ Write DAC sets the speaker output level }
procedure WriteDAC(level : byte);
{ ReadDAC reads the microphone input level }
function ReadDAC : byte;
{ SpeakerOn connects the DAC to the speaker }
function SpeakerOn: byte;
{ SpeakerOff disconnects the DAC from the speaker,
but does not affect the DAC operation }
function SpeakerOff: byte;
{ Functions to pause DMA playback }
procedure DMAStop;
procedure DMAContinue;
{ Playback plays a sample of a given size back at a given frequency
using
DMA channel 1. The sample must not cross a page boundry }
procedure Playback(sound : Pointer; size : word; frequency : word);
Implementation
Uses Crt;
var DSP_RESET : word;
DSP_READ_DATA : word;
DSP_WRITE_DATA : word;
DSP_WRITE_STATUS : word;
DSP_DATA_AVAIL : word;
function ResetDSP(base : word) : boolean;
begin
base := base * $10;
{ Calculate the port addresses }
DSP_RESET := base + $206;
DSP_READ_DATA := base + $20A;
DSP_WRITE_DATA := base + $20C;
DSP_WRITE_STATUS := base + $20C;
DSP_DATA_AVAIL := base + $20E;
{ Reset the DSP, and give some nice long delays just to be safe
}
Port[DSP_RESET] := 1;
Delay(10);
Port[DSP_RESET] := 0;
Delay(10);
if (Port[DSP_DATA_AVAIL] And $80 = $80) And
(Port[DSP_READ_DATA] = $AA) then
ResetDSP := true
else
ResetDSP := false;
end;
procedure WriteDSP(value : byte);
begin
while Port[DSP_WRITE_STATUS] And $80 <> 0 do;
Port[DSP_WRITE_DATA] := value;
end;
function ReadDSP : byte;
begin
while Port[DSP_DATA_AVAIL] and $80 = 0 do;
ReadDSP := Port[DSP_READ_DATA];
end;
procedure WriteDAC(level : byte);
begin
WriteDSP($10);
WriteDSP(level);
end;
function ReadDAC : byte;
begin
WriteDSP($20);
ReadDAC := ReadDSP;
end;
function SpeakerOn: byte;
begin
WriteDSP($D1);
end;
function SpeakerOff: byte;
begin
WriteDSP($D3);
end;
procedure DMAContinue;
begin
WriteDSP($D4);
end;
procedure DMAStop;
begin
WriteDSP($D0);
end;
procedure Playback(sound : Pointer; size : word; frequency : word);
var time_constant : word;
page, offset : word;
begin
SpeakerOn;
size := size - 1;
{ Set up the DMA chip }
offset := Seg(sound^) Shl 4 + Ofs(sound^);
page := (Seg(sound^) + Ofs(sound^) shr 4) shr 12;
Port[$0A] := 5;
Port[$0C] := 0;
Port[$0B] := $49;
Port[$02] := Lo(offset);
Port[$02] := Hi(offset);
Port[$83] := page;
Port[$03] := Lo(size);
Port[$03] := Hi(size);
Port[$0A] := 1;
{ Set the playback frequency }
time_constant := 256 - 1000000 div frequency;
WriteDSP($40);
WriteDSP(time_constant);
{ Set the playback type (8-bit) }
WriteDSP($14);
WriteDSP(Lo(size));
WriteDSP(Hi(size));
end;
end.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ References ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
Title : The SoundBlaster Developpers Kit
Publishers : Creative Labs Inc
Creative Technology PTE LTD
Title : Sound Blaster - The Official Book
Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge
Publishers : Osborne/McGraw Hill
ISBN : 0-07-881907-5
Some of the information in this file was either obtained from or verified
by the source code in a public domain library called SOUNDX by Peter
Sprenger. I haven't tried using his library yet (I don't have a C compiler
at the moment) but it looks very well done and contains numerous sound
card
detection routines. Says Peter : "It would be nice, that when you make
something commercial with my routines, that you send me a copy of your
project or send me some bucks, just enough for pizza and coke to support
my
night programming sessions. If you send me nothing, ok. But USE the
stuff,
if you can need it!". Heh...a REAL programmer!
ftpsite: ftp.uwp.edu
directory: /pub/msdos/demos/programming/game-dev/source
filename: soundx.zip
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ Sound Familiar? ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
What the...why is there a faint glimmer of sunlight outside? HOLY $#!^!!
It's
5:30am! I'm goin' to bed!