https://gitlab.synchro.net/main/sbbs/-/commit/897325cdb8ee22b19b9cf91a
Modified Files:
src/conio/cterm.c cterm.h cterm_cterm.c sdl_con.c src/syncterm/ooii.c ripper.c src/xpdev/xpbeep.c xpbeep.h
Log Message:
xpbeep: node-list FIFO mixer, dB volumes, soft-clip, -12 dB stream base
Replaces the per-stream fixed 1 s S16 ring with a head/tail linked list
of producer-supplied frame buffers. The caller malloc()s the PCM data
and xp_audio_append() transfers ownership; the channel free()s it once
the mixer has fully consumed the node. Append is non-blocking in the
steady state — it only waits when the per-node metadata allocation
itself fails and we need the mixer to drop a buf to free memory. This
unblocks the scene-music use case where queuing an arbitrarily long
playlist must return to the terminal immediately.
Fold xp_audio_append_faded + xp_audio_append into a single entry point
that takes a NULLable xp_audio_opts_t carrying per-entry volume (dB,
summed with the stream base), fade_in/fade_out frames, crossfade, and
loop. Envelopes live on the node and are evaluated per-sample in the
mixer, which means looping bufs rise from silence exactly once and a
crossfade append starts the overlap immediately — old tail fades out
via an overlay envelope while the new buf fades in, both mixing
concurrently until the overlay expires. XP_AUDIO_OPTS_INIT presets
unity dB on all fields so = {0} is equivalent.
Rework xp_mixer_pull to accumulate all streams into an int32_t scratch
(grown under mixer_lock, persistent) and apply tanh soft-clipping in a
single narrow pass at the end — replaces the old per-add int16_t
saturate that distorted multi-stream mixes the moment any contribution
pushed the running sum to full scale. Volumes now compose in dB (per-
entry + stream base → one powf per channel per buf per pull) with 0 dB
as unity.
Lift the -12 dB headroom reduction out of xptone_makewave (both the
U8-wrap noisy path and the double clean path) and apply it as stream
base dB instead: cterm->music_stream and cterm->fx_stream open at
-12 dB, xptone opens its ephemeral stream at -12 dB, sdl_beep bakes
-12 dB into its static wave once at generation. Synth output keeps
its full 16-bit resolution; OOII/RIP samples now ride at the same
level as tones instead of being 12 dB louder than the rest of the mix.
Add cterm_play_fx/_tone/_u8 on a per-cterm fx_stream (lazy-opened,
distinct from music_stream so MF/MB ANSI-music state doesn't interact
with RIP/OOII SFX). Migrate ripper.c rv_sound cases (A, BE, BL, M, P,
R) and the ~40 xp_play_sample call sites in ooii.c to the new API;
drop background bool since the persistent fx_stream handles sequencing.
Teach parse_rip_new to forward the 0x0E music terminator to cterm when
the preceding CSI introducer (| unconditional, M when music_enable ==
ENABLED, N when music_enable >= BANSI) actually arms
cterm_accumulate_music. Previously parse_rip ate all SO/SI bytes as
RIPterm text-window controls, which left the music accumulator stuck
until the connection ended.
xptone chunks and play_music notes switch to per-chunk malloc + append transfer; ripper rv_sound A/BE/BL/M/P/R go through cterm_play_fx* and
no longer re-open the device per tone.
Co-Authored-By: Claude Opus 4.7 (1M context) <
[email protected]>
---
■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net