feat(core/audio): music-ended callback (CONV-03)

Ja::Engine exposa setOnMusicEnded(std::function<void()>). Quan
updateCurrentMusic detecta que la pista actual ha acabat de drenar
(times == 0 && stream buit) s'atura primer via stopMusic i després
s'invoca el callback — així un eventual playMusic des del callback pot
començar amb l'engine en estat net.

Audio proxeia amb setOnMusicEnded. Contracte documentat: s'executa al
mateix thread que Audio::update (render loop); no fer operacions
blocants.

Cap consumidor actualment; només exposa l'API per quan calgui.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
JailDesignerandClaude Opus 4.7 committed 2026-04-20 13:31:47 +02:00
1 parent 4e0dcfe739
commit 2ec6fd23b6
4 files changed
+31 -5

No files matched your search

+8
View File
@@ -144,6 +144,14 @@ void Audio::fadeOutMusic(int milliseconds) {
}
}
// Registra un callback que el motor dispararà quan la pista actual acabi de
// drenar (times == 0 + stream buit). S'executa al mateix thread que
// Audio::update (render loop); els consumidors no poden fer I/O blocant.
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_
void Audio::setOnMusicEnded(std::function<void()> callback) {
if (engine_) { engine_->setOnMusicEnded(std::move(callback)); }
}
// Consulta directament l'estat a Ja i el projecta al subconjunt d'estats que
// exposa Audio (INVALID/DISABLED de Ja col·lapsen a STOPPED — la capa d'usuari
// només vol saber si està sonant, pausat o parat).
+7 -5
View File
@@ -1,10 +1,11 @@
#pragma once
#include <cmath> // Per a std::lround
#include <cstdint> // Per a int8_t, uint8_t
#include <memory> // Per a std::unique_ptr
#include <string> // Per a string
#include <utility> // Per a move
#include <cmath> // Per a std::lround
#include <cstdint> // Per a int8_t, uint8_t
#include <functional> // Per a std::function
#include <memory> // Per a std::unique_ptr
#include <string> // Per a string
#include <utility> // Per a move
// Forward-declares per no incloure core/audio/jail_audio.hpp al header. Els
// tres símbols (Music/Sound per al punter que exposa la API i Engine per al
@@ -74,6 +75,7 @@ class Audio {
void resumeMusic(); // Continua la música pausada
void stopMusic(); // Aturar completament la música
void fadeOutMusic(int milliseconds); // Fosa de sortida de la música (muta globals de Ja)
void setOnMusicEnded(std::function<void()> callback); // Callback disparat quan la pista actual acaba de drenar (CONV-03)
// --- Control de sons ---
void playSound(const std::string& name, Group group = Group::GAME); // Reproduir so puntual per nom (muta globals de Ja)
+8
View File
@@ -151,7 +151,11 @@ namespace Ja {
pumpMusic(current_music_);
if (current_music_->times == 0 && SDL_GetAudioStreamAvailable(current_music_->stream) == 0) {
// La pista ha acabat de drenar naturalment. L'aturem primer (deixa
// l'engine en estat consistent) i llavors invoquem el callback;
// així un eventual playMusic des del callback comença net.
stopMusic();
if (on_music_ended_) { on_music_ended_(); }
}
}
@@ -319,6 +323,10 @@ namespace Ja {
return music_volume_;
}
void Engine::setOnMusicEnded(std::function<void()> callback) {
on_music_ended_ = std::move(callback);
}
void Engine::onMusicDeleted(const Music* music) {
if (music == nullptr) { return; }
if (current_music_ == music) {
+8
View File
@@ -4,6 +4,7 @@
#include <SDL3/SDL.h>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -133,6 +134,12 @@ namespace Ja {
void crossfadeMusic(Music* music, int crossfade_ms, int loop = -1);
[[nodiscard]] auto getMusicState() const -> MusicState;
auto setMusicVolume(float volume) -> float;
// Registra un callback que es disparà quan la música actual acabi de
// drenar naturalment (times == 0 + stream buit). Es crida DESPRÉS de
// stopMusic, així que el callback pot invocar playMusic sense córrer.
// S'executa al mateix thread que Engine::update (render loop); no fer
// operacions blocants.
void setOnMusicEnded(std::function<void()> callback);
// Notifica al motor que un Music s'està destruint: si és el current_music
// s'atura abans que els seus recursos (stream/vorbis) deixin de ser vàlids.
void onMusicDeleted(const Music* music);
@@ -166,6 +173,7 @@ namespace Ja {
SDL_AudioDeviceID sdl_audio_device_{0};
OutgoingMusic outgoing_music_;
FadeState incoming_fade_;
std::function<void()> on_music_ended_;
// NOLINTNEXTLINE(readability-identifier-naming) — convenció projecte: private static amb sufix _
static Engine* active_;