You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2166 lines
36 KiB
2166 lines
36 KiB
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>The sound lowlevel interface</TITLE
|
|
><META
|
|
NAME="GENERATOR"
|
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
|
|
REL="HOME"
|
|
TITLE="Bochs Developers Guide"
|
|
HREF="index.html"><LINK
|
|
REL="UP"
|
|
TITLE="About the code"
|
|
HREF="about-the-code.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Sound Blaster 16 Emulation"
|
|
HREF="sb16-emulation-basics.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="Harddisk Images based on redologs"
|
|
HREF="harddisk-redologs.html"></HEAD
|
|
><BODY
|
|
CLASS="SECTION"
|
|
BGCOLOR="#FFFFFF"
|
|
TEXT="#000000"
|
|
LINK="#0000FF"
|
|
VLINK="#840084"
|
|
ALINK="#0000FF"
|
|
><DIV
|
|
CLASS="NAVHEADER"
|
|
><TABLE
|
|
SUMMARY="Header navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TH
|
|
COLSPAN="3"
|
|
ALIGN="center"
|
|
>Bochs Developers Guide</TH
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="left"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="sb16-emulation-basics.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
>Chapter 2. About the code</TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="harddisk-redologs.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H1
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="SOUND-LOWLOVEL-BASICS"
|
|
>2.9. The sound lowlevel interface</A
|
|
></H1
|
|
><P
|
|
>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
|
|
><P
|
|
>You should also have a look at the exisiting files, <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>SOUNDLOW.CC</I
|
|
></SPAN
|
|
>,
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>SOUNDMOD.CC</I
|
|
></SPAN
|
|
> and e.g. <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>SOUNDLNX.CC</I
|
|
></SPAN
|
|
> for Linux
|
|
or <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>SOUNDWIN.CC</I
|
|
></SPAN
|
|
> for Windows and their respective header files
|
|
to get an idea about how these things really work.</P
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H2
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN476"
|
|
>2.9.1. Files</A
|
|
></H2
|
|
><P
|
|
>The main include file for a lowlevel sound driver is <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>iodev.h</I
|
|
></SPAN
|
|
>.
|
|
It has all definitions for the system-independent functions that a sound driver
|
|
uses. The sound driver also needs to include <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>soundlow.h</I
|
|
></SPAN
|
|
> for
|
|
the definitions of the base classes <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_sound_lowlevel_c</I
|
|
></SPAN
|
|
>,
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_waveout_c</I
|
|
></SPAN
|
|
>, <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_wavein_c</I
|
|
></SPAN
|
|
>
|
|
and <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_midiout_c</I
|
|
></SPAN
|
|
>.</P
|
|
><P
|
|
>Additionally, every output driver will have an include file, which should be
|
|
included on top of <TT
|
|
CLASS="FILENAME"
|
|
>soundmod.cc</TT
|
|
> to allow the emulator
|
|
to use that driver. The code to initialize the object for the selected drivers
|
|
can be found in that file, so a soundcard emulation does not need to include
|
|
the specific driver headers.</P
|
|
><P
|
|
>To actually make the emulator use any specific driver as the default,
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>BX_SOUND_LOWLEVEL_NAME</I
|
|
></SPAN
|
|
> has to be set to the name of the
|
|
respective driver.</P
|
|
><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 <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>#if defined</I
|
|
></SPAN
|
|
> (OS-define) construct.
|
|
Also don't forget to add your file to the list of lowlevel sound object
|
|
files (<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>SOUNDLOW_OBJS</I
|
|
></SPAN
|
|
>) in the file <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>configure.in</I
|
|
></SPAN
|
|
>
|
|
and to regenerate the configure script,</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H2
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN493"
|
|
>2.9.2. Defines and strutures</A
|
|
></H2
|
|
><P
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
>#define BX_SOUNDLOW_WAVEPACKETSIZE 19200
|
|
|
|
#define BX_SOUNDLOW_OK 0
|
|
#define BX_SOUNDLOW_ERR 1
|
|
|
|
typedef struct {
|
|
Bit16u samplerate;
|
|
Bit8u bits;
|
|
Bit8u channels;
|
|
Bit8u format;
|
|
Bit16u volume;
|
|
} bx_pcm_param_t;
|
|
|
|
const bx_pcm_param_t default_pcm_param = {44100, 16, 2, 1};</PRE
|
|
></P
|
|
><P
|
|
>The maximum size of a wave data packet, the return values of the lowlevel
|
|
functions, the structure for the PCM parameters and the default parameter
|
|
set are also important for the sound driver development. They can be found
|
|
in the main include file <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>soundlow.h</I
|
|
></SPAN
|
|
>.</P
|
|
><P
|
|
>All lowlevel sound methods called from the device code have to return either
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>BX_SOUNDLOW_OK</I
|
|
></SPAN
|
|
> if the function was successful, or
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>BX_SOUNDLOW_ERR</I
|
|
></SPAN
|
|
> if not. If any of the initialization
|
|
functions fail, the device emulation should disable the affected feature.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H2
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN502"
|
|
>2.9.3. Classes</A
|
|
></H2
|
|
><P
|
|
>The following classes are involved with the sound lowlevel interface:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundmod_ctl_c</I
|
|
></SPAN
|
|
> is a pseudo device that is used to
|
|
initialize the sound drivers depending on the configuration.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_sound_lowlevel_c</I
|
|
></SPAN
|
|
> is the base class of the
|
|
lowlevel sound support. It has methods to return pointers to the objects for
|
|
the available services <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>waveout</I
|
|
></SPAN
|
|
>, <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>wavein</I
|
|
></SPAN
|
|
>
|
|
and <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>midiout</I
|
|
></SPAN
|
|
>. The base class returns NULL for all services.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_sound_dummy_c</I
|
|
></SPAN
|
|
> is derived from <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_sound_lowlevel_c</I
|
|
></SPAN
|
|
>.
|
|
It returns vaild pointers for all services, but the output classes are only
|
|
implemented as stubs and the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>wavein</I
|
|
></SPAN
|
|
> service returns silence.
|
|
This "dummy" driver is used whenever a OS specific driver does not implement
|
|
all services.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_waveout_c</I
|
|
></SPAN
|
|
>, <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_wavein_c</I
|
|
></SPAN
|
|
>
|
|
and <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_midiout_c</I
|
|
></SPAN
|
|
> are the base classes for the
|
|
services provided by the Bochs lowlevel sound support. Some methods are stubs
|
|
and used by the "dummy" sound driver, others are helper methods and used by
|
|
the OS specific implementations derived from these base classes.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_sound_OS_c</I
|
|
></SPAN
|
|
> is derived from <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_sound_lowlevel_c</I
|
|
></SPAN
|
|
>.
|
|
It returns vaild pointers for all services it implements for the selected
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>OS</I
|
|
></SPAN
|
|
> (operating system / library) or NULL for services it does
|
|
not implement. In the second case the Bochs sound init code falls back to the
|
|
"dummy" driver.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H2
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN530"
|
|
>2.9.4. The base class <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_sound_lowlevel_c</I
|
|
></SPAN
|
|
></A
|
|
></H2
|
|
><P
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
>class bx_sound_lowlevel_c : public logfunctions {
|
|
public:
|
|
bx_sound_lowlevel_c();
|
|
virtual ~bx_sound_lowlevel_c();
|
|
|
|
virtual bx_soundlow_waveout_c* get_waveout() {return NULL;}
|
|
virtual bx_soundlow_wavein_c* get_wavein() {return NULL;}
|
|
virtual bx_soundlow_midiout_c* get_midiout() {return NULL;}
|
|
|
|
protected:
|
|
bx_soundlow_waveout_c *waveout;
|
|
bx_soundlow_wavein_c *wavein;
|
|
bx_soundlow_midiout_c *midiout;
|
|
};</PRE
|
|
></P
|
|
><P
|
|
>The base class for sound lowlevel support is derived from the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>logfunctions</I
|
|
></SPAN
|
|
>
|
|
class to make the Bochs logging capabilities available in the sound driver code.
|
|
The constructor of this base class only initializes all pointers to NULL and
|
|
the destructor deletes the objects if necessary.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H2
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN537"
|
|
>2.9.5. The <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>waveout</I
|
|
></SPAN
|
|
> base class <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_waveout_c</I
|
|
></SPAN
|
|
></A
|
|
></H2
|
|
><P
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
>class bx_soundlow_waveout_c : public logfunctions {
|
|
public:
|
|
bx_soundlow_waveout_c();
|
|
virtual ~bx_soundlow_waveout_c();
|
|
|
|
virtual int openwaveoutput(const char *wavedev);
|
|
virtual int set_pcm_params(bx_pcm_param_t *param);
|
|
virtual int sendwavepacket(int length, Bit8u data[], bx_pcm_param_t *src_param);
|
|
virtual int get_packetsize();
|
|
virtual int output(int length, Bit8u data[]);
|
|
virtual int closewaveoutput();
|
|
|
|
virtual int register_wave_callback(void *, get_wave_cb_t wd_cb);
|
|
virtual void unregister_wave_callback(int callback_id);
|
|
|
|
virtual bx_bool mixer_common(Bit8u *buffer, int len);
|
|
protected:
|
|
void convert_pcm_data(Bit8u *src, int srcsize, Bit8u *dst, int dstsize, bx_pcm_param_t *param);
|
|
void start_mixer_thread(void);
|
|
|
|
bx_pcm_param_t emu_pcm_param, real_pcm_param;
|
|
int cvt_mult;
|
|
|
|
int cb_count;
|
|
struct {
|
|
void *device;
|
|
get_wave_cb_t cb;
|
|
} get_wave[BX_MAX_WAVE_CALLBACKS];
|
|
int pcm_callback_id;
|
|
};</PRE
|
|
></P
|
|
><P
|
|
>The base class for wave output support is also derived from the
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>logfunctions</I
|
|
></SPAN
|
|
> class. In addition to wave output methods
|
|
used from sound devices, it contains everything required for the mixer thread
|
|
feature (register PCM sources, convert data formats, start mixer).</P
|
|
><P
|
|
>The constructor should <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>not</I
|
|
></SPAN
|
|
> allocate the output devices.
|
|
This should be done in <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
>.</P
|
|
><P
|
|
>This table shows the waveout class methods, where are they called from and
|
|
if a platform / library specific implementation is required.
|
|
<DIV
|
|
CLASS="TABLE"
|
|
><A
|
|
NAME="AEN549"
|
|
></A
|
|
><P
|
|
><B
|
|
>Table 2-4. Waveout methods</B
|
|
></P
|
|
><TABLE
|
|
BORDER="1"
|
|
CLASS="CALSTABLE"
|
|
><COL><COL><COL><THEAD
|
|
><TR
|
|
><TH
|
|
>Method</TH
|
|
><TH
|
|
>Called from</TH
|
|
><TH
|
|
>Platform code</TH
|
|
></TR
|
|
></THEAD
|
|
><TBODY
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Sound init code</TD
|
|
><TD
|
|
>Required</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>set_pcm_params()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
> and <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sendwavepacket()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Required</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sendwavepacket()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Sound device emulation</TD
|
|
><TD
|
|
>Optional</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>get_packetsize()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Mixer thread</TD
|
|
><TD
|
|
>Optional</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>output()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Mixer thread</TD
|
|
><TD
|
|
>Required</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>closewaveoutput()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Sound device emulation</TD
|
|
><TD
|
|
>Optional</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>register_wave_callback()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
> and sound device emulation</TD
|
|
><TD
|
|
>Optional</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>unregister_wave_callback()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>class destructor and sound device emulation</TD
|
|
><TD
|
|
>Optional</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>mixer_common()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Mixer thread</TD
|
|
><TD
|
|
>Optional</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>convert_pcm_data()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Internal</TD
|
|
><TD
|
|
>No</TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>start_mixer_thread()</I
|
|
></SPAN
|
|
></TD
|
|
><TD
|
|
>Internal</TD
|
|
><TD
|
|
>No</TD
|
|
></TR
|
|
></TBODY
|
|
></TABLE
|
|
></DIV
|
|
> </P
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN616"
|
|
>2.9.5.1. int openwaveoutput(const char *wavedev)</A
|
|
></H3
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
> is called when the sound output subsystem
|
|
initializes. It should do the following:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Set up the default PCM parameters for output.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Open the given device, and prepare it for wave output.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Register the callback function for the PCM buffer queue (<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sendwavepacket()</I
|
|
></SPAN
|
|
>
|
|
adds the output to the queue and the mixer thread gets it from there).</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Start the mixer thread, unless the sound library has it's own one (e.g. SDL).</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
> will only be called once, whereas
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>set_pcm_params()</I
|
|
></SPAN
|
|
> is called whenever the PCM samplerate
|
|
has been changed.</P
|
|
><P
|
|
>The parameters are the following:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>wavedev</I
|
|
></SPAN
|
|
> is the wave output device selected by the user.
|
|
It is strictly system-dependent. Some sound libraries currently ignore this
|
|
value and use the default one instead. The value is that of the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>waveout=device</I
|
|
></SPAN
|
|
>
|
|
configuration parameter of the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sound</I
|
|
></SPAN
|
|
> bochsrc option.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>Note that only one wave output device will be used at any one time.
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>wavedev</I
|
|
></SPAN
|
|
> may not have the same value throughout one session,
|
|
but it will be closed before it is changed.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN642"
|
|
>2.9.5.2. int set_pcm_params(bx_pcm_param_t *param)</A
|
|
></H3
|
|
><P
|
|
>This function should called from <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
> to initialize
|
|
the output device with the default parameters and from <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sendwavepacket()</I
|
|
></SPAN
|
|
>
|
|
whenever the samplerate has been changed in the emulated sound device.
|
|
It should do the following:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Open the wave output device, unless <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
> did that
|
|
already.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Prepare the device for data and set the device parameters to those given
|
|
in the function call.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>The parameters are the following:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>param</I
|
|
></SPAN
|
|
> is a pointer to a structure containing the set of
|
|
parameters required to set up a sound device for PCM output.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>The members of the structure <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_pcm_param_t</I
|
|
></SPAN
|
|
> are these:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>samplerate</I
|
|
></SPAN
|
|
> is the desired frequency of the
|
|
output. Because of the capabities of the soundcards, it can have any value
|
|
between 5000 and 48,000.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bits</I
|
|
></SPAN
|
|
> is either 8 or 16, denoting the resolution
|
|
of one sample.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>channels</I
|
|
></SPAN
|
|
> is the number of channels (2 for stereo output,
|
|
or 1 for mono output.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>format</I
|
|
></SPAN
|
|
> is a bit-coded value (see below).</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>volume</I
|
|
></SPAN
|
|
> is the output volume to be used by the mixer code.
|
|
The 16 bit value consists of two 8 bit values for each channel.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
><DIV
|
|
CLASS="TABLE"
|
|
><A
|
|
NAME="AEN677"
|
|
></A
|
|
><P
|
|
><B
|
|
>Table 2-5. format bits</B
|
|
></P
|
|
><TABLE
|
|
BORDER="1"
|
|
CLASS="CALSTABLE"
|
|
><COL><COL><THEAD
|
|
><TR
|
|
><TH
|
|
>Bit number</TH
|
|
><TH
|
|
>Meaning</TH
|
|
></TR
|
|
></THEAD
|
|
><TBODY
|
|
><TR
|
|
><TD
|
|
> 0 (LSB) </TD
|
|
><TD
|
|
><P
|
|
> 0: unsigned data </P
|
|
><P
|
|
> 1: signed data </P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
> 1..6 </TD
|
|
><TD
|
|
> Type of codec (see below) </TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
> 7 </TD
|
|
><TD
|
|
><P
|
|
> 0: no reference byte </P
|
|
><P
|
|
> 1: with reference byte </P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
> 8..x </TD
|
|
><TD
|
|
> reserved (0) </TD
|
|
></TR
|
|
></TBODY
|
|
></TABLE
|
|
></DIV
|
|
>
|
|
|
|
<DIV
|
|
CLASS="TABLE"
|
|
><A
|
|
NAME="AEN701"
|
|
></A
|
|
><P
|
|
><B
|
|
>Table 2-6. codecs</B
|
|
></P
|
|
><TABLE
|
|
BORDER="1"
|
|
CLASS="CALSTABLE"
|
|
><COL><COL><THEAD
|
|
><TR
|
|
><TH
|
|
>Value</TH
|
|
><TH
|
|
>Meaning</TH
|
|
></TR
|
|
></THEAD
|
|
><TBODY
|
|
><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 (Creative Labs format) </TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
> 3 </TD
|
|
><TD
|
|
> 2.4-bit (3-bit) ADPCM (Creative Labs format) </TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
> 4 </TD
|
|
><TD
|
|
> 4-bit ADPCM (Creative Labs format) </TD
|
|
></TR
|
|
></TBODY
|
|
></TABLE
|
|
></DIV
|
|
></P
|
|
><P
|
|
>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.</P
|
|
><P
|
|
>The number of bytes per sample can be calculated from this as (bits / 8) * channels.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN726"
|
|
>2.9.5.3. int sendwavepacket(int length, Bit8u data[], bx_pcm_param_t *src_param)</A
|
|
></H3
|
|
><P
|
|
>This function is called whenever a data packet of at most
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>BX_SOUNDLOW_WAVEPACKETSIZE</I
|
|
></SPAN
|
|
> is ready at the soundcard
|
|
emulation. It should then do the following:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Add this wave packet to the waveout buffer chain after converting to 16 bit signed
|
|
little endian. If the samplerate has been changed <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>set_pcm_params()</I
|
|
></SPAN
|
|
>
|
|
should be called to update the sound hardware settings.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>Parameters:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>length</I
|
|
></SPAN
|
|
> is the number of data bytes in
|
|
the data stream. It will never be larger than <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>BX_SOUNDLOW_WAVEPACKETSIZE</I
|
|
></SPAN
|
|
>.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>data</I
|
|
></SPAN
|
|
> is the array of data bytes.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>src_param</I
|
|
></SPAN
|
|
> is a pointer to a structure containing the PCM parameters
|
|
(see above).</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>The order of bytes in the data stream is the same as that in the Wave file format:
|
|
|
|
<DIV
|
|
CLASS="TABLE"
|
|
><A
|
|
NAME="AEN747"
|
|
></A
|
|
><P
|
|
><B
|
|
>Table 2-7. wave output types</B
|
|
></P
|
|
><TABLE
|
|
BORDER="1"
|
|
CLASS="CALSTABLE"
|
|
><COL><COL><THEAD
|
|
><TR
|
|
><TH
|
|
>Output type</TH
|
|
><TH
|
|
>Sequence of data bytes</TH
|
|
></TR
|
|
></THEAD
|
|
><TBODY
|
|
><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
|
|
></TBODY
|
|
></TABLE
|
|
></DIV
|
|
></P
|
|
><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
|
|
soundcard emulations are not limited to this.
|
|
site.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN768"
|
|
>2.9.5.4. int get_packetsize()</A
|
|
></H3
|
|
><P
|
|
>This function is called from the mixer thread to retrieve the size of a wave data
|
|
packet based on the current samplerate. By default the packet size is big enough
|
|
to send output for 0.1 seconds. If the host sound driver / library uses a different
|
|
value, this value should be returned with this method.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN771"
|
|
>2.9.5.5. int output(int length, Bit8u data[])</A
|
|
></H3
|
|
><P
|
|
>This function is called from the mixer thread to send the mixed PCM output to
|
|
the host sound hardware.</P
|
|
><P
|
|
>Parameters:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>length</I
|
|
></SPAN
|
|
> is the number of data bytes in
|
|
the data stream. It will never be larger than the value returned from <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>get_packetsize</I
|
|
></SPAN
|
|
>.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>data</I
|
|
></SPAN
|
|
> is the array of data bytes.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN783"
|
|
>2.9.5.6. int closewaveoutput()</A
|
|
></H3
|
|
><P
|
|
>This function is currently only called from the soundcard emulation if the "file"
|
|
driver is used. This makes the runtime change of the output file possible.
|
|
By default this method does nothing and the wave output device is closed in the
|
|
destructor of the specific class.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN786"
|
|
>2.9.5.7. int register_wave_callback(void *arg, get_wave_cb_t wd_cb)</A
|
|
></H3
|
|
><P
|
|
>This function is called from <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
> to register
|
|
the function to retrieve data from the PCM output buffer chain. Other sound
|
|
emulation devices (e.g. OPL3, PC speaker) can register a function to poll the
|
|
data from the device emulation. The return value is the ID of the registered
|
|
function and it is usually used to unregister the source.</P
|
|
><P
|
|
>Parameters:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>arg</I
|
|
></SPAN
|
|
> is the pointer to the device emulation object.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>wd_cb</I
|
|
></SPAN
|
|
> is the pointer to a static function that returns
|
|
wave data from the device emulation. This function is usually called from the
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>mixer_common()</I
|
|
></SPAN
|
|
> method.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN799"
|
|
>2.9.5.8. void unregister_wave_callback(int callback_id)</A
|
|
></H3
|
|
><P
|
|
>This function is usually called from the destructor of the sound emulation
|
|
device to unregister it's registered function to poll PCM data. If the
|
|
driver / library doesn't use the default mixer thread, a specific implementation
|
|
of this method my be required.</P
|
|
><P
|
|
>Parameter:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>callback_id</I
|
|
></SPAN
|
|
> is the ID of the function to unregister.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN807"
|
|
>2.9.5.9. bx_bool mixer_common(Bit8u *buffer, int len)</A
|
|
></H3
|
|
><P
|
|
>This is the main wave output mixing function. It is called from the mixer
|
|
thread, it polls the wave data from all registered sources and it mixes the
|
|
data using a simple algorithm (addition and clipping). The return value
|
|
indicates whether or not wave data is available for output.</P
|
|
><P
|
|
>Parameters:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>buffer</I
|
|
></SPAN
|
|
> is the output buffer for the wave data.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>len</I
|
|
></SPAN
|
|
> is the maximum length of the output buffer.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN818"
|
|
>2.9.5.10. void convert_pcm_data(Bit8u *src, int srcsize, Bit8u *dst, int dstsize, bx_pcm_param_t *param)</A
|
|
></H3
|
|
><P
|
|
>This function converts the PCM data sent from the sound device emulation to the
|
|
16 bit stereo signed little endian format. It should be called in <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sendwavepacket()</I
|
|
></SPAN
|
|
>
|
|
after allocating the output buffer in the buffer queue. Future versions might
|
|
also perform resampling here.</P
|
|
><P
|
|
>Parameters:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>src</I
|
|
></SPAN
|
|
> is the buffer containing data sent from the sound emulation.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>srcsize</I
|
|
></SPAN
|
|
> is the amount of wave data to be converted.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>dst</I
|
|
></SPAN
|
|
> is the buffer for the converted wave data.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>dstsize</I
|
|
></SPAN
|
|
> is the size of the destination buffer.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>param</I
|
|
></SPAN
|
|
> is a pointer to the struture containing the format
|
|
parameters of the source data.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN839"
|
|
>2.9.5.11. void start_mixer_thread()</A
|
|
></H3
|
|
><P
|
|
>This function starts the mixer thread and it should be called in <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveoutput()</I
|
|
></SPAN
|
|
>
|
|
unless the sound driver / library has it's own way to do this (e.g. SDL). This
|
|
function also initializes the mutex required for locking the mixer thread when
|
|
adding data to the buffer chain or unregistering a source.</P
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H2
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN843"
|
|
>2.9.6. The <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>wavein</I
|
|
></SPAN
|
|
> base class <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_wavein_c</I
|
|
></SPAN
|
|
></A
|
|
></H2
|
|
><P
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
>class bx_soundlow_wavein_c : public logfunctions {
|
|
public:
|
|
bx_soundlow_wavein_c();
|
|
virtual ~bx_soundlow_wavein_c();
|
|
|
|
virtual int openwaveinput(const char *wavedev, sound_record_handler_t rh);
|
|
virtual int startwaverecord(bx_pcm_param_t *param);
|
|
virtual int getwavepacket(int length, Bit8u data[]);
|
|
virtual int stopwaverecord();
|
|
|
|
static void record_timer_handler(void *);
|
|
void record_timer(void);
|
|
protected:
|
|
int record_timer_index;
|
|
int record_packet_size;
|
|
sound_record_handler_t record_handler;
|
|
};</PRE
|
|
></P
|
|
><P
|
|
>The base class for wave input support is also derived from the
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>logfunctions</I
|
|
></SPAN
|
|
> class. It contains the framework for wave
|
|
input (recording) support. The base class is used by the "dummy" sound driver
|
|
and returns silence to let the input mechanism of the soundcard emulation work.
|
|
The soundcard emulator object needs to implement a callback function to notifies
|
|
the emulation about available data. This function usually calls the driver method
|
|
to get the wave data packet. The driver objects has a periodic timer with an
|
|
interval of 0.1 emulated seconds that is active during recording. The timer
|
|
handler processes the wave data recorded with platform or library specific
|
|
function and finally notifies the emulator.</P
|
|
><P
|
|
>The constructor of the base class only initializes the timer ID. OS specific
|
|
implementations should initialize other required members here.</P
|
|
><P
|
|
>The destructor of the base class only calls <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>stopwaverecord()</I
|
|
></SPAN
|
|
>.
|
|
OS specific implementations should close the input device here if necessary.</P
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN854"
|
|
>2.9.6.1. int openwaveinput(char *device, sound_record_handler_t rh)</A
|
|
></H3
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveinput()</I
|
|
></SPAN
|
|
> is called when the sound emulation first
|
|
receives a sound recording command. It should do the following:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Open the given device, and prepare it for wave input</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>or</I
|
|
></SPAN
|
|
></P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Store the device name so that the device can be opened in <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>startwaverecord()</I
|
|
></SPAN
|
|
>.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>In addition to this the record handler value should be stored and the record timer
|
|
should be registered. This is the definition of record handler callback function:
|
|
<PRE
|
|
CLASS="SCREEN"
|
|
>typedef Bit32u (*sound_record_handler_t)(void *arg, Bit32u len);</PRE
|
|
></P
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveinput()</I
|
|
></SPAN
|
|
> will only be called once, whereas
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>startwaverecord()</I
|
|
></SPAN
|
|
> is called for every new wave input
|
|
command to the soundcard emulation. If feasible, it could be useful to open
|
|
and/or lock the input device in <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>startwaverecord()</I
|
|
></SPAN
|
|
> as
|
|
opposed to <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openwaveinput()</I
|
|
></SPAN
|
|
> to ensure that it can be used
|
|
by other applications while Bochs doesn't need it.</P
|
|
><P
|
|
>The parameters are the following: </P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>device</I
|
|
></SPAN
|
|
> is the wave device selected by the user. It is
|
|
strictly system-dependent. The value is that of the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>wavein=device</I
|
|
></SPAN
|
|
>
|
|
configuration parameter of the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sound</I
|
|
></SPAN
|
|
> bochsrc option.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>rh</I
|
|
></SPAN
|
|
> is a pointer to the record handler method of the sound
|
|
emulation. When sound recording is active, this handler is called periodicly to
|
|
notify the sound emulation about newly available data.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>Note that only one wave input device will be used at any one time.
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>device</I
|
|
></SPAN
|
|
> may not have the same value throughout one session,
|
|
but it will be closed before it is changed.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN886"
|
|
>2.9.6.2. int startwaverecord(bx_pcm_param_t *param)</A
|
|
></H3
|
|
><P
|
|
>This method receives a pointer to the required PCM parameters (samplerate,
|
|
data format) as the argument and it should set up the input device for recording,
|
|
calculate the size of the recording packet for 0.1 second and start the record
|
|
timer.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN889"
|
|
>2.9.6.3. int getwavepacket(int length, Bit8u data[])</A
|
|
></H3
|
|
><P
|
|
>This method is called from the record handler method of the sound emulation device
|
|
to retrieve the recorded wave data packet.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN892"
|
|
>2.9.6.4. int stopwaverecord()</A
|
|
></H3
|
|
><P
|
|
>This method is called to stop the wave recording. It deactivates the timer that
|
|
calls the method to perform the recording.</P
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H2
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN895"
|
|
>2.9.7. The <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>midiout</I
|
|
></SPAN
|
|
> base class <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>bx_soundlow_midiout_c</I
|
|
></SPAN
|
|
></A
|
|
></H2
|
|
><P
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
>class bx_soundlow_midiout_c : public logfunctions {
|
|
public:
|
|
bx_soundlow_midiout_c();
|
|
virtual ~bx_soundlow_midiout_c();
|
|
|
|
virtual int openmidioutput(const char *mididev);
|
|
virtual int midiready();
|
|
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
|
|
virtual int closemidioutput();
|
|
};</PRE
|
|
></P
|
|
><P
|
|
>The base class for MIDI output support is also derived from the
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>logfunctions</I
|
|
></SPAN
|
|
> class.</P
|
|
><P
|
|
>OS specific implementations should initialize required members in the constructor.</P
|
|
><P
|
|
>The destructor of the base class only calls <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>closemidioutput()</I
|
|
></SPAN
|
|
>.
|
|
OS specific implementations should close the input device here if necessary.</P
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN906"
|
|
>2.9.7.1. int openmidioutput(char *device)</A
|
|
></H3
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openmidioutput()</I
|
|
></SPAN
|
|
> is called when the first midi output starts.
|
|
It is only called if the midi output to the driver is active (midimode 1). It should
|
|
prepare the given MIDI hardware for receiving midi commands.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
>Description of the parameters:</P
|
|
><P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>mididev</I
|
|
></SPAN
|
|
> is a system-dependent variable.
|
|
The value is that of the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>midiout=device</I
|
|
></SPAN
|
|
>
|
|
configuration parameter of the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sound</I
|
|
></SPAN
|
|
> bochsrc option.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Note that only one midi output device will be used at any one time.
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>device</I
|
|
></SPAN
|
|
>
|
|
may not have the same value throughout one session, but it will be closed
|
|
before it is changed.</P
|
|
></LI
|
|
></UL
|
|
></P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN923"
|
|
>2.9.7.2. int midiready()</A
|
|
></H3
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>midiready()</I
|
|
></SPAN
|
|
> is called whenever the applications asks if the
|
|
midi queue can accept more data.</P
|
|
><P
|
|
>Return values:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>BX_SOUNDLOW_OK</I
|
|
></SPAN
|
|
> if the midi output device is ready.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>BX_SOUNDLOW_ERR</I
|
|
></SPAN
|
|
> if it isn't ready.</P
|
|
></LI
|
|
></UL
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>Note: </I
|
|
></SPAN
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>midiready()</I
|
|
></SPAN
|
|
> will be called a few times
|
|
<SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>before</I
|
|
></SPAN
|
|
> the device is opened. If this is the case, it should
|
|
always report that it is ready, otherwise the application (not Bochs)
|
|
will hang.</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN939"
|
|
>2.9.7.3. int sendmidicommand(int delta, int command, int length, Bit8u data[])</A
|
|
></H3
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>sendmidicommand()</I
|
|
></SPAN
|
|
>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.</P
|
|
><P
|
|
>Description of the parameters:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>delta</I
|
|
></SPAN
|
|
> 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.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>command</I
|
|
></SPAN
|
|
> 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.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>length</I
|
|
></SPAN
|
|
> is the number of data bytes that
|
|
are contained in the data structure. This does <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>not</I
|
|
></SPAN
|
|
> include the status
|
|
byte which is not replicated in the data array. It can only be greater
|
|
than 3 for SysEx messages (commands <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>0xF0</I
|
|
></SPAN
|
|
> and <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>0xF7</I
|
|
></SPAN
|
|
>)</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>data[]</I
|
|
></SPAN
|
|
> is the array of these data bytes,
|
|
in the order they have in the standard MIDI specification.
|
|
Note, it might be <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>NULL</I
|
|
></SPAN
|
|
> if length==0.</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECTION"
|
|
><H3
|
|
CLASS="SECTION"
|
|
><A
|
|
NAME="AEN961"
|
|
>2.9.7.4. int closemidioutput()</A
|
|
></H3
|
|
><P
|
|
><SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>closemidioutput()</I
|
|
></SPAN
|
|
> is called before shutting down Bochs or
|
|
when the
|
|
emulator gets the <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>stop_output</I
|
|
></SPAN
|
|
> command through the emulator port.
|
|
After this, no more output will be necessary until <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>openmidioutput()</I
|
|
></SPAN
|
|
>
|
|
is called again, but <SPAN
|
|
CLASS="emphasis"
|
|
><I
|
|
CLASS="EMPHASIS"
|
|
>midiready()</I
|
|
></SPAN
|
|
> might still be called. It should
|
|
do the following:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Wait for all remaining messages to be completed</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Reset and close the midi output device</P
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="NAVFOOTER"
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"><TABLE
|
|
SUMMARY="Footer navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="sb16-emulation-basics.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="index.html"
|
|
ACCESSKEY="H"
|
|
>Home</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="harddisk-redologs.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Sound Blaster 16 Emulation</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="about-the-code.html"
|
|
ACCESSKEY="U"
|
|
>Up</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Harddisk Images based on redologs</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
>
|