From ee34638c890c26614f3219a3646ab1560652d4ed Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Mon, 20 Apr 2026 12:03:10 +0200 Subject: [PATCH] refactor(core/audio): helper fadeProgress compartit per fades (DUP-03) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updateOutgoingFade i updateIncomingFade calculaven el mateix PERCENT lineal (ELAPSED / duration_ms) per separat i prenien decisions sobre si el fade havia acabat comparant bytes. Ara fadeProgress(FadeState) retorna [0..1] i concentra la corba del fade — si cal passar-la a logarítmica o quadràtica, es toca en un sol lloc. També protegeix duration_ms<=0 com a "fade completat" (abans el divisor donava una divisió per zero en debug o un progrés >> 1 en release). Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/audit-core-audio.md | 2 +- source/core/audio/jail_audio.hpp | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/audit-core-audio.md b/docs/audit-core-audio.md index 924c444..50cc73b 100644 --- a/docs/audit-core-audio.md +++ b/docs/audit-core-audio.md @@ -32,7 +32,7 @@ Los IDs se mantienen estables una vez asignados. Cada entrada apunta al(los) fic |----|---------------|----------|-----------|--------|-------| | DUP-01 | `audio.cpp:58-101` | Dos `playMusic` (nombre/puntero) repiten el bloque crossfade/stop+play | Menor | DONE | `playMusicInternal(Ja::Music*, loop, crossfade_ms)` privat; els dos overloads fan gating + name-handling i deleguen el dispatch | | DUP-02 | `audio.cpp:172-185` | `setSoundVolume`/`setMusicVolume` idéntica estructura de clamp+gate+producto | Menor | DONE | `effectiveVolume(volume, channel_enabled)` privat; els dos setters deleguen | -| DUP-03 | `jail_audio.hpp:196-222` | `updateOutgoingFade`/`updateIncomingFade` comparten la curva lineal | Menor | PENDING | Helper `fadeProgress(FadeState&) -> float` | +| DUP-03 | `jail_audio.hpp:196-222` | `updateOutgoingFade`/`updateIncomingFade` comparten la curva lineal | Menor | DONE | `fadeProgress(FadeState&)` concentra la corba en un sol lloc; també cobreix `duration_ms <= 0` com a 1.0 | | DUP-04 | `jail_audio.hpp:391-471` | `fadeOutMusic`/`crossfadeMusic` repiten "destruir outgoing + pre-fill + robar stream + reset vorbis" | Importante | PENDING | Función privada `stealCurrentIntoOutgoing(int ms)` | | DUP-05 | `jail_audio.hpp:575-631` | `pauseChannel`/`resumeChannel`/`stopChannel` repiten dispatch `channel==-1 / [0,MAX)` | Menor | PENDING | Helper `forEachTargetChannel(int, fn)` | diff --git a/source/core/audio/jail_audio.hpp b/source/core/audio/jail_audio.hpp index 7a224ae..9039d0b 100644 --- a/source/core/audio/jail_audio.hpp +++ b/source/core/audio/jail_audio.hpp @@ -197,18 +197,27 @@ namespace Ja { // --- Core Functions --- + // Retorna el progrés lineal [0..1] d'un fade. 1.0 vol dir completat. Única + // font de la corba del fade: si es vol canviar a logarítmica/quadràtica, + // s'edita aquí i afecta fade-in i fade-out alhora. + inline auto fadeProgress(const FadeState& fade) -> float { + if (fade.duration_ms <= 0) { return 1.0F; } + const Uint64 ELAPSED = SDL_GetTicks() - fade.start_time; + if (ELAPSED >= static_cast(fade.duration_ms)) { return 1.0F; } + return static_cast(ELAPSED) / static_cast(fade.duration_ms); + } + // Avança el fade-out de l'outgoing music (crossfade o fade-out a silenci). inline void updateOutgoingFade() { if (outgoing_music.stream == nullptr || !outgoing_music.fade.active) { return; } - const Uint64 ELAPSED = SDL_GetTicks() - outgoing_music.fade.start_time; - if (ELAPSED >= static_cast(outgoing_music.fade.duration_ms)) { + const float PROGRESS = fadeProgress(outgoing_music.fade); + if (PROGRESS >= 1.0F) { SDL_DestroyAudioStream(outgoing_music.stream); outgoing_music.stream = nullptr; outgoing_music.fade.active = false; } else { - const float PERCENT = static_cast(ELAPSED) / static_cast(outgoing_music.fade.duration_ms); - SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0F - PERCENT)); + SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0F - PROGRESS)); } } @@ -216,13 +225,12 @@ namespace Ja { inline void updateIncomingFade() { if (!incoming_fade.active) { return; } - const Uint64 ELAPSED = SDL_GetTicks() - incoming_fade.start_time; - if (ELAPSED >= static_cast(incoming_fade.duration_ms)) { + const float PROGRESS = fadeProgress(incoming_fade); + if (PROGRESS >= 1.0F) { incoming_fade.active = false; SDL_SetAudioStreamGain(current_music->stream, music_volume); } else { - const float PERCENT = static_cast(ELAPSED) / static_cast(incoming_fade.duration_ms); - SDL_SetAudioStreamGain(current_music->stream, music_volume * PERCENT); + SDL_SetAudioStreamGain(current_music->stream, music_volume * PROGRESS); } }