Description of Sound???.CC

This file is intended for programmers who would like to port the sound output routines to their platform. It gives a short outline what services have to be provided.

You should also have a look at the exisiting files, SOUNDLNX.CC for Linux and SOUNDWIN.CC for Windows.

Overview

Include file

The include file is "bochs.h". It contains all definitions for the system-independent functions that the SB16 emulation uses.

Functions

The following functions should be supplied by this output driver, even if only as stubs. They should return BX_SB16_OUTPUT_OK (0)  if the function was successful, and BX_SB16_OUTPUT_ERR (1) if not. Note that the return information is not used at the moment.

General functions:

Midi functions: Wave functions:

Variables

The following variable is defined in the BX_SB16_C class and is available to the output functions:

Details

Functions

int bx_sb16_c::initoutput()

initoutput() is called at the start of the emulator. It should do the following tasks: It should not do the following:

int bx_sb16_c::doneoutput()

doneoutput() is called just before Bochs ends. It should

int bx_sb16_c::openmidioutput(char *device)

openmidioutput() is called when the first midi output starts. It is only called if the midi output mode is 1 (midimode 1). It should openmidioutput() will always be called before openwaveoutput(), and closemidioutput()will always be called before closewaveoutput(), but not in all cases will both functions be called.

Description of the parameters:

Note that only one midi output device will be used at any one time. device may not have the same value throughout one session, but it will be closed before it is changed.

int bx_sb16_c::sendmidicommand(int delta, int command, int length, Bit8u data[])

sendmidicommand()is called whenever a complete midi command has been written to the emulator. It should then It will only be called after the midi output has been opened.

Description of the parameters:

int bx_sb16_c::closemidioutput()

closemidioutput() is called before shutting down Bochs or the emulator after it gets the stop_output command. After this, no more output will be necessary until openmidioutput() is called again. It should

int bx_sb16_c::openwaveoutput(char *device)

openwaveoutput() is called when the first wave output occurs, and only if the selected wavemode is 1. It should or openmidioutput() will always be called before openwaveoutput(), and closemidioutput()will always be called before closewaveoutput(), but not in all cases will both functions be called.

openwaveoutput() will typically be called once, where startplayback() is called for every new DMA transfer to the SB16 emulation. If feasible, it could be useful to open and/or lock the output device in startplayback() to ensure that it can be used by other applications while Bochs doesn't need it.

The parameters are

Note that only one wave output device will be used at any one time. device may not have the same value throughout one session, but it will be closed before it is changed.

int bx_sb16_c::startwaveplayback(int frequency, int bits, int stereo, int format)

This function is called whenever the application starts a new DMA transfer. It should The parameters are:
The bits in format are 
Bit number Meaning
0 (LSB) 0: unsigned data
1: signed data
1..6 Type of codec
7 0: no reference byte
1: with reference byte
8..x reserved (0)
The codec can be one of the following:
Value Meaning
0 raw data
1 reserved
2 2-bit ADPCM
(Creative Labs format)
3 2.4-bit (3-bit) ADPCM
(Creative Labs format)
4 4-bit ADPCM
(Creative Labs format)
Other codecs are not supported by the SB hardware. In fact, most applications will translate their data into raw data, so that in most cases the codec will be zero.
The number of bytes per sample can be calculated as (bits / 8) * (stereo + 1).

I recommend that these values be stored in the outputdata structure if they are going to be used in the future. Although they can be accessed through the emulator variables as well, this is not recommended.

int bx_sb16_c::sendwavepacket(int length, Bit8u data[])

This functions is called whenever a data packet of at most BX_SB16_WAVEPACKETSIZE has been sent to the SB16 emulator. It should then This function has to be synchronous, meaning that it has to return immediately, and not wait until the output is done. Also, this function might be called before the previous output is done. If your hardware can't append the new output to the old one, you will have to implement this yourself, or the output will be very chunky, with as much silence between the blocks as the blocks take to play.

Parameters:


The order of bytes in the data stream is the same as that in the Wave file format:
 
Output type Sequence of data bytes
8 bit mono Sample 1; Sample 2; Sample 3; etc.
8 bit stereo Sample 1, Channel 0; Sample 1, Channel 1; Sample 2, Channel 0; Sample 2, Channel 1; etc.
16 bit mono Sample 1, LSB; Sample 1, MSB; Sample 2, LSB; Sample 2, MSB; etc.
16 bit stereo Sample 1, LSB, Channel 0; Sample 1, MSB, Channel 0; Sample 1, LSB, Channel 1; Sample 1, MSB, Channel 1; etc.

Typically 8 bit data will be unsigned with values from 0 to 255, and 16 bit data will be signed with values from -32768 to 32767, although the SB16 is not limited to this. For further information on the codecs and the use of reference bytes please refer to the Creative Labs Sound Blaster Programmer's Manual, which can be downloaded from the Creative Labs web site.

int bx_sb16_c::stopwaveplayback()

This function is called at the end of a DMA transfer. It should

int bx_sb16_c::closewaveoutput()

This function is called just before Bochs exits. It should Typically, stopwaveplayback() will be called several times, whenever a DMA transfer is done, where closewaveoutput() will only be called once. However, in the future it might be possible that openwaveoutput() is called again, for example if the user chose to switch devices while Bochs was running. This is not supported at the moment, but might be in the future.

Variables

void *outputdata

This variable is unused by the emulator itself and is intended to hold data for the output part. It will be initialized to NULL at the start of the emulator and should be initialized by the initoutput() function. outputdata can be type cast to any struct you like. It will not be touched by the emulator; it is only used in the output file.

I recommend the definition of a structure (just local to the output file) and a #define to access it like this:

struct bx_sb16_output_struct {
// put the variables used by your functions here
};

#define OUTPUTDATA ( (bx_sb16_output_struct*) (BX_SB16_THIS outputdata) )

Then the variables can be accessed by OUTPUTDATA->variablename.

Since this is rather difficult to debug, it might make sense to define a global variable and have OUTPUTDATA point to it while debugging the output functions.

Boolean waveoutputready

This variable tells the emulator if the wave output functions are ready to receive a data block. It has to be handled by the output functions, whenever output is running, i. e. between a startwaveplayback and a stopwaveplayback call. If it is not set when a block of data becomes available, this block is not sent until waveoutputready is set to 1. Note that the time between  setting it and the block being sent to the output function is approximately the time for one byte (or word in 16bit DMA) to be transferred, but in reality may be slightly longer.

It should be accessed by the following construct
BX_SB16_THIS waveoutputready

Boolean midioutputready

This is equivalent to waveoutputready, except that it is for midi output.

It should be accessed by
BX_SB16_THIS midioutputready

Other variables

All other variables should be read-only, but the compiler doesn't ensure this. I don't think it's necessary to use any of them and that they should rather be passed to the individual functions as parameters. If you need the value of a variable and it's not passed as parameter, please tell me and I will add it to the parameter list.