violat jail_audio amb JA_CrossfadeMusic i globals a structs
fix: fade_initial_volume
This commit is contained in:
@@ -16,7 +16,7 @@ zones:
|
|||||||
|
|
||||||
- name: forest
|
- name: forest
|
||||||
tileSetFile: forest.gif
|
tileSetFile: forest.gif
|
||||||
music: 574070_KUVO_Farewell_to_school.ogg
|
music: 574071_EA_DTV.ogg
|
||||||
bgColor: 35
|
bgColor: 35
|
||||||
|
|
||||||
- name: sewers
|
- name: sewers
|
||||||
|
|||||||
@@ -38,10 +38,15 @@ Audio::~Audio() {
|
|||||||
// Método principal
|
// Método principal
|
||||||
void Audio::update() {
|
void Audio::update() {
|
||||||
JA_Update();
|
JA_Update();
|
||||||
|
|
||||||
|
// Sincronizar estado: detectar cuando la música se para (ej. fade-out completado)
|
||||||
|
if (instance && instance->music_.state == MusicState::PLAYING && JA_GetMusicState() != JA_MUSIC_PLAYING) {
|
||||||
|
instance->music_.state = MusicState::STOPPED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reproduce la música
|
// Reproduce la música (con crossfade opcional)
|
||||||
void Audio::playMusic(const std::string& name, const int loop) {
|
void Audio::playMusic(const std::string& name, const int loop, const int crossfade_ms) {
|
||||||
bool new_loop = (loop != 0);
|
bool new_loop = (loop != 0);
|
||||||
|
|
||||||
// Si ya está sonando exactamente la misma pista y mismo modo loop, no hacemos nada
|
// Si ya está sonando exactamente la misma pista y mismo modo loop, no hacemos nada
|
||||||
@@ -51,20 +56,19 @@ void Audio::playMusic(const std::string& name, const int loop) {
|
|||||||
|
|
||||||
// Intentar obtener recurso; si falla, no tocar estado
|
// Intentar obtener recurso; si falla, no tocar estado
|
||||||
auto* resource = Resource::Cache::get()->getMusic(name);
|
auto* resource = Resource::Cache::get()->getMusic(name);
|
||||||
if (resource == nullptr) {
|
if (resource == nullptr) return;
|
||||||
// manejo de error opcional
|
|
||||||
return;
|
if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) {
|
||||||
|
// Crossfade: fade-out de la pista actual + fade-in de la nueva
|
||||||
|
JA_CrossfadeMusic(resource, crossfade_ms, loop);
|
||||||
|
} else {
|
||||||
|
// Cambio inmediato
|
||||||
|
if (music_.state == MusicState::PLAYING) {
|
||||||
|
JA_StopMusic();
|
||||||
|
}
|
||||||
|
JA_PlayMusic(resource, loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si hay algo reproduciéndose, detenerlo primero (si el backend lo requiere)
|
|
||||||
if (music_.state == MusicState::PLAYING) {
|
|
||||||
JA_StopMusic(); // sustituir por la función de stop real del API si tiene otro nombre
|
|
||||||
}
|
|
||||||
|
|
||||||
// Llamada al motor para reproducir la nueva pista
|
|
||||||
JA_PlayMusic(resource, loop);
|
|
||||||
|
|
||||||
// Actualizar estado y metadatos después de iniciar con éxito
|
|
||||||
music_.name = name;
|
music_.name = name;
|
||||||
music_.loop = new_loop;
|
music_.loop = new_loop;
|
||||||
music_.state = MusicState::PLAYING;
|
music_.state = MusicState::PLAYING;
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ class Audio {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr float MAX_VOLUME = 1.0F; // Volumen máximo
|
static constexpr float MAX_VOLUME = 1.0F; // Volumen máximo
|
||||||
static constexpr float MIN_VOLUME = 0.0F; // Volumen mínimo
|
static constexpr float MIN_VOLUME = 0.0F; // Volumen mínimo
|
||||||
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
|
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
|
||||||
|
static constexpr int DEFAULT_CROSSFADE_MS = 1500; // Duración del crossfade por defecto (ms)
|
||||||
|
|
||||||
// --- Singleton ---
|
// --- Singleton ---
|
||||||
static void init(); // Inicializa el objeto Audio
|
static void init(); // Inicializa el objeto Audio
|
||||||
@@ -35,11 +36,11 @@ class Audio {
|
|||||||
static void update(); // Actualización del sistema de audio
|
static void update(); // Actualización del sistema de audio
|
||||||
|
|
||||||
// --- Control de música ---
|
// --- Control de música ---
|
||||||
void playMusic(const std::string& name, int loop = -1); // Reproducir música en bucle
|
void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0); // Reproducir música (con crossfade opcional)
|
||||||
void pauseMusic(); // Pausar reproducción de música
|
void pauseMusic(); // Pausar reproducción de música
|
||||||
void resumeMusic(); // Continua la música pausada
|
void resumeMusic(); // Continua la música pausada
|
||||||
void stopMusic(); // Detener completamente la música
|
void stopMusic(); // Detener completamente la música
|
||||||
void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música
|
void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música
|
||||||
|
|
||||||
// --- Control de sonidos ---
|
// --- Control de sonidos ---
|
||||||
void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre
|
void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre
|
||||||
|
|||||||
@@ -66,33 +66,61 @@ inline bool JA_musicEnabled{true};
|
|||||||
inline bool JA_soundEnabled{true};
|
inline bool JA_soundEnabled{true};
|
||||||
inline SDL_AudioDeviceID sdlAudioDevice{0};
|
inline SDL_AudioDeviceID sdlAudioDevice{0};
|
||||||
|
|
||||||
inline bool fading{false};
|
// --- Crossfade / Fade State ---
|
||||||
inline int fade_start_time{0};
|
struct JA_FadeState {
|
||||||
inline int fade_duration{0};
|
bool active{false};
|
||||||
inline float fade_initial_volume{0.0f}; // Corregido de 'int' a 'float'
|
Uint64 start_time{0};
|
||||||
|
int duration_ms{0};
|
||||||
|
float initial_volume{0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JA_OutgoingMusic {
|
||||||
|
SDL_AudioStream* stream{nullptr};
|
||||||
|
JA_FadeState fade;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline JA_OutgoingMusic outgoing_music;
|
||||||
|
inline JA_FadeState incoming_fade;
|
||||||
|
|
||||||
// --- Forward Declarations ---
|
// --- Forward Declarations ---
|
||||||
inline void JA_StopMusic();
|
inline void JA_StopMusic();
|
||||||
inline void JA_StopChannel(const int channel);
|
inline void JA_StopChannel(const int channel);
|
||||||
inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0, const int group = 0);
|
inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0, const int group = 0);
|
||||||
|
inline void JA_CrossfadeMusic(JA_Music_t* music, int crossfade_ms, int loop = -1);
|
||||||
|
|
||||||
// --- Core Functions ---
|
// --- Core Functions ---
|
||||||
|
|
||||||
inline void JA_Update() {
|
inline void JA_Update() {
|
||||||
|
// --- Outgoing music fade-out (crossfade o fade-out a silencio) ---
|
||||||
|
if (outgoing_music.stream && outgoing_music.fade.active) {
|
||||||
|
Uint64 now = SDL_GetTicks();
|
||||||
|
Uint64 elapsed = now - outgoing_music.fade.start_time;
|
||||||
|
if (elapsed >= (Uint64)outgoing_music.fade.duration_ms) {
|
||||||
|
SDL_DestroyAudioStream(outgoing_music.stream);
|
||||||
|
outgoing_music.stream = nullptr;
|
||||||
|
outgoing_music.fade.active = false;
|
||||||
|
} else {
|
||||||
|
float percent = (float)elapsed / (float)outgoing_music.fade.duration_ms;
|
||||||
|
SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0f - percent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Current music ---
|
||||||
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) {
|
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) {
|
||||||
if (fading) {
|
// Fade-in (parte de un crossfade)
|
||||||
int time = SDL_GetTicks();
|
if (incoming_fade.active) {
|
||||||
if (time > (fade_start_time + fade_duration)) {
|
Uint64 now = SDL_GetTicks();
|
||||||
fading = false;
|
Uint64 elapsed = now - incoming_fade.start_time;
|
||||||
JA_StopMusic();
|
if (elapsed >= (Uint64)incoming_fade.duration_ms) {
|
||||||
return;
|
incoming_fade.active = false;
|
||||||
|
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
|
||||||
} else {
|
} else {
|
||||||
const int time_passed = time - fade_start_time;
|
float percent = (float)elapsed / (float)incoming_fade.duration_ms;
|
||||||
const float percent = (float)time_passed / (float)fade_duration;
|
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * percent);
|
||||||
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * (1.0 - percent));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Buffering de musica en loop
|
||||||
if (current_music->times != 0) {
|
if (current_music->times != 0) {
|
||||||
if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) {
|
if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) {
|
||||||
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
|
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
|
||||||
@@ -103,6 +131,7 @@ inline void JA_Update() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Sound channels ---
|
||||||
if (JA_soundEnabled) {
|
if (JA_soundEnabled) {
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i)
|
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i)
|
||||||
if (channels[i].state == JA_CHANNEL_PLAYING) {
|
if (channels[i].state == JA_CHANNEL_PLAYING) {
|
||||||
@@ -132,7 +161,11 @@ inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void JA_Quit() {
|
inline void JA_Quit() {
|
||||||
if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); // Corregido: !sdlAudioDevice -> sdlAudioDevice
|
if (outgoing_music.stream) {
|
||||||
|
SDL_DestroyAudioStream(outgoing_music.stream);
|
||||||
|
outgoing_music.stream = nullptr;
|
||||||
|
}
|
||||||
|
if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||||
sdlAudioDevice = 0;
|
sdlAudioDevice = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +266,14 @@ inline void JA_ResumeMusic() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void JA_StopMusic() {
|
inline void JA_StopMusic() {
|
||||||
|
// Limpiar outgoing crossfade si existe
|
||||||
|
if (outgoing_music.stream) {
|
||||||
|
SDL_DestroyAudioStream(outgoing_music.stream);
|
||||||
|
outgoing_music.stream = nullptr;
|
||||||
|
outgoing_music.fade.active = false;
|
||||||
|
}
|
||||||
|
incoming_fade.active = false;
|
||||||
|
|
||||||
if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return;
|
if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return;
|
||||||
|
|
||||||
current_music->pos = 0;
|
current_music->pos = 0;
|
||||||
@@ -241,17 +282,65 @@ inline void JA_StopMusic() {
|
|||||||
SDL_DestroyAudioStream(current_music->stream);
|
SDL_DestroyAudioStream(current_music->stream);
|
||||||
current_music->stream = nullptr;
|
current_music->stream = nullptr;
|
||||||
}
|
}
|
||||||
// No liberamos filename aquí, se debería liberar en JA_DeleteMusic
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void JA_FadeOutMusic(const int milliseconds) {
|
inline void JA_FadeOutMusic(const int milliseconds) {
|
||||||
if (!JA_musicEnabled) return;
|
if (!JA_musicEnabled) return;
|
||||||
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
|
if (!current_music || current_music->state != JA_MUSIC_PLAYING) return;
|
||||||
|
|
||||||
fading = true;
|
// Destruir outgoing anterior si existe
|
||||||
fade_start_time = SDL_GetTicks();
|
if (outgoing_music.stream) {
|
||||||
fade_duration = milliseconds;
|
SDL_DestroyAudioStream(outgoing_music.stream);
|
||||||
fade_initial_volume = JA_musicVolume;
|
outgoing_music.stream = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Robar el stream del current_music al outgoing
|
||||||
|
outgoing_music.stream = current_music->stream;
|
||||||
|
outgoing_music.fade = {true, SDL_GetTicks(), milliseconds, JA_musicVolume};
|
||||||
|
|
||||||
|
// Dejar current_music sin stream (ya lo tiene outgoing)
|
||||||
|
current_music->stream = nullptr;
|
||||||
|
current_music->pos = 0;
|
||||||
|
current_music->state = JA_MUSIC_STOPPED;
|
||||||
|
incoming_fade.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const int loop) {
|
||||||
|
if (!JA_musicEnabled || !music) return;
|
||||||
|
|
||||||
|
// Destruir outgoing anterior si existe (crossfade durante crossfade)
|
||||||
|
if (outgoing_music.stream) {
|
||||||
|
SDL_DestroyAudioStream(outgoing_music.stream);
|
||||||
|
outgoing_music.stream = nullptr;
|
||||||
|
outgoing_music.fade.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Robar el stream de la musica actual al outgoing para el fade-out
|
||||||
|
if (current_music && current_music->state == JA_MUSIC_PLAYING && current_music->stream) {
|
||||||
|
outgoing_music.stream = current_music->stream;
|
||||||
|
outgoing_music.fade = {true, SDL_GetTicks(), crossfade_ms, JA_musicVolume};
|
||||||
|
current_music->stream = nullptr;
|
||||||
|
current_music->state = JA_MUSIC_STOPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iniciar la nueva pista con gain=0 (el fade-in la sube gradualmente)
|
||||||
|
current_music = music;
|
||||||
|
current_music->pos = 0;
|
||||||
|
current_music->state = JA_MUSIC_PLAYING;
|
||||||
|
current_music->times = loop;
|
||||||
|
|
||||||
|
current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec);
|
||||||
|
if (!current_music->stream) {
|
||||||
|
SDL_Log("Failed to create audio stream for crossfade!");
|
||||||
|
current_music->state = JA_MUSIC_STOPPED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
|
||||||
|
SDL_SetAudioStreamGain(current_music->stream, 0.0f);
|
||||||
|
SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
|
||||||
|
|
||||||
|
// Configurar fade-in
|
||||||
|
incoming_fade = {true, SDL_GetTicks(), crossfade_ms, 0.0f};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JA_Music_state JA_GetMusicState() {
|
inline JA_Music_state JA_GetMusicState() {
|
||||||
|
|||||||
@@ -1024,7 +1024,7 @@ void Game::updateMusicForRoom() {
|
|||||||
|
|
||||||
// Reproducir si no coincide la pista actual o si está parada
|
// Reproducir si no coincide la pista actual o si está parada
|
||||||
if (Audio::get()->getCurrentMusicName() != target || Audio::get()->getMusicState() == Audio::MusicState::STOPPED) {
|
if (Audio::get()->getCurrentMusicName() != target || Audio::get()->getMusicState() == Audio::MusicState::STOPPED) {
|
||||||
Audio::get()->playMusic(target);
|
Audio::get()->playMusic(target, -1, Audio::DEFAULT_CROSSFADE_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user