AudioOut.cpp resets a port with `port = Port{}`, which copy-list-initializes
its HostGainRamp member. With the default argument on the explicit
constructor, clang rejects that ("chosen constructor is explicit in
copy-initialization"), so libSceAudioOut does not build on macOS. The default
constructor is now separate and implicit; the one taking the ramp length
stays explicit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
libSceVideoOut reads and changes the shared host volume state, and linking libSceAudioOut for it puts a second shared library with its own static SDL2 into libSceVideoOut. Both libraries already link libScePad, so the headers that describe that state move there first; the include paths and guards follow.
They are called across libraries like the other _nid_no_patch and _nid_postfix helpers, so their symbols must not depend on the C++ mangling of a particular compiler.
The state sits behind a mutex and publishes its gain through an atomic, so the audio threads read it without locking. HostVolumeConfigure replaces the state, parsing ANYPS5_VOLUME and ANYPS5_MUTE_ON_FOCUS_LOSS before changing anything, so an invalid value leaves it untouched and throws an error naming the variable.
A flag is exactly 0 or 1 and a level a whole number from 0 to 100. Anything else, including an empty value, throws an error that names the variable and quotes the value.
HostGainFilter returns the title's own pointer when the ramp is at unity with a unity target, so the default path copies nothing and multiplies nothing. Otherwise it applies the ramp to a scratch copy, or in place when the data already is the scratch buffer, and never writes the title's memory.
The float overload uses the same per-frame gain as the 16-bit one, converted exactly from the fixed-point value, and does not clamp. At unity with a unity target it touches nothing.
HostGainRamp moves a 16.16 fixed-point gain toward its target by a constant step per frame, so the ramp is exact, continues across buffers and applies one gain to every channel of a frame. 16-bit samples are rounded and saturate. At unity with a unity target nothing is touched.
With the option on, a window without focus counts as muted and gaining focus ends it. The focus mute is derived from the focus and the option, so it never replaces the user's own mute. With the option off, focus changes change nothing.
SDL's WASAPI enumeration drops failures silently: EnumAudioEndpoints or
GetCount errors leave the list empty, and a device whose metadata lookup
fails is left out, so an empty list does not prove there is no default
endpoint. The skip now also requires IMMDeviceEnumerator's
GetDefaultAudioEndpoint(eRender, eConsole), the call SDL's default open
makes, to return ERROR_NOT_FOUND. The probe runs only when the wasapi list
is empty.
audio_out_default_open gains wasapi_zero_default (empty WASAPI list, the
probe finds an endpoint, the default is opened) and checks that the probe
runs only for an empty WASAPI list.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
SDL documents that a default open can succeed when SDL_GetNumAudioDevices
returns zero, for instance ALSA whose default PCM works without device
hints. The shortcut now applies only to the wasapi driver, which
enumerates active render endpoints synchronously when the subsystem
starts; with none, its default open has no endpoint to use and fails after
SDL's 8 s retry.
audio_out_default_open runs AudioOut.cpp against a stubbed SDL in four
modes: zero devices on alsa with a working default, zero on wasapi, a
positive count and an unknown count.
Co-Authored-By: Claude Opus 5.5 <[email protected]>