The Sound Blaster can play samples (voice) in two modes: direct and DMA. If you use
the first mode you will use a lot of processor time, but is the simplest to use. The second mode
allow the main processor to do other things until the dedicated processor (the DMA) copies the data
to the Sound Blaster. But this mode is limited by the old DMA processor, that can transfer data only
from (or to) the real memory area (first MB). Si it requires a buffer in the conventional memory
and can transfer only up to 64Kb at time. The only way to play samples longest more than 64Kb is
to divide the samples in blocks of 64Kb or less, and the Sound Blaster will help us by issuing an
interrupt each time a DMA transfer stops. Another limitation is that the buffer musn't cross the
64Kb page boundries.
The procedure for doing a DMA transfer is:
- Load the sound data into memory
- Set the
DSP TIME_CONSTANT
to the sampling rate
- Set up the DMA chip for the tranfer
- Write
DMA_TYPE_VALUE
value to the DSP
- Write
DATA_LENGTH
to the DSP (2 bytes, LSB first) where DATA_LENGTH
= number of bytes to send - 1
- Repeat steps 3, 4, 5 to play all the sample
The DSP_TIME_CONSTANT
sets the frequency of reproduction, where
(BYTE)TIME_CONSTANT = 256 - 1000000 / frequency
This method allow a sampling rate of max 22222 Hz (Normal Mode). With SB 2.0 or above, we can
have a higher frequency, using High Speed mode. The TIME_COSTANT
will be computed
in this way:
(WORD)TIME_CONSTANT = 65535 - 256000000 / frequency
The result is a WORD, but we'll send only the MSB to the DSP. The code of the function to set
the sampling rate will be:
// Sets the Time Costant
// 'frequency'(in): the sampling rate
// 'return'(out): result code
PRIVATE BOOL driver_set_time_costant(WORD frequency)
{
if((frequency < driver_capability.min_mono_8) ||
(frequency > driver_capability.max_mono_8)) return(SB_SAMPLE_RATE);
if(frequency > 23 * 1024)
{
WORD time_costant;
time_costant = 65536 - 256000000 / frequency;
sb_dsp_write(SB_TIME_COSTANT);
sb_dsp_write(time_costant >> 8);
driver_use_high_speed = TRUE;
} else {
BYTE time_costant;
time_costant = 256 - 1000000 / frequency;
sb_dsp_write(SB_TIME_COSTANT);
sb_dsp_write(time_costant);
driver_use_high_speed = FALSE;
}
return(SB_OK);
}
We can program the DMA chip in this way (assuming that the Sound Blaster use DMA channel 1):
- Calculate the 20 bit address of the memory buffer you are using where Base Address = Segment * 16 + Offset
- Send the value 05h to port 0Ah (mask off channel 1)
- Send the value 00h to port 0Ch (clear the internal DMA flip/flop)
- Send the value 49h to port 0Bh (for playback) or 45h to port 0Bh (for recording)
- Write the LSB (bits 0 -> 7) of the 20 bit memory address to port 02h
- Write the MSB (bits 8 -> 15) of the 20 bit memory address to ort 02h
- Write the Page (bits 16 -> 19) of the 20 bit memory address to port 83h
- Send the LSB of DATA_LENGTH to port 03h
- Send the MSB of DATA_LENGTH to port 03h
- Send the value 01h to port 0Ah (enable channel 1)
But with Sound Blaster 2.0 or better, is possible to use an Auto Initialized DMA mode. The difference
is that both DMA controller and DSP will automagically reinitialize at the end of the buffer transfer.
This permit to avoid the presence of a noise (a 'click'), produced by the sound card at the end of
the transfer of a buffer, before starting to transfer the new.
This is all for now. I will write more when I've the time. Remeber to see the
demo program that play WAV files (but only 8 bits, mono not compressed).