Soundcard Device Specification

Memory Layout

Byte Mode Name Description
00 RW Control Controll register, write to initiate soundcard operations
01RW DMA No 0Number of buffer to play
02 RW DMA No 1 Number of buffer to play
03 RW Data Format Data Format (see below)
04 RW Channels Number of channels
05 RW Bits per Sample Number of bits per sample
06-07 RW Samplerate Number of Samples per channel per second
08-09 R Unused
0A R Loaded The number of the buffer that just finished loading
0B R Playing The number of the buffer that is currently playing
0C-0F R Position Current position in the buffer just playing
10-17RW DMA1.addressphysical address of first buffer where the next transfer takes place
18-1F RW DMA1.size size of first buffer where the next transfer takes place
... RW DMA2-15 more DMA address and size registers
100-107 RW DMA16.address physical address of 16th and last buffer where the next transfer takes place
108-10F RW DMA16.size size of 16th and last buffer where the next transfer takes place

Operation

The program will contact the motherboard at [host:]port and register itself with the given address and interrupt.

The Control register is used to give commands to the sound card device.The possible command values are:

There are 16 DMA registers that specify a physical buffer address and its size. The address is a full octabyte value; it holds the physical address of the buffer. The size value must be an unsigned tetrabyte value (the hight tetra of the size register is ignored); it's the size of the buffer. Either a single buffer or two alternating buffers can be used together in a playing operation.

The Playing register contains a value from 1 to 16 indicating the DMA buffer that is currently playing. A value of zero indicates that the sond device is currently idle.

If the Plaiyng register is nonzero, the Position register indicates the current position in the buffer; it is a value beween 0 and the buffer size. Data that preceedes this position is already played, and data that follows this position will be played in the future.

The registers DMANo0 and DMANo1 specify up to two buffers to be used in the playing operation. Values between 1 and 16 indicate the buffer to be used. A DMA No register with the value zero is ignored.

Format

The sound device simulates an advanced soundcard that can play different sound formats. As for now, PCM and MP3 Formats are implemented. If the Control Byte speciefies PCM data, the format is specified in the format registers (Byte 03-07). The Data Format Byte can have one of the values specified for the format tag of the RIFF WAVE format. Currently only the Value 0x01 (PCM) is implemented.

Data Format Byte

ID Bezeichnung
0x01 PCM
0x02 MS ADPCM
0x03 IEEE FLOAT
0x05 IBM CVSD
0x06 ALAW
0x07 MULAW
0x10 OKI ADPCM
0x11 DVI/IMA ADPCM
0x12 MEDIASPACE ADPCM
0x13 SIERRA ADPCM
0x14 G723 ADPCM
0x15 DIGISTD
0x16 DIGIFIX
0x17 DIALOGIC OKI ADPCM
0x20 YAMAHA ADPCM
0x21 SONARC
0x22 DSPGROUP TRUESPEECH
0x23 ECHOSC1
0x24 AUDIOFILE AF36
0x25 APTX
0x26 AUDIOFILE AF10
0x30 DOLBY AC2
ID Bezeichnung
0x31 GSM610
0x33 ANTEX ADPCME
0x34 CONTROL RES VQLPC
0x35 CONTROL RES VQLPC
0x36 DIGIADPCM
0x37 CONTROL RES CR10
0x38 NMS VBXADPCM
0x39 CS IMAADPCM (Roland RDAC)
0x40 G721 ADPCM
0x50 MPEG-1 Layer I, II
0x55 MPEG-1 Layer III (MP3)
0x69 Xbox ADPCM
0x0200 CREATIVE ADPCM
0x0202 CREATIVE FASTSPEECH8
0x0203 CREATIVE FASTSPEECH10
0x0300 FM TOWNS SND
0x1000 OLIGSM
0x1001 OLIADPCM
0x1002 OLICELP
0x1003 OLISBC
0x1004 OLIOPR

Examples of Use

Playing Preloaded MP3 Sound

Assume that a short sound, for example a Beep available as MP3 data, needs to be played multiple times. To be specific, let's assume that the mp3 data is located at pysical address 0x100004000 and is 24800 bytes long. We choose DMA registers No 7 to play this sound.

Preparation: We store two octabytes, the address value 0x100004000 at offset 0x70 and the size value 24800 at offset 0x78, into the sound device. Then we issue a Preload command by storing the following octabyte: 0x0307000000000000 at offset 0x00 (alternatively the WYDE value 0x0307 can be stored at offset 0x00, if it is known that the value of DMA No 1 is zero). The 03 is the Preload command, the next byte selects buffer number 7. The sound device might now start to load this data into its local cache.

Playing the sound: To play the Beep sound, it is sufficient to store the following octabyte 0x0107000000000000 at offset 0x00. The first 01 is the PlayOnceMP3 command, the second 07 selects buffer 7 for playing. If the data of buffer no 7 is not yet in the local cache, the sound device will immediately start to load the buffer data. In any case, the sound device will wait until the buffer data has been loaded completely. If some sound is currently playing, playing this sound will be terminated immediately. Then the sound device will start playing the data, interpreting it as MP3 data, from buffer 7 and the Beep can be heard. Upon reaching the end of the data (as given by the size register), the soundcard will stop playing.

While the Beep is playing, reading the Playing register (the byte at offset 0x0B) will return the value 7 and reading the Position register (the octabyte at offset 0x0C) will return any value between 0 and 24800.

Playing the beep a second time just requires storing again the octabyte 0x0107000000000000 at offset 0x00. We can assume that this time the data is already in the local cache. So playing this sound repeatedly requires very little bus activity (just storing one octabyte).

Playing Preloaded PCM Sound

Assume that a short sound, for example a Click, is available as PCM data (for example from a WAV file), and it needs to be played multiple times. To be specific, let's assume that the PCM data comprises two channels of 16 bit samples at sample rate of 22050Hz, is located at pysical address 0x100008000, and is 24800 bytes long,. We choose DMA register No 2 to play this sound.

Preparation: We store two octabytes, the address value 0x100008000 at offset 0x20 and the size value 24800 at offset 0x28, into the sound device. Then, we issue a Preload command by storing the following octabyte: 0x0302000000000000 at offset 0x00 (alternatively the WYDE value 0x0302 can be stored at offset 0x00, if it is known that the value of DMA No1 is zero). The 03 is the Preload command, the next byte selects buffer number 2. The sound device might now start to load this data into its local cache.

Playing the sound: To play the Click sound, it is sufficient to store the following octabyte 0x02 02 00 01 02 10 5622 at offset 0x00. The first 02 is the PlayOncePCM command; the second 02 selects buffer 2 for playing, then next zero byte (DMA No 1) is ignored; the next 01 (Data Format) selects PCM format; then next byte 02 indicates two channel data (stereo); the next byte 10 indicated 16 bit per sample; and the final 0x5622 = 22050 is the sample rate. If the buffer data of buffer number 2 is not yet in the local cache, the sound device will immediately start load the buffer data. In any case, the sound device will wait until the buffer data has been loaded completely. If some sound is currently playing, playing this sound will be terminated immediately. Then the sound device will start playing the data, interpreting it as PCM data, from buffer 2 and the Click can be heard. Upon reaching the end of the data (as given by the size register), the soundcard will stop playing.

While the Click is playing, reading the Playing register (the byte at offset 0x0B) will return the value 7 and reading the Position register (the octabyte at offset 0x0C) will return any value between 0 and 24800.

Playing the beep a second time, requires storing again the octabyte 0x02 02 00 01 02 10 5622 at offset 0x00. We can assume that this time the data is already in the local cache. So playing this sound repeatedly requires very little bus activity (just storing one octabyte).

Playing Sound with Double Buffering

Normal sound cards usually work with double buffering, assuming that the sound cards access to main memory is fast enough to switch from one buffer to the next without causing an audible interruption in the playing of sound. Depending on the speed of the your host computer (and the virtual bus), this is a demanding real-time task. Here is how we can do it:

Assume that we want to play a large sound file, containing MP3 data, stored on the harddisk. To do so, we allocate two buffers each 16kByte long at the pysical address 0x0000000000300000 and 0x 0000000000320000. We choose DMA registers 1 and 2 to play the file.

Preparation: We initialize the two buffers with the first 2x16KByte of MP3 data from the file. We store address 0x0000000000300000 at offset 0x10 (DMA1.address) and size 0x4000 (16kByte) at offset 0x18 (DMA1.size); and we store address 0x0000000000320000 at offset 0x20 (DMA2.address) and size 0x4000 (16kByte) at offset 0x28 (DMA2.size).

An important issue here is the choice of the buffer size: The sound card simulator uses itself double buffering to supply data to the physical sound card. The buffer size is determined in such a way, that a buffer will contain sound data for about 0.2 seconds. In order for the simulated double buffering to work correctly, the (virtual) buffer size should be large enough to contain data for at least these 0.2 seconds. The sound card simulator fills its first buffer with data, starts plaing and immediately stats filling its second buffer, in order to have the data ready when the first buffer finishes playing. If the firts two virtual buffers do not contain enough data to fill these two real buffers, the sound card simulator will start reading the first virtual buffer a second time without delay after reading the second virtual buffer. It will then be impossible to refresh the data in the first virtual buffer fast enough.

Playing the sound: To start playing the sound file, we store the following octabyte 0x8501020000000000 at offset 0x00. The first 85 is the PlayLoopMP3 command combined with the BufferInterrupt command, the following 0102 selects buffers 1 and 2 for playing, and the last five zero bytes are ignored.

The soundcard will start loading 0.2 seconds worth of data from buffer 1 and then will start playing it. During this time, reading the Playing register (the byte at offset 0x0B) will return the value 1. Buffer 1 sould be large enough (see above) to contain enough data for the first 0.2 seconds.

As soon as the data in buffer 1 is completely loaded to the soundcard, the sound device will raise an interrupt, because the BufferInterrupt bit (0x80) was set in the Control register. It will then continue loading data from buffer 2.

Upon receiving the interrupt, the CPU can check the Loaded register (or use its own counter) to determine that buffer 1 was just completely loaded. It should then load the next 16kByte of data from the file into buffer 1 which will (hopefully) finish before the data in buffer 2 has finished playing.

As soon as the data in buffer 2 has finished loading, the sound device will raise again an interrupt, because the BufferInterrupt bit (0x80) is set in the Control register. It will then continue playing with the new data from buffer 1.

Upon receiving this interrupt, the CPU should load the next 16kByte of data from the file into buffer 2 which will (hopefully) finish before the data in buffer 1 has finished playing.

This process is repeated until the end of file is reached. In this case, the last buffer might contain less than 16kByte of valid data. The CPU should then store the correct size value in the buffers size register. When the next interrupt arrives, there is no more data to be stored in the next buffer. Instead its size value is set to zero. When both buffers involved in the PlayLoop command have a size value of zero, the playing stops automatically. There is no need to issue a Cancel command upon receiving the interrupt caused by finishing the last non-empty buffer.

Configuration

The disk has the following configurable parameters:
host localhost the host where the bus is located
port 9002 the port where the bus is located
address default address where the resource is located
interrupt not set interrupt sent when character is ready
x 0the x position of the window
y 0the y position of the window
minimized falsestart with a minimized window
debug falseto generate debug output
debugmask 0xFFF0 set mask to hide debug output
verbose falsemake debugging verbose, sets debug mask to zero
define not setto define a name for conditionals
config not setfilename for a configuration file
help falseto print information

These can be set in default.vmb