sound docs: small corrections after doing a quick read

This commit is contained in:
hap 2025-04-28 12:54:29 +02:00
parent 57dad8563b
commit f68b2d87a1
7 changed files with 62 additions and 48 deletions

View File

@ -100,12 +100,11 @@ emu.add_machine_post_load_notifier(callback)
to a previously saved state. Returns a to a previously saved state. Returns a
:ref:`notifier subscription <luascript-ref-notifiersub>`. :ref:`notifier subscription <luascript-ref-notifiersub>`.
emu.register_sound_update(callback) emu.register_sound_update(callback)
Add a callback to receive new samples that have been created. THe Add a callback to receive new samples that have been created. The samples
samples are coming from the sound devices for which the hook are coming from the sound devices for which the hook property has been set
property has been set to true. The callback gets one parameter to true. The callback gets one parameter which is a hash with device tag
which is a hash with device tag as key and a (channel-sized) as key and a (channel-sized) vector of (buffer-sized) vector of samples
vector of (buffer-sized) vector of in the -1..1 range.
samples in the -1..1 range.
emu.print_error(message) emu.print_error(message)
Print an error message. Print an error message.
emu.print_warning(message) emu.print_warning(message)

View File

@ -633,7 +633,7 @@ Sound device interface
--------------------- ---------------------
Wraps MAMEs ``device_sound_interface`` class which is a mix-in implemented by Wraps MAMEs ``device_sound_interface`` class which is a mix-in implemented by
devices that inputs and/or ouputs sound. devices that input and/or output sound.
Instantiation Instantiation
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
@ -659,11 +659,11 @@ sound.speaker (read-only)
sound.io_positions[] (read-only) sound.io_positions[] (read-only)
Non-empty only for microphones and speakers, indicates the positions of Non-empty only for microphones and speakers, indicates the positions of
the inputs or outputs as (x, y, z) coordinates (f.i. [-0.2, 0.0, 1.0]) the inputs or outputs as (x, y, z) coordinates (e.g. [-0.2, 0.0, 1.0])
sound.io_names[] (read-only) sound.io_names[] (read-only)
Non-empty only for microphones and speakers, indicates the positions of Non-empty only for microphones and speakers, indicates the positions of
the inputs or outputs as strings (f.i. Front Left) the inputs or outputs as strings (e.g. Front Left)
sound.hook sound.hook
A boolean indicating whether to tap the output samples of this device in A boolean indicating whether to tap the output samples of this device in

View File

@ -25,7 +25,7 @@ Adding an effect requires working on four parts:
The audio_effect class in the aeffect sources provides three things: The audio_effect class in the aeffect sources provides three things:
* an enum value to designate the effect type and which much match its * an enum value to designate the effect type and which must match its
position in the chain (iow, the effect chain follows the enum order), position in the chain (iow, the effect chain follows the enum order),
in the .h in the .h
* the effect name in the audio_effect::effect_names array in the .cpp * the effect name in the audio_effect::effect_names array in the .cpp
@ -36,7 +36,7 @@ The audio_effect class in the aeffect sources provides three things:
3. audio_effects/youreffect.* 3. audio_effects/youreffect.*
----------------------------- -----------------------------
This is where you implement the effect. It takes the shape of a This is where you implement the effect. It takes the shape of an
audio_effect_youreffect class which derives from audio_effect. audio_effect_youreffect class which derives from audio_effect.
The methods to implement are: The methods to implement are:
@ -61,7 +61,7 @@ allows to tell how many samples should still be available of the
previous input frame. Note that this number must not depend on the previous input frame. Note that this number must not depend on the
parameters and only on the sample rate. parameters and only on the sample rate.
An effect have a number of parameters that can come from three sources: An effect has a number of parameters that can come from three sources:
* fixed default value * fixed default value
* equivalent effect object from the default effect chain * equivalent effect object from the default effect chain
@ -72,7 +72,7 @@ gets the value of ``def`` in the constructor. When it's nullptr, the
value to use when not set by the user is the fixed one, otherwise it's value to use when not set by the user is the fixed one, otherwise it's
the one in ``m_default``. the one in ``m_default``.
At a minimum an effect should have a parameter allowing to bypass it. At minimum an effect should have a parameter allowing to bypass it.
Managing a parameter uses four methods: Managing a parameter uses four methods:
@ -131,7 +131,7 @@ than the parameter setting calls are made from.
4. frontend/mame/ui/audioeffects.cpp 4. frontend/mame/ui/audioeffects.cpp
------------------------------------ ------------------------------------
There it suffices to add a creation of the menu Here it suffices to add a creation of the menu
menu_audio_effect_youreffect in menu_audio_effects::handle. The menu menu_audio_effect_youreffect in menu_audio_effects::handle. The menu
effect will pick the effect names from audio_effect (in aeffect.*). effect will pick the effect names from audio_effect (in aeffect.*).

View File

@ -32,19 +32,19 @@ input and output channels, the sample rate and optionally flags.
The sample rate can be SAMPLE_RATE_INPUT_ADAPTIVE, The sample rate can be SAMPLE_RATE_INPUT_ADAPTIVE,
SAMPLE_RATE_OUTPUT_ADAPTIVE or SAMPLE_RATE_ADAPTIVE. In that case the SAMPLE_RATE_OUTPUT_ADAPTIVE or SAMPLE_RATE_ADAPTIVE. In that case the
chosen sample rate is the highest one amongs the inputs, outputs or chosen sample rate is the highest one among the inputs, outputs or
both respectively. In case of loop, the chosen sample rate is the both respectively. In case of loop, the chosen sample rate is the
configured global sample rate. configured global sample rate.
The only available non-default flag is STREAM_SYNCHRONOUS. When set, The only available non-default flag is STREAM_SYNCHRONOUS. When set,
the sound generation method will be called for every sample the sound generation method will be called for every sample
individually. It's necessary for dsps that run a program on every 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 sample. but on the other hand it's expensive, so only to be used when
required. required.
Devices can create multiple streams. It's rare though. Some yamaha Devices can create multiple streams. It's rare though. Some Yamaha
chips should but don't. Inputs and outputs are numbered from 0 and chips should but don't. Inputs and outputs are numbered from 0 and
collate all streams in the order they are created. arrange all streams in the order they are created.
2.2 Sound input/output 2.2 Sound input/output
@ -140,7 +140,7 @@ a given source device.
u64 get_sound_requested_outputs_mask() const; u64 get_sound_requested_outputs_mask() const;
Those methods are useful for devices which want to behave differently Those methods are useful for devices which want to behave differently
depending on what routes are setup on them. You get either the max depending on what routes are set up on them. You get either the max
number of requested channel plus one (which is the number of channels 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) 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 or a mask of use for channels 0-63. Note that ``ALL_OUTPUTS`` does
@ -158,7 +158,7 @@ Streams are endpoints associated with devices and, when connected
together, ensure the transmission of audio data between them. A together, ensure the transmission of audio data between them. A
stream has a number of inputs (which can be zero) and outputs (same) 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 and one sample rate which is common to all inputs and outputs. The
connections are setup at the machine configuration level and the sound connections are set up at the machine configuration level and the sound
system ensures mixing and resampling is done transparently. system ensures mixing and resampling is done transparently.
Samples in streams are encoded as sample_t. In the current Samples in streams are encoded as sample_t. In the current
@ -226,7 +226,7 @@ does it with an integer ``sample`` but pre-divides it by ``max``.
what's there instead of replacing. ``get_output`` gets the currently what's there instead of replacing. ``get_output`` gets the currently
stored output value. stored output value.
``fill`` sets a range of the an output channel to a given ``value``. ``fill`` sets a range of an output channel to a given ``value``.
``start`` tells where to start (default index 0), ``count`` how many ``start`` tells where to start (default index 0), ``count`` how many
(default up to the end of the buffer). (default up to the end of the buffer).

View File

@ -92,7 +92,7 @@ At a minimum, the class must include a constructor and an enum picking up the co
If the CPU has its own dispatch table, the class must also include the declaration (but not definition) of **disasm_entries**, **do_exec_full** and **do_exec_partial**, the declaration and definition of **disasm_disassemble** (identical for all classes but refers to the class-specific **disasm_entries** array) and include the .inc file (which provides the missing definitions). Support for the generation must also be added to CPU.mak. If the CPU has its own dispatch table, the class must also include the declaration (but not definition) of **disasm_entries**, **do_exec_full** and **do_exec_partial**, the declaration and definition of **disasm_disassemble** (identical for all classes but refers to the class-specific **disasm_entries** array) and include the .inc file (which provides the missing definitions). Support for the generation must also be added to CPU.mak.
If the CPU has in addition its own opcodes, their declaration must be done through a macro, see f.i. m65c02. The .inc file will provide the definitions. If the CPU has in addition its own opcodes, their declaration must be done through a macro, see e.g. m65c02. The .inc file will provide the definitions.
Dispatch tables Dispatch tables
@ -365,7 +365,7 @@ A negative icount means that the CPU won't be able to do anything for some time
Multi-dispatch variants Multi-dispatch variants
----------------------- -----------------------
Some variants currently in the process of being supported change instruction set depending on an internal flag, either switching to a 16-bits mode or changing some register accesses to memory accesses. This is handled by having multiple dispatch tables for the CPU, the d<CPU>.lst not being 257 entries anymore but 256*n+1. The variable **inst_state_base** must select which instruction table to use at a given time. It must be a multiple of 256, and is in fact simply OR-ed to the first instruction byte to get the dispatch table index (aka inst_state). Some variants currently in the process of being supported change instruction set depending on an internal flag, either switching to a 16-bit mode or changing some register accesses to memory accesses. This is handled by having multiple dispatch tables for the CPU, the d<CPU>.lst not being 257 entries anymore but 256*n+1. The variable **inst_state_base** must select which instruction table to use at a given time. It must be a multiple of 256, and is in fact simply OR-ed to the first instruction byte to get the dispatch table index (aka inst_state).
Current TO-DO: Current TO-DO:
-------------- --------------

View File

@ -20,14 +20,16 @@ The OSD interface is designed to allow three levels of support,
depending on what the API allows and the amount of effort to expend. depending on what the API allows and the amount of effort to expend.
Those are: Those are:
* Level 1: One or more audio targets, only one stream allowed per target (aka exclusive mode) * Level 1: One or more audio targets, only one stream allowed per target
(aka exclusive mode)
* Level 2: One or more audio targets, multiple streams per target * Level 2: One or more audio targets, multiple streams per target
* Level 3: One or more audio targets, multiple streams per target, user-visible per-stream-channel volume control * Level 3: One or more audio targets, multiple streams per target, user-visible
per-stream-channel volume control
In any case we support having the user use an external interface to In any case we support having the user use an external interface to
change the target of a stream and, in level 3, change the volumes. By change the target of a stream and, in level 3, change the volumes. By
support we mean storing the information in the per-game configuration support we mean storing the information in the per-game configuration
and keeping in the internal UI in sync. and keeping the internal UI in sync.
Terminology Terminology
@ -35,8 +37,11 @@ Terminology
For this module, we use the terms: For this module, we use the terms:
* node: some object we can send audio to. Can be physical, like speakers, or virtual, like an effect system. It should have a unique, user-presentable name for the UI. * node: some object we can send audio to. Can be physical, like speakers,
* port: a channel of a node, has a name (non-unique, like "front left") and a 3D position or virtual, like an effect system. It should have a unique, user-presentable
name for the UI.
* port: a channel of a node, has a name (non-unique, like "front left") and a
3D position
* stream: a connection to a node with allows to send audio to it * stream: a connection to a node with allows to send audio to it
@ -82,10 +87,14 @@ which follows this structure,
In that code, four names must be chosen: In that code, four names must be chosen:
* MODULE_SUPPORT_KEY some #define coming from the genie scripts to tell that this particular module can be compiled (like NO_USE_PIPEWIRE or SDLMAME_MACOSX) * MODULE_SUPPORT_KEY some #define coming from the genie scripts to tell that
* sound_module_class is the name of the class which makes up the module (like sound_coreaudio) this particular module can be compiled (like NO_USE_PIPEWIRE or SDLMAME_MACOSX)
* module_name is the name to be used in -sound <xxx> to select that particular module (like coreaudio) * sound_module_class is the name of the class which makes up the module
* SOUND_MODULE_KEY is a symbol that represents the module internally (like SOUND_COREAUDIO) (like sound_coreaudio)
* module_name is the name to be used in -sound <xxx> to select that particular
module (like coreaudio)
* SOUND_MODULE_KEY is a symbol that represents the module internally (like
SOUND_COREAUDIO)
The file path needs to be added to scripts/src/osd/modules.lua in The file path needs to be added to scripts/src/osd/modules.lua in
osdmodulesbuild() and the module reference to osdmodulesbuild() and the module reference to
@ -123,12 +132,12 @@ The full interface is:
virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override; virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override;
The class sound_module provides default for minimum capabilities: one The class sound_module provides defaults for minimum capabilities: one
stereo target and stream at default sample rate. To support that, stereo target and stream at default sample rate. To support that,
only *init*, *exit* and *stream_update* need to be implemented. only *init*, *exit* and *stream_update* need to be implemented.
*init* is called at startup and *exit* when quitting and can do *init* is called at startup and *exit* when quitting and can do
whatever they need to do. *stream_sink_update* will be called on a whatever they need to do. *stream_sink_update* will be called on a
regular basis with a buffer of sample_this_frame*2*int16_t with the regular basis with a buffer of sample_this_frame * 2 * int16_t with the
audio to play. From this point in the documentation we'll assume more audio to play. From this point in the documentation we'll assume more
than a single stereo channel is wanted. than a single stereo channel is wanted.
@ -139,8 +148,10 @@ Capabilities
Two methods are used by the module to indicate the level of capability Two methods are used by the module to indicate the level of capability
of the module: of the module:
* split_streams_per_source() should return true when having multiple streams for one target is expected (e.g. Level 2 or 3) * split_streams_per_source() should return true when having multiple streams
* external_per_channel_volume() should return true when the streams have per-channel volume control that can be externally controlled (e.g. Level 3) for one target is expected (e.g. Level 2 or 3)
* external_per_channel_volume() should return true when the streams have
per-channel volume control that can be externally controlled (e.g. Level 3)
Hardware information and generations Hardware information and generations
@ -151,7 +162,7 @@ can change at any time (bluetooth devices coming and going, usb
hot-plugging...) and that the module has some way to keep tabs on what hot-plugging...) and that the module has some way to keep tabs on what
is happening, possibly using multi-threading. To keep it is happening, possibly using multi-threading. To keep it
lightweight-ish, we use the concept of a *generation* which is a lightweight-ish, we use the concept of a *generation* which is a
32-bits number that is incremented by the module every time something 32-bit number that is incremented by the module every time something
changes. The core checks the current generation value at least once changes. The core checks the current generation value at least once
every update (once per frame, usually) and if it changed asks for the every update (once per frame, usually) and if it changed asks for the
new state and detects and handles the differences. *generation* new state and detects and handles the differences. *generation*
@ -211,17 +222,20 @@ of the host and the module. This state is:
* m_id: The numeric ID of the node * m_id: The numeric ID of the node
* m_rate: The minimum, maximum and preferred sample rate for the node * m_rate: The minimum, maximum and preferred sample rate for the node
* m_port_names: The vector of port names * m_port_names: The vector of port names
* m_port_positions: The vector of 3D position of the ports. Refer to src/emu/speaker.h for the "standard" positions * m_port_positions: The vector of 3D position of the ports. Refer to
src/emu/speaker.h for the "standard" positions
* m_sinks: Number of sinks (inputs) * m_sinks: Number of sinks (inputs)
* m_sources: Number of sources (outputs) * m_sources: Number of sources (outputs)
* m_default_sink: ID of the node that is the current "system default" for audio output, 0 if there's no such concept * m_default_sink: ID of the node that is the current "system default" for
audio output, 0 if there's no such concept
* m_default_source: same for audio input (currently unused) * m_default_source: same for audio input (currently unused)
* m_streams: The vector of active streams (*stream_info*) * m_streams: The vector of active streams (*stream_info*)
* m_id: The numeric ID of the stream * m_id: The numeric ID of the stream
* m_node: The target node of the stream * m_node: The target node of the stream
* m_volumes: empty if *external_per_channel_volume* is false, current volume value per-channel otherwise * m_volumes: empty if *external_per_channel_volume* is false, current volume
value per-channel otherwise
IDs, for nodes and streams, are (independant) 32-bit unsigned non-zero IDs, for nodes and streams, are (independant) 32-bit unsigned non-zero
values associated to respectively nodes and streams. IDs should not values associated to respectively nodes and streams. IDs should not
@ -262,7 +276,7 @@ Input and output streams
virtual void stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override; virtual void stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override;
virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override; virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override;
Streams are the concept used to send or recieve audio from/to the host Streams are the concept used to send or receive audio from/to the host
audio system. A stream is first opened through *stream_sink_open* for audio system. A stream is first opened through *stream_sink_open* for
speakers and *stream_source_open* for microphones and targets a speakers and *stream_source_open* for microphones and targets a
specific node at a specific sample rate. It is given a name for use specific node at a specific sample rate. It is given a name for use
@ -270,7 +284,7 @@ by the host sound services for user UI purposes (currently the game
name if split_streams_per_source is false, the name if split_streams_per_source is false, the
speaker_device/microphone_device tag if true). The returned ID must speaker_device/microphone_device tag if true). The returned ID must
be a non-zero, never-used-before for streams value in case of success. be a non-zero, never-used-before for streams value in case of success.
Failures, like when the node went away between the get_information Failures, like when the node went away between the *get_information*
call and the open one, should be silent and return zero. call and the open one, should be silent and return zero.
*stream_set_volumes* is used only when *external_per_channel_volume* *stream_set_volumes* is used only when *external_per_channel_volume*
@ -321,12 +335,12 @@ Helper class *abuffer*
}; };
The class *abuffer* is a helper provided by *sound_module* to buffer The class *abuffer* is a helper provided by *sound_module* to buffer
audio in output or output. It automatically drops data when there is audio input or output. It automatically drops data when there is
an overflow and duplicates the last sample on underflow. It must an overflow and duplicates the last sample on underflow. It must
first be initialized with the number of channels, which can be first be initialized with the number of channels, which can be
retrieved with *channels()* if needed. *push* sends retrieved with *channels()* if needed. *push* sends
*samples* * *channels* 16-bits samples in the buffer. *get* retrieves *samples* * *channels* 16-bit samples in the buffer. *get* retrieves
*samples* * *channels* 16-bits samples from the buffer, on a fifo basis. *samples* * *channels* 16-bit samples from the buffer, on a FIFO basis.
It is not protected against multithreading, but uses no class It is not protected against multithreading, but uses no class
variables. So just don't read and write from one specific abuffer variables. So just don't read and write from one specific abuffer

View File

@ -317,7 +317,7 @@ stereo system output.
A channel mapping maps between one channel of speaker or a microphone A channel mapping maps between one channel of speaker or a microphone
and one channel of a system input or output. It can be a little and one channel of a system input or output. It can be a little
tedious, but it allows for instance to take two mono speakers and turn tedious, but it allows for instance to take two mono speakers and turn
it into the left and right channels of a system output, whcih is it into the left and right channels of a system output, which is
useful for some cabinets. useful for some cabinets.
Every mapping has a configurable volume associated. Every mapping has a configurable volume associated.
@ -355,6 +355,7 @@ parameters of the Default chain are fixed. The default chain allows
to create a global setup that one likes and have it applied everywhere to create a global setup that one likes and have it applied everywhere
by default. by default.
Filter effect Filter effect
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
@ -365,7 +366,7 @@ low-pass filter (defaulting to off) allows to reproduce how muffled
the sound of a number of cabinets and TVs were. the sound of a number of cabinets and TVs were.
The Q factor defines how sharp the transition is, the higher the The Q factor defines how sharp the transition is, the higher the
sharper. Over 0.7 the filter starts amplifying the frequencies arount sharper. Over 0.7 the filter starts amplifying the frequencies around
the cutoff though, which can be surprising. the cutoff though, which can be surprising.
@ -384,7 +385,7 @@ Not implemented yet.
EQ effect EQ effect
~~~~~~~~~ ~~~~~~~~~
The 5-band parametric equalizer allows to amplify or reduce certains The 5-band parametric equalizer allows to amplify or reduce certain
bands of frequency in the spectrum. The three middle filters, and bands of frequency in the spectrum. The three middle filters, and
also the extreme ones if configured as "Peak", change frequencies also the extreme ones if configured as "Peak", change frequencies
around the cutoff. The Q factor selects the sharpness of the peak, around the cutoff. The Q factor selects the sharpness of the peak,