mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
The mixer applied each voice's mix volume and each splitter destination's volume to a whole 5 ms frame as one constant, so the level jumped at the frame's first sample whenever the game moved a volume, which is heard as a click. It now keeps what each voice and each splitter destination was mixed with in the frame before and goes from there to the new value in equal steps across the frame's samples, as the console's renderer does. An unchanged volume stays on the constant path. A voice that has just started, one that was silent in the frame before or was moved to another mix or splitter, a destination that is new or was moved, and the first frame after the renderer starts take the new volume at once. NX2NAVI_AUDIO_RAMP=0 turns the ramps off. The audio statistics line counts the render passes that ramped a volume. tests/audio_mixer_check.py builds the mixer with the rest of the runtime stubbed and checks the ramps and the cases that must not ramp. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
43 lines
1.9 KiB
Python
43 lines
1.9 KiB
Python
"""Build and run tests/audio_mixer_check.c: runtime/audio_mixer.c with the rest of the runtime stubbed. No game files
|
|
and no audio device (the mixer runs as with NX2NAVI_AUDIO=none); SDL3 is only linked.
|
|
|
|
Windows: python tests\\audio_mixer_check.py [--toolchain C:/msys64/ucrt64]
|
|
Linux: python tests/audio_mixer_check.py (clang and SDL3 development files via pkg-config)
|
|
"""
|
|
import argparse
|
|
import os
|
|
import shlex
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MSYS = Path(r'C:\msys64\ucrt64')
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser(description=__doc__)
|
|
ap.add_argument('--toolchain', type=Path, default=MSYS if os.name == 'nt' and MSYS.exists() else None)
|
|
a = ap.parse_args()
|
|
work = ROOT / 'build' / 'test' / 'audio_mixer'
|
|
work.mkdir(parents=True, exist_ok=True)
|
|
env = dict(os.environ)
|
|
if a.toolchain:
|
|
env['PATH'] = str(a.toolchain / 'bin') + os.pathsep + env.get('PATH', '')
|
|
cc = os.environ.get('CC') or str(a.toolchain / 'bin' / 'clang.exe')
|
|
sdl = ['-L', str(a.toolchain / 'lib'), '-lSDL3']
|
|
else:
|
|
cc = os.environ.get('CC') or shutil.which('clang') or 'cc'
|
|
sdl = shlex.split(subprocess.check_output(['pkg-config', '--cflags', '--libs', 'sdl3'], text=True))
|
|
exe = work / ('audio_mixer_check.exe' if os.name == 'nt' else 'audio_mixer_check')
|
|
# the default build's target (x86-64-v3: AVX2 and FMA), so the mixing loops are compiled as they ship
|
|
subprocess.check_call([cc, '-std=gnu11', '-O2', '-fno-strict-aliasing', '-march=x86-64-v3', '-Wall',
|
|
'-Wno-unused-function', '-I', str(ROOT / 'runtime'),
|
|
str(ROOT / 'tests' / 'audio_mixer_check.c'), '-o', str(exe), *sdl, '-lm'], env=env)
|
|
return subprocess.run([str(exe)], env=env, timeout=60).returncode
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|