mirror of
https://github.com/holub/mame
synced 2025-05-17 03:10:43 +03:00

Should be added soon: - mute - speaker/microphone resampling To be added a little later: - compression - reverb Needs to be added by someone else: - coreaudio - direct - portaudio - xaudio2 - js
287 lines
9.9 KiB
ReStructuredText
287 lines
9.9 KiB
ReStructuredText
The device_sound_interface
|
|
==========================
|
|
|
|
.. contents:: :local:
|
|
|
|
|
|
1. The sound system
|
|
-------------------
|
|
|
|
The device sound interface is the entry point for devices that handle
|
|
sound input and/or output. The sound system is built on the concept
|
|
of *streams* which connect devices together with resampling and mixing
|
|
applied transparently as needed. Microphones (audio input) and
|
|
speakers (audio output) are specific known devices which use the same
|
|
interface.
|
|
|
|
2. Devices using device_sound_interface
|
|
---------------------------------------
|
|
|
|
2.1 Initialisation
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
Sound streams must be created in the device_start (or
|
|
interface_pre_start) method.
|
|
|
|
.. code-block:: C++
|
|
|
|
sound_stream *stream_alloc(int inputs, int outputs, int sample_rate, sound_stream_flags flags = STREAM_DEFAULT_FLAGS);
|
|
|
|
A stream is created with ``stream_alloc``. It takes the number of
|
|
input and output channels, the sample rate and optionally flags.
|
|
|
|
The sample rate can be SAMPLE_RATE_INPUT_ADAPTIVE,
|
|
SAMPLE_RATE_OUTPUT_ADAPTIVE or SAMPLE_RATE_ADAPTIVE. In that case the
|
|
chosen sample rate is the highest one amongs the inputs, outputs or
|
|
both respectively. In case of loop, the chosen sample rate is the
|
|
configured global sample rate.
|
|
|
|
The only available non-default flag is STREAM_SYNCHRONOUS. When set,
|
|
the sound generation method will be called for every sample
|
|
individually. It's necessary for dsps that run a program on every
|
|
sample. but on the other hand it's expensive, so only to be used when
|
|
required.
|
|
|
|
Devices can create multiple streams. It's rare though. Some yamaha
|
|
chips should but don't. Inputs and outputs are numbered from 0 and
|
|
collate all streams in the order they are created.
|
|
|
|
|
|
2.2 Sound input/output
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
virtual void sound_stream_update(sound_stream &stream);
|
|
|
|
This method is required to be implemented to consume the input samples
|
|
and/or compute the output ones. The stream to update for is passed as
|
|
the parameter. See the streams section, specifically sample access,
|
|
to see how to write the method.
|
|
|
|
|
|
2.3 Stream information
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
int inputs() const;
|
|
int outputs() const;
|
|
std::pair<sound_stream *, int> input_to_stream_input(int inputnum) const;
|
|
std::pair<sound_stream *, int> output_to_stream_output(int outputnum) const;
|
|
|
|
The method ``inputs`` returns the total number of inputs in the
|
|
streams created by the device. The method ``outputs`` similarly
|
|
counts the outputs. The other two methods allow to grab the stream
|
|
and channel number for the device corresponding to the global input or
|
|
output number.
|
|
|
|
|
|
2.4 Gain management
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
float input_gain(int inputnum) const;
|
|
float output_gain(int outputnum) const;
|
|
void set_input_gain(int inputnum, float gain);
|
|
void set_output_gain(int outputnum, float gain);
|
|
void set_route_gain(int source_channel, device_sound_interface *target, int target_channel, float gain);
|
|
|
|
float user_output_gain() const;
|
|
float user_output_gain(int outputnum) const;
|
|
void set_user_output_gain(float gain);
|
|
void set_user_output_gain(int outputnum, float gain);
|
|
|
|
Those methods allow to set the gain on every step of the routes
|
|
between streams. All gains are multipliers, with default value 1.0.
|
|
The steps are, from samples output in ``sound_stream_update`` to
|
|
samples read in the next device's ``sound_stream_update``:
|
|
|
|
* Per-channel output gain
|
|
* Per-channel user output gain
|
|
* Per-device user output gain
|
|
* Per-route gain
|
|
* Per-channel input gain
|
|
|
|
The user gains must not be set from the driver, they're for use by the
|
|
user interface (the sliders) and are saved in the game configuration.
|
|
The other gains are for driver/device use, and are saved in save
|
|
states.
|
|
|
|
|
|
2.5 Routing setup
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
device_sound_interface &add_route(u32 output, const device_finder<T, R> &target, double gain, u32 channel = 0)
|
|
device_sound_interface &add_route(u32 output, const char *target, double gain, u32 channel = 0);
|
|
device_sound_interface &add_route(u32 output, device_sound_interface &target, double gain, u32 channel = 0);
|
|
|
|
device_sound_interface &reset_routes();
|
|
|
|
Routes between devices, e.g. between streams, are set at configuration
|
|
time. The method ``add_route`` must be called on the source device
|
|
and gives the channel on the source device, the target device, the
|
|
gain, and optionally the channel on the target device. The constant
|
|
``ALL_OUTPUTS`` can be used to add a route from every channel of the
|
|
source to a given channel of the destination.
|
|
|
|
The method ``reset_routes`` is used to remove all the routes setup on
|
|
a given source device.
|
|
|
|
|
|
.. code-block:: C++
|
|
|
|
u32 get_sound_requested_inputs() const;
|
|
u32 get_sound_requested_outputs() const;
|
|
u64 get_sound_requested_inputs_mask() const;
|
|
u64 get_sound_requested_outputs_mask() const;
|
|
|
|
Those methods are useful for devices which want to behave differently
|
|
depending on what routes are setup on them. You get either the max
|
|
number of requested channel plus one (which is the number of channels
|
|
when all channels are routed, but is more useful when there are gaps)
|
|
or a mask of use for channels 0-63. Note that ``ALL_OUTPUTS`` does
|
|
not register any specific output or output count.
|
|
|
|
|
|
|
|
3. Streams
|
|
----------
|
|
|
|
3.1 Generalities
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
Streams are endpoints associated with devices and, when connected
|
|
together, ensure the transmission of audio data between them. A
|
|
stream has a number of inputs (which can be zero) and outputs (same)
|
|
and one sample rate which is common to all inputs and outputs. The
|
|
connections are setup at the machine configuration level and the sound
|
|
system ensures mixing and resampling is done transparently.
|
|
|
|
Samples in streams are encoded as sample_t. In the current
|
|
implementation, this is a float. Nominal values are between -1 and 1,
|
|
but clamping at the device level is not recommended (unless that's
|
|
what happens in hardware of course) because the gain values, volume
|
|
and effects can easily avoid saturation.
|
|
|
|
They are implemented in the class ``sound_stream``.
|
|
|
|
|
|
3.2 Characteristics
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
device_t &device() const;
|
|
bool input_adaptive() const;
|
|
bool output_adaptive() const;
|
|
bool synchronous() const;
|
|
u32 input_count() const;
|
|
u32 output_count() const;
|
|
u32 sample_rate() const;
|
|
attotime sample_period() const;
|
|
|
|
|
|
3.3 Sample access
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
s32 samples() const;
|
|
|
|
void put(s32 output, s32 index, sample_t sample);
|
|
void put_clamp(s32 output, s32 index, sample_t sample, sample_t clamp = 1.0);
|
|
void put_int(s32 output, s32 index, s32 sample, s32 max);
|
|
void put_int_clamp(s32 output, s32 index, s32 sample, s32 maxclamp);
|
|
void add(s32 output, s32 index, sample_t sample);
|
|
void add_int(s32 output, s32 index, s32 sample, s32 max);
|
|
void fill(s32 output, sample_t value, s32 start, s32 count);
|
|
void fill(s32 output, sample_t value, s32 start);
|
|
void fill(s32 output, sample_t value);
|
|
void copy(s32 output, s32 input, s32 start, s32 count);
|
|
void copy(s32 output, s32 input, s32 start);
|
|
void copy(s32 output, s32 input);
|
|
sample_t get(s32 input, s32 index) const;
|
|
sample_t get_output(s32 output, s32 index) const;
|
|
|
|
Those are the methods used to implement ``sound_stream_update``.
|
|
First ``samples`` tells how many samples to consume and/or generate.
|
|
The to-generate samples, if any, are pre-cleared (e.g. set to zero).
|
|
|
|
Input samples are retrieved with ``get``, where ``input`` is the
|
|
stream channel number and ``index`` the sample number.
|
|
|
|
Generated samples are written with the put variants. ``put`` sets a
|
|
sample_t in channel ``output`` at position ``index``. ``put_clamp``
|
|
does the same but first clamps the value to +/-``clamp``. ``put_int``
|
|
does it with an integer ``sample`` but pre-divides it by ``max``.
|
|
``put_int_clamp`` does the same but also pre-clamps within
|
|
-``maxclamp`` and ``maxclamp``-1, which is the normal range for a
|
|
2-complement value.
|
|
|
|
``add`` and ``add_int`` are similar but add the value of the sample to
|
|
what's there instead of replacing. ``get_output`` gets the currently
|
|
stored output value.
|
|
|
|
``fill`` sets a range of the an output channel to a given ``value``.
|
|
``start`` tells where to start (default index 0), ``count`` how many
|
|
(default up to the end of the buffer).
|
|
|
|
``copy`` does the same as fill but gets its value from the indentical
|
|
position in an input channel.
|
|
|
|
Note that clamping should not be used unless it actually happens in
|
|
hardware. Between gains and effects there is a fair chance saturation
|
|
can be avoided later in the chain.
|
|
|
|
|
|
|
|
3.4 Gain management
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
float user_output_gain() const;
|
|
void set_user_output_gain(float gain);
|
|
float user_output_gain(s32 output) const;
|
|
void set_user_output_gain(s32 output, float gain);
|
|
|
|
float input_gain(s32 input) const;
|
|
void set_input_gain(s32 input, float gain);
|
|
void apply_input_gain(s32 input, float gain);
|
|
float output_gain(s32 output) const;
|
|
void set_output_gain(s32 output, float gain);
|
|
void apply_output_gain(s32 output, float gain);
|
|
|
|
|
|
This is similar to the device gain control, with a twist: apply
|
|
multiplies the current gain by the given value.
|
|
|
|
|
|
3.5 Misc. actions
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
.. code-block:: C++
|
|
|
|
void set_sample_rate(u32 sample_rate);
|
|
void update();
|
|
|
|
The method ``set_sample_rate`` allows to change the sample rate of the
|
|
stream. The method ``update`` triggers a call of
|
|
``sound_stream_update`` on the stream and the ones it depends on to
|
|
reach the current time in terms of samples.
|
|
|
|
|
|
4. Devices using device_mixer_interface
|
|
---------------------------------------
|
|
|
|
The device mixer interface is used for devices that want to relay
|
|
sound in the device tree without acting on it. It's very useful on
|
|
for instance slot devices connectors, where the slot device may have
|
|
an audio connection with the main system. They are routed like every
|
|
other sound device, create the streams automatically and copy input to
|
|
output. Nothing needs to be done in the device.
|