674 lines
22 KiB
HTML
674 lines
22 KiB
HTML
|
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||
|
<meta name="Author" content="Josef Drexler">
|
||
|
<meta name="Description" content="A brief description of how the portable part of the sound subsystem of Bochs works, and how it should or could be ported to other platforms than those already supported.">
|
||
|
<title>Porting Bochs Sound Output</title>
|
||
|
</head>
|
||
|
<body text="#000000" bgcolor="#ECECEC" link="#3333CC" vlink="#666666">
|
||
|
|
||
|
<center><h1>Sound Blaster 16 emulation</h1></center>
|
||
|
|
||
|
<h1>About SB16 emulation for bochs</h1>
|
||
|
This is Sound Blaster 16 emulation for bochs, written and donated by
|
||
|
Josef Drexler.
|
||
|
You can see also check out his related web page
|
||
|
<a href="http://publish.uwo.ca/~jdrexler/bochs/">here</a>.
|
||
|
The entire set of his SB16 patches have been integrated into
|
||
|
bochs, so you will not need to do so.
|
||
|
<p>
|
||
|
It has been tested with several soundcards and versions of Linux.
|
||
|
Please give
|
||
|
<a href="mailto:jdrexler@julian.uwo.ca">Josef</a>
|
||
|
feedback on whether is does or doesn't work
|
||
|
on your combination of software and hardware.
|
||
|
|
||
|
<h3>How much does work?</h3>
|
||
|
|
||
|
Right now, MPU401 emulation is next to perfect. It supports UART
|
||
|
and SBMIDI
|
||
|
mode, because the SB16's MPU401 ports can't do anything else as well.
|
||
|
<p>
|
||
|
The digital audio basically works, the emulation is too slow for fluent
|
||
|
output unless the application doesn't do much in the background (or the
|
||
|
foreground, really). The sound tends to looping or crackle on slower
|
||
|
computer, but the emulation appears to be correct. Even a MOD
|
||
|
player works, although only for lower sampling speeds.
|
||
|
<p>
|
||
|
Also, the MIDI data running through the MPU401 ports can be written
|
||
|
into a SMF, that is the standard midi file. The wave output
|
||
|
can be written into a VOC file, which has a format defined by
|
||
|
Creative Labs. This file format can be converted to WAV by
|
||
|
sox for example.
|
||
|
|
||
|
<h3>Output to a sound card</h3>
|
||
|
|
||
|
Output is supported on Linux and Windows 95 at the moment.
|
||
|
<p>
|
||
|
On Linux, the output goes to any file or device. If you have a
|
||
|
wavetable synthesizer, midi can go to /dev/midi00, otherwise you may need
|
||
|
a midi interpreter. For example, the midid program from the
|
||
|
DosEmu project would work. Wave output should go to /dev/dsp.
|
||
|
These devices are assumed to be OSS devices, if they're not
|
||
|
some of the ioctl's might fail.
|
||
|
<p>
|
||
|
On Windows, midi and output goes to the midi mapper and the wave mapper,
|
||
|
respectively. A future version might have selectable output devices.
|
||
|
|
||
|
<hr>
|
||
|
<h1>Installation on Linux</h1>
|
||
|
|
||
|
<h3>Prerequisites</h3>
|
||
|
|
||
|
A wavetable synthesizer on /dev/midi00 and a working /dev/dsp if you want real time music and sound, otherwise output to midi and wave files is also possible.
|
||
|
Optionally, you can use a software midi interpreter, such as the midid program from the DosEmu project instead of /dev/midi00.
|
||
|
|
||
|
<h3>Configuring bochs</h3>
|
||
|
|
||
|
<pre>
|
||
|
There are a few values in config.h that are relevant to the sound functions.
|
||
|
Edit config.h after running configure, but before compiling.
|
||
|
|
||
|
BX_USE_SB16_SMF should be 1 unless you intend to have several sound cards
|
||
|
running at the same time.
|
||
|
|
||
|
BX_USE_SOUND_VIRTUAL can be 0 or 1, and determines whether the output class
|
||
|
uses virtual functions or not. The former is more versatile and allows to
|
||
|
select the class at runtime (not supported at the moment), while the latter
|
||
|
is slightly faster.
|
||
|
|
||
|
BX_SOUND_OUTPUT_C is the name of the class used for output. The default is
|
||
|
to have no output functions, so you need to change this if you want any sound.
|
||
|
The following are supported at the moment:
|
||
|
bx_sound_linux_c for output to /dev/dsp and /dev/midi00 on Linux
|
||
|
(and maybe other OSes that use the OSS driver)
|
||
|
bx_sound_windows_c for output to the midi and wave mapper of
|
||
|
Windows 3.1 and higher.
|
||
|
bx_sound_output_c for no output at all.
|
||
|
|
||
|
Setup the SB16 emulation in your .bochsrc, according to instructions
|
||
|
in that file.
|
||
|
</pre>
|
||
|
<hr>
|
||
|
|
||
|
<h1>Runtime configuration</h1>
|
||
|
|
||
|
The source for the SB16CTRL program that is used to modify
|
||
|
the runtime behaviour of the SB16 emulator is included in
|
||
|
<b>misc/sb16</b>. You can compile it or download the
|
||
|
<a href="http://publish.uwo.ca/~jdrexler/bochs/">executable</a>.
|
||
|
<p>
|
||
|
<pre>
|
||
|
misc/sb16/ contains a C program that can be run inside the emulator, and the
|
||
|
executable for DOS. It currently supports the following commands:
|
||
|
-i <number>: shows the selected emulator info string,
|
||
|
e.g. sb16ctrl -i 3 to show how many patch translations are active
|
||
|
|
||
|
-t <six numbers>: loads a translation into the translation table. The
|
||
|
numbers are:
|
||
|
OldBankMSB,OldBankLSB,OldProgram,NewBankMSB,NewBankLSB,NewProgram
|
||
|
All values can be 0..127 or 255. 255 for Old values means "match
|
||
|
any" and for New values means "don't change",
|
||
|
e.g. sb16ctrl -t 255,255,0,255,255,32
|
||
|
to change patch 0 (Piano) to patch 32 (Acoustic Bass)
|
||
|
|
||
|
-r: Reset the patch translation table
|
||
|
e.g. sb16ctrl -r
|
||
|
|
||
|
-m <some numbers>: Upload the given numbers to the midi output device. Note
|
||
|
that it should be a complete midi message, and also that it is
|
||
|
subject to patch translation.
|
||
|
e.g. sb16ctrl -m 0x80,64,0
|
||
|
to send a note-off message to channel 0.
|
||
|
|
||
|
-f <filename>: Reads in a file and executes the commands in it. These have
|
||
|
the same format as the above commands, except that they don't have
|
||
|
the dash "-" in front of them.
|
||
|
Comment lines are supported and start with a hash sign "#".
|
||
|
|
||
|
-h: Show a brief summary of the commands.
|
||
|
|
||
|
All numbers can be valid parameters to the strtol() function, so hex and
|
||
|
octal notation is fine. They have to be delimited by either commas "," or
|
||
|
slashes "/", spaces are not allowed.
|
||
|
|
||
|
The command line can have any number of commands. However, if none are given,
|
||
|
"-f -" is assumed, which means commands are taken from stdin.
|
||
|
</pre>
|
||
|
|
||
|
<hr>
|
||
|
<h1>Features planned for the future</h1>
|
||
|
<ul>
|
||
|
<li>Ports to more OS's, but I can't do this myself
|
||
|
<li>Finishing the OPL3 FM emulation by translating the music to midi data
|
||
|
</ul>
|
||
|
|
||
|
<hr>
|
||
|
<h1>
|
||
|
Description of the sound output classes</h1>
|
||
|
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.
|
||
|
<p>You should also have a look at the exisiting files, <tt>SOUNDLNX.CC</tt>
|
||
|
for Linux and <tt>SOUNDWIN.CC</tt> for Windows and their respective
|
||
|
header files to get an idea about how these things <i>really</i> work.
|
||
|
|
||
|
<h2>Overview</h2>
|
||
|
|
||
|
<h3>Files</h3>
|
||
|
The main include file is <tt>"bochs.h"</tt>. It has all definitions
|
||
|
for the system-independent functions that the SB16 emulation uses, which
|
||
|
are defined in <tt>"sb16.h"</tt>.
|
||
|
|
||
|
<p>Additionally, every output driver will have an include file, which
|
||
|
should be included at the end of <tt>sb16.h</tt> to allow the emulator
|
||
|
to use that driver.
|
||
|
|
||
|
<p>To actually make the emulator use any specific driver,
|
||
|
<tt>BX_SOUND_OUTPUT_C</tt> has to be set to the name of the respective
|
||
|
output class.
|
||
|
|
||
|
<p>Note that if your class contains any system-specific statements,
|
||
|
include-files and so on, you should enclose both the include-file and
|
||
|
the CC-file in an <tt>#if defined(<i>OS-define</i>)</tt> construct.
|
||
|
Also don't forget to add your file to the object list in
|
||
|
<tt>iodev/Makefile</tt> and <tt>iodev/Makefile.in</tt>.
|
||
|
|
||
|
<h3>Classes</h3>
|
||
|
The following classes are involved with the SB16 emulation:
|
||
|
<ul>
|
||
|
<li><tt>bx_sb16_c</tt> is the class containing the emulator itself, that
|
||
|
is the part acting on port accesses by the application, handling the
|
||
|
DMA transfers and so on. It also prepares the data for the output
|
||
|
classes.
|
||
|
</li>
|
||
|
<li><tt>bx_sound_output_c</tt> is the base output class. It has all
|
||
|
the methods used by the emulator, but only as stubs and does not
|
||
|
actually produce any output. These methods are then called by
|
||
|
the emulator whenever output is necessary.
|
||
|
</li>
|
||
|
<li><tt>bx_sound_<i>OS</i>_c</tt> is derived from
|
||
|
<tt>bx_sound_output_c</tt>. It contains the code to generate
|
||
|
output for the <tt><i>OS</i></tt> operating system.
|
||
|
It is necessary to override all
|
||
|
the methods defined in the base class, unless virtual functions
|
||
|
are used. Note that this should remain an option, so try to
|
||
|
override all methods, even if only as stubs. They should be
|
||
|
declared <tt>virtual</tt> if and only if <tt>BX_USE_SOUND_VIRTUAL</tt>
|
||
|
is defined, just as in the examples.
|
||
|
The constructor should call the inherited constructor
|
||
|
as usual, even though the current constructor does not do
|
||
|
anything yet.
|
||
|
</li>
|
||
|
</ul>
|
||
|
|
||
|
<h3>Methods</h3>
|
||
|
The following are the methods that the output class has to override.
|
||
|
All but constructor and destructor have to return either
|
||
|
<tt>BX_SOUND_OUTPUT_OK</tt> (0) if the function was successful,
|
||
|
or <tt>BX_SOUND_OUTPUT_ERR</tt> (1) if not. If any of the initialization
|
||
|
functions fail, output to that device is disabled until the emulator
|
||
|
is restarted.
|
||
|
|
||
|
<p>Constructor and destructor:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<tt><a href="#constructor">bx_sound_<i>OS</i>_c(bx_sb16_c *sb16)</a></tt>
|
||
|
</li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#destructor">~bx_sound_<i>OS</i>_c()</a></tt>
|
||
|
</li>
|
||
|
</ul>
|
||
|
|
||
|
<p>Midi functions:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<tt><a href="#openmidioutput">int openmidioutput(char *device)</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#sendmidicommand">int sendmidicommand(int delta,
|
||
|
int command, int length, Bit8u data[])</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#midiready">int midiready()</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#closemidioutput">int closemidioutput()</a></tt></li>
|
||
|
</ul>
|
||
|
Wave functions:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<tt><a href="#openwaveoutput">int openwaveoutput(char *device)</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#startwaveplayback">int startwaveplayback(int frequency,
|
||
|
int bits, int stereo, int format)</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#waveready">int waveready()</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#sendwavepacket">int sendwavepacket(int length, Bit8u data[])</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#stopwaveplayback">int stopwaveplayback()</a></tt></li>
|
||
|
|
||
|
<li>
|
||
|
<tt><a href="#closewaveoutput">int closewaveoutput()</a></tt></li>
|
||
|
</ul>
|
||
|
|
||
|
<hr SIZE=4 WIDTH="100%">
|
||
|
<h2>Details</h2>
|
||
|
|
||
|
<h3>Methods</h3>
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="constructor"></a><tt>bx_sound_<i>OS</i>_c(bx_sb16_c
|
||
|
*<a href="#conssb16">sb16</a>)</tt></h4>
|
||
|
The emulator instantiates the class at the initialization of Bochs.
|
||
|
|
||
|
<p>Description of the parameter:
|
||
|
<ul>
|
||
|
<li><a NAME="conssb16"></a><tt>sb16</tt> is a pointer to the emulator class.
|
||
|
This pointer can then be used
|
||
|
to access for example the <tt>writelog</tt> function to generate
|
||
|
sound-related log messages. Apart from that, no access to the emulator
|
||
|
should be necessary.
|
||
|
</ul>
|
||
|
|
||
|
The constructor should <i>not</i> allocate the output devices.
|
||
|
This shouldn't be done until the actual output
|
||
|
occurs; in either <tt>initmidioutput()</tt> or <tt>initwaveoutput()</tt>.
|
||
|
Otherwise it would be impossible to have two copies of Bochs running
|
||
|
concurrently (if anybody ever wants to do this).</li>
|
||
|
</ul>
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="destructor"></a><tt>~bx_sound_<i>OS</i>_c()</tt></h4>
|
||
|
The instance is destroyed just before Bochs ends.
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="openmidioutput"></a><tt>int openmidioutput(char *<a href="#omodevice">device</a>)</tt></h4>
|
||
|
<tt>openmidioutput()</tt> is called when the first midi output starts.
|
||
|
It is only called if the midi output mode is 1 (midimode 1). It should
|
||
|
<ul>
|
||
|
<li>
|
||
|
prepare the given MIDI hardware for receiving midi commands.</li>
|
||
|
</ul>
|
||
|
<tt>openmidioutput()</tt> will always be called before <tt>openwaveoutput()</tt>,
|
||
|
and <tt>closemidioutput()</tt>will always be called before <tt>closewaveoutput()</tt>,
|
||
|
but not in all cases will both functions be called.
|
||
|
<p>Description of the parameters:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a NAME="omodevice"></a><tt>device</tt> is a system-dependent variable.
|
||
|
It contains the value of the <tt>MIDI=device</tt> configuration option.</li>
|
||
|
</ul>
|
||
|
Note that only one midi output device will be used at any one time.
|
||
|
<tt>device</tt>
|
||
|
may not have the same value throughout one session, but it will be closed
|
||
|
before it is changed.
|
||
|
|
||
|
<h4>
|
||
|
<a name="midiready"></a><tt>int midiready()</tt></h4>
|
||
|
|
||
|
<tt>midiready()</tt> is called whenever the applications asks if the
|
||
|
midi queue can accept more data.
|
||
|
|
||
|
<p>Return values:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<tt>BX_SOUND_OUTPUT_OK</tt> if the midi output device is ready
|
||
|
</li>
|
||
|
<li>
|
||
|
<tt>BX_SOUND_OUTPUT_ERR</tt> if it isn't ready
|
||
|
</ul>
|
||
|
|
||
|
<b>Note: </b><tt>midiready()</tt> will be called a few times
|
||
|
<i>before</i> the device is opened. If this is the case, it should
|
||
|
always report that it is ready, otherwise the application (not Bochs)
|
||
|
will hang.
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="sendmidicommand"></a><tt>int sendmidicommand(int <a href="#smcdelta">delta</a>,
|
||
|
int <a href="#smdcommand">command</a>, int <a href="#smclength">length</a>,
|
||
|
Bit8u <a href="#smcdata">data</a>[])</tt></h4>
|
||
|
<tt>sendmidicommand()</tt>is called whenever a complete midi command has
|
||
|
been written to the emulator. It should then
|
||
|
<ul>
|
||
|
<li>
|
||
|
send the given midi command to the midi hardware.</li>
|
||
|
</ul>
|
||
|
It will only be called after the midi output has been opened. Note that
|
||
|
if at all possible it should not wait for the completion of the command
|
||
|
and instead indicate that the device is not ready during the execution
|
||
|
of the command. This is to avoid delays in the program while it is
|
||
|
generating midi output.
|
||
|
<p>Description of the parameters:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a NAME="smcdelta"></a><tt>delta</tt> is the number of delta ticks that
|
||
|
have passed since the last command has been issued. It is always zero for
|
||
|
the first command. There are 24 delta ticks per quarter, and 120 quarters
|
||
|
per minute, thus 48 delta ticks per second.</li>
|
||
|
|
||
|
<li>
|
||
|
<a NAME="smdcommand"></a><tt>command</tt> is the midi command byte (sometimes
|
||
|
called status byte), in the usual range of 0x80..0xff. For more information
|
||
|
please see the midi standard specification.</li>
|
||
|
|
||
|
<li>
|
||
|
<a NAME="smclength"></a><tt>length</tt> is the number of data bytes that
|
||
|
are contained in the data structure. This does <i>not</i> include the status
|
||
|
byte which is not replicated in the data array. It can only be greater
|
||
|
than 3 for SysEx messages (commands <tt>0xF0</tt> and <tt>0xF7</tt>)</li>
|
||
|
|
||
|
<li>
|
||
|
<a NAME="smcdata"></a><tt>data[]</tt> is the array of these data bytes,
|
||
|
in the order they have in the standard MIDI specification.
|
||
|
Note, it might be <tt>NULL</tt> if length==0.</li>
|
||
|
</ul>
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="closemidioutput"></a><tt>int closemidioutput()</tt></h4>
|
||
|
<tt>closemidioutput()</tt> is called before shutting down Bochs or
|
||
|
when the
|
||
|
emulator gets the <tt>stop_output</tt> command through the emulator port.
|
||
|
After this, no more output will be necessary until <tt>openmidioutput()</tt>
|
||
|
is called again, but <tt>midiready()</tt> might still be called. It should
|
||
|
<ul>
|
||
|
<li>
|
||
|
Wait for all remaining messages to be completed
|
||
|
</li>
|
||
|
<li>
|
||
|
Reset and close the midi output device</li>
|
||
|
</ul>
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="openwaveoutput"></a><tt>int openwaveoutput(char *<a href="#owodevice">device</a>)</tt></h4>
|
||
|
<tt>openwaveoutput()</tt> is called when the first wave output occurs,
|
||
|
and only if the selected wavemode is 1. It should
|
||
|
<ul>
|
||
|
<li>
|
||
|
Open the given device, and prepare it for wave output</li>
|
||
|
</ul>
|
||
|
<i>or</i>
|
||
|
<ul>
|
||
|
<li>
|
||
|
Store the device name so that the device can be opened in <tt>startplayback()</tt>.</li>
|
||
|
</ul>
|
||
|
<tt>openmidioutput()</tt> will always be called before <tt>openwaveoutput()</tt>,
|
||
|
and <tt>closemidioutput()</tt>will always be called before <tt>closewaveoutput()</tt>,
|
||
|
but not in all cases will both functions be called.
|
||
|
<p><tt>openwaveoutput()</tt> will typically be called once, whereas
|
||
|
<tt>startplayback()</tt>
|
||
|
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
|
||
|
<tt>startplayback()</tt> as opposed to <tt>openwaveoutput()</tt>
|
||
|
to ensure that it can be used by other applications while Bochs doesn't
|
||
|
need it.
|
||
|
<p>However, many older applications don't use the auto-init DMA
|
||
|
mode, which means that they start a new DMA transfer for every single
|
||
|
block of output, which means usually for every 2048 bytes or so.
|
||
|
Unfortunately there is no way of knowing whether the application will
|
||
|
restart an expired DMA transfer soon, so that in these cases the
|
||
|
<tt>startwaveplayback</tt> function will be called very often, and it
|
||
|
isn't a good idea to have it reopen the device every time.
|
||
|
|
||
|
<p>The buffer when writing to the device should not be overly large.
|
||
|
Usually about four buffers of 4096 bytes produce best results. Smaller
|
||
|
buffers could mean too much overhead, while larger buffers contribute
|
||
|
to the fact that the actual output will always be late when the application
|
||
|
tries to synchronize it with for example graphics.
|
||
|
|
||
|
<p>The parameters are
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a NAME="owodevice"></a><tt>device</tt> is the wave device selected by
|
||
|
the user. It is strictly system-dependent. The value is that of the
|
||
|
<tt>WAVE=device</tt>
|
||
|
configuration option.</li>
|
||
|
</ul>
|
||
|
Note that only one wave output device will be used at any one time.
|
||
|
<tt>device</tt>
|
||
|
may not have the same value throughout one session, but it will be closed
|
||
|
before it is changed.
|
||
|
<h4>
|
||
|
<a NAME="startwaveplayback"></a><tt>int startwaveplayback(int
|
||
|
<a href="#swpfreq">frequency</a>,
|
||
|
int <a href="#swpbits">bits</a>, int
|
||
|
<a href="#swpstereo">stereo</a>, int
|
||
|
<a href="#swpcodec">format</a>)</tt></h4>
|
||
|
This function is called whenever the application starts a new DMA transfer.
|
||
|
It should
|
||
|
<ul>
|
||
|
<li>
|
||
|
Open the wave output device, unless <tt>openwaveoutput()</tt> did that
|
||
|
already</li>
|
||
|
|
||
|
<li>
|
||
|
Prepare the device for data and set the device parameters to those given
|
||
|
in the function call</li>
|
||
|
</ul>
|
||
|
The parameters are:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a NAME="swpfreq"></a><tt>frequency</tt> is the desired frequency of the
|
||
|
output. Because of the capabities of the SB16, it can have any value between
|
||
|
5000 and 44,100.</li>
|
||
|
|
||
|
<li>
|
||
|
<a NAME="swpbits"></a><tt>bits</tt> is either 8 or 16, denoting the resolution
|
||
|
of one sample.</li>
|
||
|
|
||
|
<li>
|
||
|
<a NAME="swpstereo"></a><tt>stereo</tt> is either 1 for stereo output,
|
||
|
or 0 for mono output.</li>
|
||
|
|
||
|
<li>
|
||
|
<a NAME="swpcodec"></a><tt>format</tt> is a bit-coded value (see below).</li>
|
||
|
</ul>
|
||
|
|
||
|
<table>
|
||
|
<tr VALIGN=TOP>
|
||
|
<td NOSAVE>The bits in <tt>format</tt> are
|
||
|
<table BORDER=2 >
|
||
|
<tr>
|
||
|
<th>Bit number</th>
|
||
|
|
||
|
<th>Meaning</th>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>0 (LSB)</td>
|
||
|
|
||
|
<td>0: unsigned data
|
||
|
<br>1: signed data</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>1..6</td>
|
||
|
|
||
|
<td>Type of codec</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>7</td>
|
||
|
|
||
|
<td>0: no reference byte
|
||
|
<br>1: with reference byte</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>8..x</td>
|
||
|
|
||
|
<td>reserved (0)</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
</td>
|
||
|
|
||
|
<td WIDTH="5%"></td>
|
||
|
|
||
|
<td>The codec can be one of the following:
|
||
|
<table BORDER=2>
|
||
|
<tr>
|
||
|
<th>Value</th>
|
||
|
|
||
|
<th>Meaning</th>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>0</td>
|
||
|
|
||
|
<td>PCM (raw data)</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>1</td>
|
||
|
|
||
|
<td>reserved</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>2</td>
|
||
|
|
||
|
<td>2-bit ADPCM
|
||
|
<br>(Creative Labs format)</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>3</td>
|
||
|
|
||
|
<td>2.4-bit (3-bit) ADPCM
|
||
|
<br>(Creative Labs format)</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>4</td>
|
||
|
|
||
|
<td>4-bit ADPCM
|
||
|
<br>(Creative Labs format)</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
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.</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
The number of bytes per sample can be calculated from this as
|
||
|
<tt>(bits / 8) * (stereo + 1)</tt>.
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="waveready"></a><tt>int waveready()</tt></h4>
|
||
|
This is called whenever the emulator has another output buffer ready
|
||
|
and would like to pass it to the output class. This happens every
|
||
|
<tt>BX_SOUND_OUTPUT_WAVEPACKETSIZE</tt> bytes, or whenever a DMA transfer
|
||
|
is done or aborted.
|
||
|
|
||
|
<p>It should return whether the output device is ready for another buffer
|
||
|
of <tt>BX_SOUND_OUTPUT_WAVEPACKETSIZE</tt> bytes.
|
||
|
If <tt>BX_SOUND_OUTPUT_ERR</tt>
|
||
|
is returned, the emulator waits about 1/(frequency * bytes per sample) seconds
|
||
|
and then asks again. The DMA transfer is stalled during that time, but
|
||
|
the application keeps running, until the output device becomes ready.
|
||
|
|
||
|
<p>As opposed to <tt>midiready(), waveready()</tt> will <i>not</i> be
|
||
|
called unless the device is open.
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="sendwavepacket"></a><tt>int sendwavepacket(int <a href="#swplength">length</a>,
|
||
|
Bit8u <a href="#swpdata">data[]</a>)</tt></h4>
|
||
|
This function is called whenever a data packet of at most <tt>BX_SB16_WAVEPACKETSIZE</tt>
|
||
|
is ready at the SB16 emulator. It should then
|
||
|
<ul>
|
||
|
<li>
|
||
|
Send this wave packet to the wave hardware</li>
|
||
|
</ul>
|
||
|
This function <i>has</i> to be synchronous, meaning that it <i>has</i>
|
||
|
to return immediately, and <i>not</i> 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. This is not what you want.
|
||
|
Instead, <tt>waveready()</tt> should return <tt>BX_SOUND_OUTPUT_ERR</tt>
|
||
|
until the device accepts another block of data.
|
||
|
<p>Parameters:
|
||
|
<ul>
|
||
|
<li>
|
||
|
<a NAME="swplength"></a><tt>length</tt> is the number of data bytes in
|
||
|
the data stream. It will never be larger than <tt>BX_SB16_WAVEPACKETSIZE</tt>.</li>
|
||
|
|
||
|
<li>
|
||
|
<a NAME="swpdata"></a><tt>data</tt> is the array of data bytes.</li>
|
||
|
</ul>
|
||
|
|
||
|
<p><br>The order of bytes in the data stream is the same as that in the
|
||
|
Wave file format:
|
||
|
<br>
|
||
|
<table BORDER=2>
|
||
|
<tr>
|
||
|
<th>Output type</th>
|
||
|
|
||
|
<th ALIGN=LEFT>Sequence of data bytes</th>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>8 bit mono</td>
|
||
|
|
||
|
<td>Sample 1; Sample 2; Sample 3; etc.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>8 bit stereo</td>
|
||
|
|
||
|
<td>Sample 1, Channel 0; Sample 1, Channel 1; Sample 2, Channel 0; Sample
|
||
|
2, Channel 1; etc.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>16 bit mono</td>
|
||
|
|
||
|
<td>Sample 1, LSB; Sample 1, MSB; Sample 2, LSB; Sample 2, MSB; etc.</td>
|
||
|
</tr>
|
||
|
|
||
|
<tr>
|
||
|
<td>16 bit stereo</td>
|
||
|
|
||
|
<td>Sample 1, LSB, Channel 0; Sample 1, MSB, Channel 0; Sample 1, LSB,
|
||
|
Channel 1; Sample 1, MSB, Channel 1; etc.</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
|
||
|
<p>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.
|
||
|
<h4>
|
||
|
<a NAME="stopwaveplayback"></a><tt>int stopwaveplayback()</tt></h4>
|
||
|
This function is called at the end of a DMA transfer. It should
|
||
|
<ul>
|
||
|
<li>
|
||
|
Close the output device if it was opened by <tt>startwaveplayback()</tt>.</li>
|
||
|
and it's not going to be opened soon. Which is almost impossible to tell.
|
||
|
</ul>
|
||
|
|
||
|
<h4>
|
||
|
<a NAME="closewaveoutput"></a><tt>int closewaveoutput()</tt></h4>
|
||
|
This function is called just before Bochs exits. It should
|
||
|
<ul>
|
||
|
<li>
|
||
|
Close the output device, if this hasn't been done by <tt>stopwaveplayback()</tt>.</li>
|
||
|
</ul>
|
||
|
Typically, <tt>stopwaveplayback()</tt> will be called several times, whenever
|
||
|
a DMA transfer is done, where <tt>closewaveoutput()</tt> will only be called
|
||
|
once. However, in the future it might be possible that <tt>openwaveoutput()</tt>
|
||
|
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.
|
||
|
</body>
|
||
|
</html>
|