Moving the "classes" portion of SB16 emulation to the developer documentation.
This commit is contained in:
parent
eff7720ae7
commit
b0ec110bdc
@ -1,7 +1,7 @@
|
||||
<!--
|
||||
================================================================
|
||||
doc/docbook/user/user.dbk
|
||||
$Id: user.dbk,v 1.62 2002-11-18 07:40:50 ndavidg Exp $
|
||||
$Id: user.dbk,v 1.63 2002-11-19 14:08:30 ndavidg Exp $
|
||||
|
||||
This is the top level file for the Bochs Users Manual.
|
||||
================================================================
|
||||
@ -2735,7 +2735,7 @@ parport1: enabled=0
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>sb16</title>
|
||||
<section id="sb16line"><title>sb16</title>
|
||||
<para>
|
||||
Examples:
|
||||
<screen>
|
||||
@ -3026,9 +3026,15 @@ ctrlaltdel, ctrlaltesc, ctrlaltf1, alttab
|
||||
|
||||
<section> <!-- start of SB16 section-->
|
||||
|
||||
<title>Sound Blaster 16 Emulation</title>
|
||||
<title>Sound Blaster 16 Emulation: Configuring From Source</title>
|
||||
|
||||
<para>
|
||||
This is Sound Blaster 16 (SB16) emulation for Bochs, written and donated by
|
||||
This section is a detailed description for configuring Sound Blaster 16 from
|
||||
source. I you have a binary and all you need to know is what to put in your
|
||||
.bochsrc file, see <xref linkend="sb16line">.
|
||||
</para>
|
||||
<para>
|
||||
Sound Blaster 16 (SB16) emulation for Bochs was written and donated by
|
||||
Josef Drexler, who has a
|
||||
<ulink url="http://publish.uwo.ca/~jdrexler/bochs/">web page</ulink> on the topic.
|
||||
The entire set of his SB16 patches have been integrated into
|
||||
@ -3197,508 +3203,11 @@ The command line can have any number of commands. However, if none are given,
|
||||
|
||||
<section>
|
||||
<title>Description of the sound output classes</title>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
You should also have a look at the exisiting files, <emphasis>SOUNDLNX.CC</emphasis>
|
||||
for Linux and <emphasis>SOUNDWIN.CC</emphasis> for Windows and their respective
|
||||
header files to get an idea about how these things really work.
|
||||
You can find a description of the sound output classes and more details on
|
||||
Sound Blaster 16 emulation in the developer documentation.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>Files</title>
|
||||
|
||||
<para>
|
||||
The main include file is <emphasis>bochs.h</emphasis>. It has all definitions
|
||||
for the system-independent functions that the SB16 emulation uses, which
|
||||
are defined in <emphasis>sb16.h</emphasis>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Additionally, every output driver will have an include file, which
|
||||
should be included at the end of sb16.h to allow the emulator
|
||||
to use that driver.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To actually make the emulator use any specific driver,
|
||||
<emphasis>BX_SOUND_OUTPUT_C</emphasis> has to be set to the name of the respective
|
||||
output class.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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 <emphasis>#if defined</emphasis> (OS-define) construct.
|
||||
Also don't forget to add your file to the object list in
|
||||
iodev/Makefile and iodev/Makefile.in.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>Classes</title>
|
||||
|
||||
<para>
|
||||
The following classes are involved with the SB16 emulation:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>bx_sb16_c</emphasis> 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.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>bx_sound_output_c</emphasis> 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.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>bx_sound_OS_c</emphasis> is derived from
|
||||
<emphasis>bx_sound_output_c</emphasis>. It contains the code to generate
|
||||
output for the <emphasis>OS</emphasis> 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 <emphasis>virtual</emphasis> if and only if <emphasis>BX_USE_SOUND_VIRTUAL</emphasis>
|
||||
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.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>Methods</title>
|
||||
<para>
|
||||
The following are the methods that the output class has to override.
|
||||
All but constructor and destructor have to return either
|
||||
<emphasis>BX_SOUND_OUTPUT_OK</emphasis> <emphasis>(0)</emphasis> if the function was successful,
|
||||
or <emphasis>BX_SOUND_OUTPUT_ERR</emphasis> <emphasis>(1)</emphasis> if not. If any of the initialization
|
||||
functions fail, output to that device is disabled until the emulator is restarted.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>bx_sound_OS_c(bx_sb16_c*sb16)</title>
|
||||
|
||||
<para>
|
||||
The emulator instantiates the class at the initialization of Bochs.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Description of the parameter:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>sb16</emphasis> is a pointer to the emulator class.
|
||||
This pointer can then be used to access for example the <emphasis>writelog</emphasis> function to generate
|
||||
sound-related log messages. Apart from that, no access to the emulator
|
||||
should be necessary.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
The constructor should <emphasis>not</emphasis> allocate the output devices.
|
||||
This shouldn't be done until the actual output occurs; in either
|
||||
<emphasis>initmidioutput()</emphasis> or <emphasis>initwaveoutput()</emphasis>.
|
||||
Otherwise it would be impossible to have two copies of Bochs running
|
||||
concurrently (if anybody ever wants to do this).
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section><title>~bx_sound_OS_c()</title>
|
||||
|
||||
<para>
|
||||
The instance is destroyed just before Bochs ends.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>int openmidioutput(char *device)</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>openmidioutput()</emphasis> is called when the first midi output starts.
|
||||
It is only called if the midi output mode is 1 (midimode 1). It should
|
||||
prepare the given MIDI hardware for receiving midi commands.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>openmidioutput()</emphasis> will always be called before <emphasis>openwaveoutput()</emphasis>,
|
||||
and <emphasis>closemidioutput()</emphasis>will always be called before <emphasis>closewaveoutput()</emphasis>, but not in all cases will both functions be called.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Description of the parameters:</title>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>device</emphasis> is a system-dependent variable.
|
||||
It contains the value of the <emphasis>MIDI=device</emphasis> configuration option.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
Note that only one midi output device will be used at any one time.
|
||||
<emphasis>device</emphasis>
|
||||
may not have the same value throughout one session, but it will be closed
|
||||
before it is changed.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section><title>int midiready()</title>
|
||||
|
||||
<para>
|
||||
<emphasis>midiready()</emphasis> is called whenever the applications asks if the
|
||||
midi queue can accept more data.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Return values:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>BX_SOUND_OUTPUT_OK</emphasis> if the midi output device is ready.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>BX_SOUND_OUTPUT_ERR</emphasis> if it isn't ready.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
<emphasis>Note: </emphasis><emphasis>midiready()</emphasis> will be called a few times
|
||||
<emphasis>before</emphasis> the device is opened. If this is the case, it should
|
||||
always report that it is ready, otherwise the application (not Bochs)
|
||||
will hang.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>int sendmidicommand(int delta, int command, int length, Bit8u data[])</title>
|
||||
|
||||
<para>
|
||||
<emphasis>sendmidicommand()</emphasis>is called whenever a complete midi command has
|
||||
been written to the emulator. It should then send the given midi command to the midi hardware.
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Description of the parameters:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>delta</emphasis> 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.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>command</emphasis> 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.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>length</emphasis> is the number of data bytes that
|
||||
are contained in the data structure. This does <emphasis>not</emphasis> include the status
|
||||
byte which is not replicated in the data array. It can only be greater
|
||||
than 3 for SysEx messages (commands <emphasis>0xF0</emphasis> and <emphasis>0xF7</emphasis>)
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>data[]</emphasis> is the array of these data bytes,
|
||||
in the order they have in the standard MIDI specification.
|
||||
Note, it might be <emphasis>NULL</emphasis> if length==0.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>int closemidioutput()</title>
|
||||
|
||||
<para>
|
||||
<emphasis>closemidioutput()</emphasis> is called before shutting down Bochs or
|
||||
when the
|
||||
emulator gets the <emphasis>stop_output</emphasis> command through the emulator port.
|
||||
After this, no more output will be necessary until <emphasis>openmidioutput()</emphasis>
|
||||
is called again, but <emphasis>midiready()</emphasis> might still be called. It should do the following:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Wait for all remaining messages to be completed
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Reset and close the midi output device
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>int openwaveoutput(char *device)</title>
|
||||
|
||||
<para>
|
||||
<emphasis>openwaveoutput()</emphasis> is called when the first wave output occurs,
|
||||
and only if the selected wavemode is 1. It should do the following:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Open the given device, and prepare it for wave output
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
<emphasis>or</emphasis>
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Store the device name so that the device can be opened in <emphasis>startplayback()</emphasis>.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
<emphasis>openmidioutput()</emphasis> will always be called before <emphasis>openwaveoutput()</emphasis>,
|
||||
and <emphasis>closemidioutput()</emphasis>will always be called before <emphasis>closewaveoutput()</emphasis>, but not in all cases will both functions be called.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>openwaveoutput()</emphasis> will typically be called once, whereas
|
||||
<emphasis>startplayback()</emphasis> 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
|
||||
<emphasis>startplayback()</emphasis> as opposed to <emphasis>openwaveoutput()</emphasis>
|
||||
to ensure that it can be used by other applications while Bochs doesn't
|
||||
need it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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
|
||||
<emphasis>startwaveplayback</emphasis> function will be called very often, and it
|
||||
isn't a good idea to have it reopen the device every time.
|
||||
</para>
|
||||
|
||||
<para>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.
|
||||
</para>
|
||||
|
||||
<para>The parameters are the following: </para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>device</emphasis> is the wave device selected by
|
||||
the user. It is strictly system-dependent. The value is that of the
|
||||
<emphasis>WAVE=device</emphasis>
|
||||
configuration option.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Note that only one wave output device will be used at any one time.
|
||||
<emphasis>device</emphasis> may not have the same value throughout one session, but it will be closed
|
||||
before it is changed.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>int startwaveplayback(int frequency, int bits, int stereo, int format)</title>
|
||||
|
||||
<para>
|
||||
This function is called whenever the application starts a new DMA transfer. It should do the following:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Open the wave output device, unless <emphasis>openwaveoutput()</emphasis> did that
|
||||
already
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
Prepare the device for data and set the device parameters to those given
|
||||
in the function call
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
The parameters are the following:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>frequency</emphasis> is the desired frequency of the
|
||||
output. Because of the capabities of the SB16, it can have any value between
|
||||
5000 and 44,100.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>bits</emphasis> is either 8 or 16, denoting the resolution
|
||||
of one sample.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>stereo</emphasis> is either 1 for stereo output, or 0 for mono output.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>format</emphasis> is a bit-coded value (see below).
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Format Bits</title>
|
||||
<para>
|
||||
&FIXME; Insert FORMAT BITS table here
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>int waveready()</title>
|
||||
|
||||
<para>
|
||||
This is called whenever the emulator has another output buffer ready
|
||||
and would like to pass it to the output class. This happens every
|
||||
<emphasis>BX_SOUND_OUTPUT_WAVEPACKETSIZE</emphasis> bytes, or whenever a DMA transfer
|
||||
is done or aborted.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It should return whether the output device is ready for another buffer
|
||||
of <emphasis>BX_SOUND_OUTPUT_WAVEPACKETSIZE</emphasis> bytes.
|
||||
If <emphasis>BX_SOUND_OUTPUT_ERR</emphasis>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As opposed to <emphasis>midiready(), waveready()</emphasis> will <emphasis>not</emphasis> be
|
||||
called unless the device is open.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>int sendwavepacket(int length, Bit8u data[])</title>
|
||||
|
||||
<para>
|
||||
This function is called whenever a data packet of at most <emphasis>BX_SB16_WAVEPACKETSIZE</emphasis>
|
||||
is ready at the SB16 emulator. It should then do the following:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Send this wave packet to the wave hardware
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
This function <emphasis>has</emphasis> to be synchronous, meaning that it <emphasis>has</emphasis>
|
||||
to return immediately, and <emphasis>not</emphasis> 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, <emphasis>waveready()</emphasis> should return <emphasis>BX_SOUND_OUTPUT_ERR</emphasis>
|
||||
until the device accepts another block of data.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Parameters:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>length</emphasis> is the number of data bytes in
|
||||
the data stream. It will never be larger than <emphasis>BX_SB16_WAVEPACKETSIZE</emphasis>.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
<emphasis>data</emphasis> is the array of data bytes.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
The order of bytes in the data stream is the same as that in the Wave file format:
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Sequences of Databytes Table</title>
|
||||
<para>
|
||||
&FIXME; Insert Sequences of Databytes table here
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section><title>int stopwaveplayback()</title>
|
||||
|
||||
<para>
|
||||
This function is called at the end of a DMA transfer. It should do the following:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Close the output device if it was opened by <emphasis>startwaveplayback()</emphasis>.
|
||||
and it's not going to be opened soon. Which is almost impossible to tell.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section><title>int closewaveoutput()</title>
|
||||
|
||||
<para>
|
||||
This function is called just before Bochs exits. It should do the following:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Close the output device, if this hasn't been done by <emphasis>stopwaveplayback()</emphasis>.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Typically, <emphasis>stopwaveplayback()</emphasis> will be called several times, whenever
|
||||
a DMA transfer is done, where <emphasis>closewaveoutput()</emphasis> will only be called
|
||||
once. However, in the future it might be possible that <emphasis>openwaveoutput()</emphasis>
|
||||
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.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section> <!-- end of SB16 section-->
|
||||
|
||||
<section id="keymap"><title>How to write your own keymap table</title>
|
||||
|
Loading…
x
Reference in New Issue
Block a user