VMB Disk Device Specification

Soundcard Device Specification

Memory Layout

Byte | Mode | Name | Description
00 | RW | Control | Controll register, write to initiate soundcard operations
01 | RW | DMA No 0 | Number 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-17 | RW | DMA1.address | physical 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:

  • Ignore (0x00)
    This command does nothing.
  • PlayOnceMP3 (0x01)
    The buffers indicated by DMA No 0 and DMA No 1 contain MP3 data. The data is decoded and played once. DMA Numbers are in the range 1 to 16; if the DMA No is zero, it is ignored. The Format information is taken from the MP3 data, The format registers (Byte 03-07) are ignored.
  • PlayOncePCM (0x02)
    The buffers indicated by DMA No 0 and DMA No 1 contain data as specified by the format registers (Byte 03-07) . The data is played once. DMA Numbers are in the range 1 to 16; if the DMANo is zero, it is ignored.
  • Preload (0x03)
    The buffer indicated by DMA No 0 contains valid data, it will be played in the near future. The sound card may start now to load this data. The data in the buffer is considered constant and might be cached localy on the sound card. The cached copy is valid until invalidated by a new Preload or Unload command.
  • Unload (0x04)
    Cached copied of the data in the buffer indicated by DMA No 0 is no longer valid. Before playing, this buffers must be reloaded.
  • PlayLoopMP3 (0x05)
    The buffers indicated by DMA No 0 and DMA No 1 contain MP3 data. The data is decoded and played repeatedly. Use the Cancel command to stop playing. DMA Numbers are in the range 1 to 16; if the DMA No is zero, it is ignored. The Format information is taken from the MP3 data. The format registers (Byte 03-07) are ignored.
  • PlayLoopPCM (0x06)
    The buffers indicated by DMA No 0 and DMA No 1 contain data as specified by the format registers (Byte 03-07). The data is played repeatedly. Use the Cancel command to stop playing. DMA Numbers are in the range 1 to 16; if the DMANo is zero, it is ignored.
  • Cancel (0x7E)
    Cancel the current operation; abort loading and stop playing immediately.
  • Reset (0x7F)
    Reset the soundcard. Stop playing, unload all buffers, set all registers to zero.
  • BufferInterrupt (0x80)
    This value can be ORed with the previous Command values (except Ignore, Unload, Cancel, and Reset). It will cause the soundcard to raise an interrupt as soon as a buffer has finished loading. It will also set the Loaded register to the DMA buffer number causing the interrupt.

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 | 0 | the x position of the window
y | 0 | the y position of the window
minimized | false | start with a minimized window
debug | false | to generate debug output
debugmask | 0xFFF0 | set mask to hide debug output
verbose | false | make debugging verbose, sets debug mask to zero
define | not set | to define a name for conditionals
config | not set | filename for a configuration file
help | false | to print information

These can be set in default.vmb