From 6246b5d89db969a2e063a78b7abab4b3b6e07551 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sat, 18 Apr 2026 11:42:29 +0200 Subject: [PATCH] normalitzat Audio --- source/core/audio/audio.cpp | 212 ++++++++++++++++++ source/core/audio/audio.hpp | 114 ++++++++++ source/core/audio/audio_adapter.cpp | 13 ++ source/core/audio/audio_adapter.hpp | 17 ++ source/core/audio/jail_audio.hpp | 330 +++++++++++++++++++--------- source/core/system/director.cpp | 18 +- source/external/stb_vorbis.c | 117 +++++----- source/game/defaults.hpp | 6 +- source/game/game.cpp | 80 +++---- source/game/options.cpp | 8 +- source/game/options.hpp | 6 +- source/game/scenes/instructions.cpp | 4 +- source/game/scenes/intro.cpp | 12 +- source/game/scenes/logo.cpp | 8 +- source/game/scenes/title.cpp | 16 +- source/game/ui/menu.cpp | 11 +- source/main.cpp | 1 - 17 files changed, 740 insertions(+), 233 deletions(-) create mode 100644 source/core/audio/audio.cpp create mode 100644 source/core/audio/audio.hpp create mode 100644 source/core/audio/audio_adapter.cpp create mode 100644 source/core/audio/audio_adapter.hpp diff --git a/source/core/audio/audio.cpp b/source/core/audio/audio.cpp new file mode 100644 index 0000000..633a767 --- /dev/null +++ b/source/core/audio/audio.cpp @@ -0,0 +1,212 @@ +#include "core/audio/audio.hpp" + +#include // Para SDL_GetError, SDL_Init + +#include // Para clamp +#include // Para std::cout + +// Implementación de stb_vorbis (debe estar ANTES de incluir jail_audio.hpp). +// clang-format off +#undef STB_VORBIS_HEADER_ONLY +#include "external/stb_vorbis.c" +// stb_vorbis.c filtra les macros L, C i R (i PLAYBACK_*) al TU. Les netegem +// perquè xocarien amb noms de paràmetres de plantilla en altres headers. +#undef L +#undef C +#undef R +#undef PLAYBACK_MONO +#undef PLAYBACK_LEFT +#undef PLAYBACK_RIGHT +// clang-format on + +#include "core/audio/audio_adapter.hpp" // Para AudioResource::getMusic/getSound +#include "core/audio/jail_audio.hpp" // Para JA_* +#include "game/options.hpp" // Para Options::audio + +// Singleton +Audio* Audio::instance = nullptr; + +// Inicializa la instancia única del singleton +void Audio::init() { Audio::instance = new Audio(); } + +// Libera la instancia +void Audio::destroy() { + delete Audio::instance; + Audio::instance = nullptr; +} + +// Obtiene la instancia +auto Audio::get() -> Audio* { return Audio::instance; } + +// Constructor +Audio::Audio() { initSDLAudio(); } + +// Destructor +Audio::~Audio() { + JA_Quit(); +} + +// Método principal +void Audio::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 por nombre (con crossfade opcional) +void Audio::playMusic(const std::string& name, const int loop, const int crossfade_ms) { + bool new_loop = (loop != 0); + + // Si ya está sonando exactamente la misma pista y mismo modo loop, no hacemos nada + if (music_.state == MusicState::PLAYING && music_.name == name && music_.loop == new_loop) { + return; + } + + if (!music_enabled_) return; + + auto* resource = AudioResource::getMusic(name); + if (resource == nullptr) return; + + if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { + JA_CrossfadeMusic(resource, crossfade_ms, loop); + } else { + if (music_.state == MusicState::PLAYING) { + JA_StopMusic(); + } + JA_PlayMusic(resource, loop); + } + + music_.name = name; + music_.loop = new_loop; + music_.state = MusicState::PLAYING; +} + +// Reproduce la música por puntero (con crossfade opcional) +void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms) { + if (!music_enabled_ || music == nullptr) return; + + if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { + JA_CrossfadeMusic(music, crossfade_ms, loop); + } else { + if (music_.state == MusicState::PLAYING) { + JA_StopMusic(); + } + JA_PlayMusic(music, loop); + } + + music_.name.clear(); // nom desconegut quan es passa per punter + music_.loop = (loop != 0); + music_.state = MusicState::PLAYING; +} + +// Pausa la música +void Audio::pauseMusic() { + if (music_enabled_ && music_.state == MusicState::PLAYING) { + JA_PauseMusic(); + music_.state = MusicState::PAUSED; + } +} + +// Continua la música pausada +void Audio::resumeMusic() { + if (music_enabled_ && music_.state == MusicState::PAUSED) { + JA_ResumeMusic(); + music_.state = MusicState::PLAYING; + } +} + +// Detiene la música +void Audio::stopMusic() { + if (music_enabled_) { + JA_StopMusic(); + music_.state = MusicState::STOPPED; + } +} + +// Reproduce un sonido por nombre +void Audio::playSound(const std::string& name, Group group) const { + if (sound_enabled_) { + JA_PlaySound(AudioResource::getSound(name), 0, static_cast(group)); + } +} + +// Reproduce un sonido por puntero directo +void Audio::playSound(JA_Sound_t* sound, Group group) const { + if (sound_enabled_ && sound != nullptr) { + JA_PlaySound(sound, 0, static_cast(group)); + } +} + +// Detiene todos los sonidos +void Audio::stopAllSounds() const { + if (sound_enabled_) { + JA_StopChannel(-1); + } +} + +// Realiza un fundido de salida de la música +void Audio::fadeOutMusic(int milliseconds) const { + if (music_enabled_ && getRealMusicState() == MusicState::PLAYING) { + JA_FadeOutMusic(milliseconds); + } +} + +// Consulta directamente el estado real de la música en jailaudio +auto Audio::getRealMusicState() -> MusicState { + JA_Music_state ja_state = JA_GetMusicState(); + switch (ja_state) { + case JA_MUSIC_PLAYING: + return MusicState::PLAYING; + case JA_MUSIC_PAUSED: + return MusicState::PAUSED; + case JA_MUSIC_STOPPED: + case JA_MUSIC_INVALID: + case JA_MUSIC_DISABLED: + default: + return MusicState::STOPPED; + } +} + +// Establece el volumen de los sonidos (float 0.0..1.0) +void Audio::setSoundVolume(float sound_volume, Group group) const { + if (sound_enabled_) { + sound_volume = std::clamp(sound_volume, MIN_VOLUME, MAX_VOLUME); + const float CONVERTED_VOLUME = sound_volume * Options::audio.volume; + JA_SetSoundVolume(CONVERTED_VOLUME, static_cast(group)); + } +} + +// Establece el volumen de la música (float 0.0..1.0) +void Audio::setMusicVolume(float music_volume) const { + if (music_enabled_) { + music_volume = std::clamp(music_volume, MIN_VOLUME, MAX_VOLUME); + const float CONVERTED_VOLUME = music_volume * Options::audio.volume; + JA_SetMusicVolume(CONVERTED_VOLUME); + } +} + +// Aplica la configuración +void Audio::applySettings() { + enable(Options::audio.enabled); +} + +// Establecer estado general +void Audio::enable(bool value) { + enabled_ = value; + + setSoundVolume(enabled_ ? Options::audio.sound.volume : MIN_VOLUME); + setMusicVolume(enabled_ ? Options::audio.music.volume : MIN_VOLUME); +} + +// Inicializa SDL Audio +void Audio::initSDLAudio() { + if (!SDL_Init(SDL_INIT_AUDIO)) { + std::cout << "SDL_AUDIO could not initialize! SDL Error: " << SDL_GetError() << '\n'; + } else { + JA_Init(FREQUENCY, SDL_AUDIO_S16LE, 2); + enable(Options::audio.enabled); + } +} diff --git a/source/core/audio/audio.hpp b/source/core/audio/audio.hpp new file mode 100644 index 0000000..9c5ea6f --- /dev/null +++ b/source/core/audio/audio.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include // Para int8_t, uint8_t +#include // Para string +#include // Para move + +// --- Clase Audio: gestor de audio (singleton) --- +// Implementació canònica, byte-idèntica entre projectes. +// Els volums es manegen internament com a float 0.0–1.0; la capa de +// presentació (menús, notificacions) usa les helpers toPercent/fromPercent +// per mostrar 0–100 a l'usuari. +class Audio { + public: + // --- Enums --- + enum class Group : std::int8_t { + ALL = -1, // Todos los grupos + GAME = 0, // Sonidos del juego + INTERFACE = 1 // Sonidos de la interfaz + }; + + enum class MusicState : std::uint8_t { + PLAYING, // Reproduciendo música + PAUSED, // Música pausada + STOPPED, // Música detenida + }; + + // --- Constantes --- + static constexpr float MAX_VOLUME = 1.0F; // Volumen máximo (float 0..1) + static constexpr float MIN_VOLUME = 0.0F; // Volumen mínimo (float 0..1) + static constexpr float VOLUME_STEP = 0.05F; // Pas estàndard per a UI (5%) + static constexpr int FREQUENCY = 48000; // Frecuencia de audio + static constexpr int DEFAULT_CROSSFADE_MS = 1500; // Duració del crossfade per defecte (ms) + + // --- Singleton --- + static void init(); // Inicializa el objeto Audio + static void destroy(); // Libera el objeto Audio + static auto get() -> Audio*; // Obtiene el puntero al objeto Audio + Audio(const Audio&) = delete; // Evitar copia + auto operator=(const Audio&) -> Audio& = delete; // Evitar asignación + + static void update(); // Actualización del sistema de audio + + // --- Control de música --- + void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0); // Reproducir música por nombre (con crossfade opcional) + void playMusic(struct JA_Music_t* music, int loop = -1, int crossfade_ms = 0); // Reproducir música por puntero (con crossfade opcional) + void pauseMusic(); // Pausar reproducción de música + void resumeMusic(); // Continua la música pausada + void stopMusic(); // Detener completamente la música + void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música + + // --- Control de sonidos --- + void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre + void playSound(struct JA_Sound_t* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero + void stopAllSounds() const; // Detener todos los sonidos + + // --- Control de volumen (API interna: float 0.0..1.0) --- + void setSoundVolume(float volume, Group group = Group::ALL) const; // Ajustar volumen de efectos + void setMusicVolume(float volume) const; // Ajustar volumen de música + + // --- Helpers de conversió per a la capa de presentació --- + // UI (menús, notificacions) manega enters 0..100; internament viu float 0..1. + static constexpr auto toPercent(float volume) -> int { + return static_cast(volume * 100.0F + 0.5F); + } + static constexpr auto fromPercent(int percent) -> float { + return static_cast(percent) / 100.0F; + } + + // --- Configuración general --- + void enable(bool value); // Establecer estado general + void toggleEnabled() { enabled_ = !enabled_; } // Alternar estado general + void applySettings(); // Aplica la configuración + + // --- Configuración de sonidos --- + void enableSound() { sound_enabled_ = true; } // Habilitar sonidos + void disableSound() { sound_enabled_ = false; } // Deshabilitar sonidos + void enableSound(bool value) { sound_enabled_ = value; } // Establecer estado de sonidos + void toggleSound() { sound_enabled_ = !sound_enabled_; } // Alternar estado de sonidos + + // --- Configuración de música --- + void enableMusic() { music_enabled_ = true; } // Habilitar música + void disableMusic() { music_enabled_ = false; } // Deshabilitar música + void enableMusic(bool value) { music_enabled_ = value; } // Establecer estado de música + void toggleMusic() { music_enabled_ = !music_enabled_; } // Alternar estado de música + + // --- Consultas de estado --- + [[nodiscard]] auto isEnabled() const -> bool { return enabled_; } + [[nodiscard]] auto isSoundEnabled() const -> bool { return sound_enabled_; } + [[nodiscard]] auto isMusicEnabled() const -> bool { return music_enabled_; } + [[nodiscard]] auto getMusicState() const -> MusicState { return music_.state; } + [[nodiscard]] static auto getRealMusicState() -> MusicState; + [[nodiscard]] auto getCurrentMusicName() const -> const std::string& { return music_.name; } + + private: + // --- Tipos anidados --- + struct Music { + MusicState state{MusicState::STOPPED}; // Estado actual de la música + std::string name; // Última pista de música reproducida + bool loop{false}; // Indica si se reproduce en bucle + }; + + // --- Métodos --- + Audio(); // Constructor privado + ~Audio(); // Destructor privado + void initSDLAudio(); // Inicializa SDL Audio + + // --- Variables miembro --- + static Audio* instance; // Instancia única de Audio + + Music music_; // Estado de la música + bool enabled_{true}; // Estado general del audio + bool sound_enabled_{true}; // Estado de los efectos de sonido + bool music_enabled_{true}; // Estado de la música +}; diff --git a/source/core/audio/audio_adapter.cpp b/source/core/audio/audio_adapter.cpp new file mode 100644 index 0000000..3b0fa56 --- /dev/null +++ b/source/core/audio/audio_adapter.cpp @@ -0,0 +1,13 @@ +#include "core/audio/audio_adapter.hpp" + +#include "core/resources/resource.h" + +namespace AudioResource { + JA_Music_t* getMusic(const std::string& name) { + return Resource::get()->getMusic(name); + } + + JA_Sound_t* getSound(const std::string& name) { + return Resource::get()->getSound(name); + } +} // namespace AudioResource diff --git a/source/core/audio/audio_adapter.hpp b/source/core/audio/audio_adapter.hpp new file mode 100644 index 0000000..a5eb16e --- /dev/null +++ b/source/core/audio/audio_adapter.hpp @@ -0,0 +1,17 @@ +#pragma once + +// --- Audio Resource Adapter --- +// Aquest fitxer exposa una interfície comuna a Audio per obtenir JA_Music_t* / +// JA_Sound_t* per nom. Cada projecte la implementa en audio_adapter.cpp +// delegant al seu singleton de recursos (Resource::get(), Resource::Cache::get(), +// etc.). Això permet que audio.hpp/audio.cpp siguin idèntics entre projectes. + +#include // Para string + +struct JA_Music_t; +struct JA_Sound_t; + +namespace AudioResource { + JA_Music_t* getMusic(const std::string& name); + JA_Sound_t* getSound(const std::string& name); +} // namespace AudioResource diff --git a/source/core/audio/jail_audio.hpp b/source/core/audio/jail_audio.hpp index 5b78a38..63308e0 100644 --- a/source/core/audio/jail_audio.hpp +++ b/source/core/audio/jail_audio.hpp @@ -3,24 +3,41 @@ // --- Includes --- #include #include // Para uint32_t, uint8_t -#include // Para NULL, fseek, printf, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET +#include // Para NULL, fseek, fclose, fopen, fread, ftell, FILE, SEEK_END, SEEK_SET #include // Para free, malloc -#include // Para strcpy, strlen + +#include // Para std::cout +#include // Para std::unique_ptr +#include // Para std::string +#include // Para std::vector #define STB_VORBIS_HEADER_ONLY -#include "external/stb_vorbis.c" +#include "external/stb_vorbis.c" // Para stb_vorbis_open_memory i streaming + +// Deleter stateless per a buffers reservats amb `SDL_malloc` / `SDL_LoadWAV*`. +// Compatible amb `std::unique_ptr` — zero size +// overhead gràcies a EBO, igual que un unique_ptr amb default_delete. +struct SDLFreeDeleter { + void operator()(Uint8* p) const noexcept { + if (p) SDL_free(p); + } +}; // --- Public Enums --- -enum JA_Channel_state { JA_CHANNEL_INVALID, +enum JA_Channel_state { + JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, - JA_SOUND_DISABLED }; -enum JA_Music_state { JA_MUSIC_INVALID, + JA_SOUND_DISABLED, +}; +enum JA_Music_state { + JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, - JA_MUSIC_DISABLED }; + JA_MUSIC_DISABLED, +}; // --- Struct Definitions --- #define JA_MAX_SIMULTANEOUS_CHANNELS 20 @@ -29,7 +46,9 @@ enum JA_Music_state { JA_MUSIC_INVALID, struct JA_Sound_t { SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000}; Uint32 length{0}; - Uint8* buffer{NULL}; + // Buffer descomprimit (PCM) propietat del sound. Reservat per SDL_LoadWAV + // via SDL_malloc; el deleter `SDLFreeDeleter` allibera amb SDL_free. + std::unique_ptr buffer; }; struct JA_Channel_t { @@ -44,21 +63,22 @@ struct JA_Channel_t { struct JA_Music_t { SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000}; - // OGG comprimit en memòria. Propietat nostra; es copia des del fitxer una - // sola vegada en JA_LoadMusic i es descomprimix en chunks per streaming. - Uint8* ogg_data{nullptr}; - Uint32 ogg_length{0}; - stb_vorbis* vorbis{nullptr}; // Handle del decoder, viu tot el cicle del JA_Music_t + // OGG comprimit en memòria. Propietat nostra; es copia des del buffer + // d'entrada una sola vegada en JA_LoadMusic i es descomprimix en chunks + // per streaming. Com que stb_vorbis guarda un punter persistent al + // `.data()` d'aquest vector, no el podem resize'jar un cop establert + // (una reallocation invalidaria el punter que el decoder conserva). + std::vector ogg_data; + stb_vorbis* vorbis{nullptr}; // handle del decoder, viu tot el cicle del JA_Music_t - char* filename{nullptr}; + std::string filename; - int times{0}; // Loops restants (-1 = infinit, 0 = un sol play) + int times{0}; // loops restants (-1 = infinit, 0 = un sol play) SDL_AudioStream* stream{nullptr}; JA_Music_state state{JA_MUSIC_INVALID}; }; -// --- Internal Global State --- -// Marcado 'inline' (C++17) para asegurar una única instancia. +// --- Internal Global State (inline, C++17) --- inline JA_Music_t* current_music{nullptr}; inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; @@ -70,15 +90,27 @@ inline bool JA_musicEnabled{true}; inline bool JA_soundEnabled{true}; inline SDL_AudioDeviceID sdlAudioDevice{0}; -inline bool fading{false}; -inline int fade_start_time{0}; -inline int fade_duration{0}; -inline float fade_initial_volume{0.0f}; +// --- Crossfade / Fade State --- +struct JA_FadeState { + bool active{false}; + 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 --- inline void JA_StopMusic(); 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 void JA_CrossfadeMusic(JA_Music_t* music, int crossfade_ms, int loop = -1); // --- Music streaming internals --- // Bytes-per-sample per canal (sempre s16) @@ -96,15 +128,15 @@ inline int JA_FeedMusicChunk(JA_Music_t* music) { if (!music || !music->vorbis || !music->stream) return 0; short chunk[JA_MUSIC_CHUNK_SHORTS]; - const int numChannels = music->spec.channels; + const int num_channels = music->spec.channels; const int samples_per_channel = stb_vorbis_get_samples_short_interleaved( music->vorbis, - numChannels, + num_channels, chunk, JA_MUSIC_CHUNK_SHORTS); if (samples_per_channel <= 0) return 0; - const int bytes = samples_per_channel * numChannels * JA_MUSIC_BYTES_PER_SAMPLE; + const int bytes = samples_per_channel * num_channels * JA_MUSIC_BYTES_PER_SAMPLE; SDL_PutAudioStreamData(music->stream, chunk, bytes); return samples_per_channel; } @@ -131,20 +163,51 @@ inline void JA_PumpMusic(JA_Music_t* music) { } } +// Pre-carrega `duration_ms` de so dins l'stream actual abans que l'stream +// siga robat per outgoing_music (crossfade o fade-out). Imprescindible amb +// streaming: l'stream robat no es pot re-alimentar perquè perd la referència +// al seu vorbis decoder. No aplica loop — si el vorbis s'esgota abans, parem. +inline void JA_PreFillOutgoing(JA_Music_t* music, int duration_ms) { + if (!music || !music->vorbis || !music->stream) return; + + const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE; + const int needed_bytes = static_cast((static_cast(duration_ms) * bytes_per_second) / 1000); + + while (SDL_GetAudioStreamAvailable(music->stream) < needed_bytes) { + const int decoded = JA_FeedMusicChunk(music); + if (decoded <= 0) break; // EOF: deixem drenar el que hi haja + } +} + // --- Core Functions --- 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 (fading) { - int time = SDL_GetTicks(); - if (time > (fade_start_time + fade_duration)) { - fading = false; - JA_StopMusic(); - return; + // Fade-in (parte de un crossfade) + if (incoming_fade.active) { + Uint64 now = SDL_GetTicks(); + Uint64 elapsed = now - incoming_fade.start_time; + if (elapsed >= (Uint64)incoming_fade.duration_ms) { + incoming_fade.active = false; + SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); } else { - const int time_passed = time - fade_start_time; - const float percent = (float)time_passed / (float)fade_duration; - SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * (1.0 - percent)); + float percent = (float)elapsed / (float)incoming_fade.duration_ms; + SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * percent); } } @@ -156,12 +219,13 @@ inline void JA_Update() { } } + // --- Sound channels --- if (JA_soundEnabled) { for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) if (channels[i].state == JA_CHANNEL_PLAYING) { if (channels[i].times != 0) { if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) { - SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length); + SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer.get(), channels[i].sound->length); if (channels[i].times > 0) channels[i].times--; } } else { @@ -172,19 +236,19 @@ inline void JA_Update() { } inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) { -#ifdef DEBUG - SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); -#endif - JA_audioSpec = {format, num_channels, freq}; if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); - if (sdlAudioDevice == 0) SDL_Log("Failed to initialize SDL audio!"); + if (sdlAudioDevice == 0) std::cout << "Failed to initialize SDL audio!" << '\n'; for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) channels[i].state = JA_CHANNEL_FREE; for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5f; } inline void JA_Quit() { + if (outgoing_music.stream) { + SDL_DestroyAudioStream(outgoing_music.stream); + outgoing_music.stream = nullptr; + } if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); sdlAudioDevice = 0; } @@ -194,26 +258,25 @@ inline void JA_Quit() { inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) { if (!buffer || length == 0) return nullptr; - // Còpia del OGG comprimit: stb_vorbis llig de forma persistent aquesta - // memòria mentre el handle estiga viu, així que hem de posseir-la nosaltres. - Uint8* ogg_copy = static_cast(SDL_malloc(length)); - if (!ogg_copy) return nullptr; - SDL_memcpy(ogg_copy, buffer, length); + // Allocem el JA_Music_t primer per aprofitar el seu `std::vector` + // com a propietari del OGG comprimit. stb_vorbis guarda un punter + // persistent al buffer; com que ací no el resize'jem, el .data() és + // estable durant tot el cicle de vida del music. + auto* music = new JA_Music_t(); + music->ogg_data.assign(buffer, buffer + length); int error = 0; - stb_vorbis* vorbis = stb_vorbis_open_memory(ogg_copy, static_cast(length), &error, nullptr); - if (!vorbis) { - SDL_free(ogg_copy); - SDL_Log("JA_LoadMusic: stb_vorbis_open_memory failed (error %d)", error); + music->vorbis = stb_vorbis_open_memory(music->ogg_data.data(), + static_cast(length), + &error, + nullptr); + if (!music->vorbis) { + std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << error << ")" << '\n'; + delete music; return nullptr; } - auto* music = new JA_Music_t(); - music->ogg_data = ogg_copy; - music->ogg_length = length; - music->vorbis = vorbis; - - const stb_vorbis_info info = stb_vorbis_get_info(vorbis); + const stb_vorbis_info info = stb_vorbis_get_info(music->vorbis); music->spec.channels = info.channels; music->spec.freq = static_cast(info.sample_rate); music->spec.format = SDL_AUDIO_S16; @@ -222,30 +285,36 @@ inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) { return music; } +// Overload amb filename — els callers l'usen per poder comparar la música +// en curs amb JA_GetMusicFilename() i no rearrancar-la si ja és la mateixa. +inline JA_Music_t* JA_LoadMusic(Uint8* buffer, Uint32 length, const char* filename) { + JA_Music_t* music = JA_LoadMusic(static_cast(buffer), length); + if (music && filename) music->filename = filename; + return music; +} + inline JA_Music_t* JA_LoadMusic(const char* filename) { + // Carreguem primer el arxiu en memòria i després el descomprimim. FILE* f = fopen(filename, "rb"); - if (!f) return NULL; + if (!f) return nullptr; fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); auto* buffer = static_cast(malloc(fsize + 1)); if (!buffer) { fclose(f); - return NULL; + return nullptr; } if (fread(buffer, fsize, 1, f) != 1) { fclose(f); free(buffer); - return NULL; + return nullptr; } fclose(f); - JA_Music_t* music = JA_LoadMusic(buffer, fsize); + JA_Music_t* music = JA_LoadMusic(static_cast(buffer), static_cast(fsize)); if (music) { - music->filename = static_cast(malloc(strlen(filename) + 1)); - if (music->filename) { - strcpy(music->filename, filename); - } + music->filename = filename; } free(buffer); @@ -268,7 +337,7 @@ inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) { current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec); if (!current_music->stream) { - SDL_Log("Failed to create audio stream!"); + std::cout << "Failed to create audio stream!" << '\n'; current_music->state = JA_MUSIC_STOPPED; return; } @@ -277,13 +346,15 @@ inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) { // Pre-cargem el buffer abans de bindejar per evitar un underrun inicial. JA_PumpMusic(current_music); - if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) printf("[ERROR] SDL_BindAudioStream failed!\n"); + if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) { + std::cout << "[ERROR] SDL_BindAudioStream failed!" << '\n'; + } } -inline char* JA_GetMusicFilename(const JA_Music_t* music = nullptr) { +inline const char* JA_GetMusicFilename(const JA_Music_t* music = nullptr) { if (!music) music = current_music; - if (!music) return nullptr; - return music->filename; + if (!music || music->filename.empty()) return nullptr; + return music->filename.c_str(); } inline void JA_PauseMusic() { @@ -303,6 +374,14 @@ inline void JA_ResumeMusic() { } 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; current_music->state = JA_MUSIC_STOPPED; @@ -319,12 +398,69 @@ inline void JA_StopMusic() { inline void JA_FadeOutMusic(const int milliseconds) { 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; - fade_start_time = SDL_GetTicks(); - fade_duration = milliseconds; - fade_initial_volume = JA_musicVolume; + // Destruir outgoing anterior si existe + if (outgoing_music.stream) { + SDL_DestroyAudioStream(outgoing_music.stream); + outgoing_music.stream = nullptr; + } + + // Pre-omplim l'stream amb `milliseconds` de so: un cop robat, ja no + // tindrà accés al vorbis decoder i només podrà drenar el que tinga. + JA_PreFillOutgoing(current_music, milliseconds); + + // 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->state = JA_MUSIC_STOPPED; + if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis); + incoming_fade.active = false; +} + +inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const int loop) { + if (!JA_musicEnabled || !music || !music->vorbis) 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. + // Pre-omplim amb `crossfade_ms` de so perquè no es quede en silenci + // abans d'acabar el fade (l'stream robat ja no pot alimentar-se). + if (current_music && current_music->state == JA_MUSIC_PLAYING && current_music->stream) { + JA_PreFillOutgoing(current_music, crossfade_ms); + 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; + if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis); + } + + // Iniciar la nueva pista con gain=0 (el fade-in la sube gradualmente) + current_music = music; + current_music->state = JA_MUSIC_PLAYING; + current_music->times = loop; + + stb_vorbis_seek_start(current_music->vorbis); + current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec); + if (!current_music->stream) { + std::cout << "Failed to create audio stream for crossfade!" << '\n'; + current_music->state = JA_MUSIC_STOPPED; + return; + } + SDL_SetAudioStreamGain(current_music->stream, 0.0f); + JA_PumpMusic(current_music); // pre-carrega abans de bindejar + SDL_BindAudioStream(sdlAudioDevice, current_music->stream); + + // Configurar fade-in + incoming_fade = {true, SDL_GetTicks(), crossfade_ms, 0.0f}; } inline JA_Music_state JA_GetMusicState() { @@ -342,8 +478,8 @@ inline void JA_DeleteMusic(JA_Music_t* music) { } if (music->stream) SDL_DestroyAudioStream(music->stream); if (music->vorbis) stb_vorbis_close(music->vorbis); - SDL_free(music->ogg_data); - free(music->filename); + // ogg_data (std::vector) i filename (std::string) s'alliberen sols + // al destructor de JA_Music_t. delete music; } @@ -356,48 +492,40 @@ inline float JA_SetMusicVolume(float volume) { } inline void JA_SetMusicPosition(float /*value*/) { - // No implementat amb el backend de streaming. Mai va arribar a usar-se - // en el codi existent, així que es manté com a stub. + // No implementat amb el backend de streaming. } inline float JA_GetMusicPosition() { - // Veure nota a JA_SetMusicPosition. return 0.0f; } inline void JA_EnableMusic(const bool value) { if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING)) JA_StopMusic(); - JA_musicEnabled = value; } // --- Sound Functions --- -inline JA_Sound_t* JA_NewSound(Uint8* buffer, Uint32 length) { - JA_Sound_t* sound = new JA_Sound_t(); - sound->buffer = buffer; - sound->length = length; - return sound; -} - inline JA_Sound_t* JA_LoadSound(uint8_t* buffer, uint32_t size) { - JA_Sound_t* sound = new JA_Sound_t(); - if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &sound->buffer, &sound->length)) { - SDL_Log("Failed to load WAV from memory: %s", SDL_GetError()); - delete sound; + auto sound = std::make_unique(); + Uint8* raw = nullptr; + if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) { + std::cout << "Failed to load WAV from memory: " << SDL_GetError() << '\n'; return nullptr; } - return sound; + sound->buffer.reset(raw); // adopta el SDL_malloc'd buffer + return sound.release(); } inline JA_Sound_t* JA_LoadSound(const char* filename) { - JA_Sound_t* sound = new JA_Sound_t(); - if (!SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length)) { - SDL_Log("Failed to load WAV file: %s", SDL_GetError()); - delete sound; + auto sound = std::make_unique(); + Uint8* raw = nullptr; + if (!SDL_LoadWAV(filename, &sound->spec, &raw, &sound->length)) { + std::cout << "Failed to load WAV file: " << SDL_GetError() << '\n'; return nullptr; } - return sound; + sound->buffer.reset(raw); // adopta el SDL_malloc'd buffer + return sound.release(); } inline int JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = 0) { @@ -406,6 +534,7 @@ inline int JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = int channel = 0; while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) { + // No hay canal libre, reemplazamos el primero channel = 0; } @@ -426,12 +555,12 @@ inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); if (!channels[channel].stream) { - SDL_Log("Failed to create audio stream for sound!"); + std::cout << "Failed to create audio stream for sound!" << '\n'; channels[channel].state = JA_CHANNEL_FREE; return -1; } - SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length); + SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer.get(), channels[channel].sound->length); SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume[group]); SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); @@ -443,7 +572,7 @@ inline void JA_DeleteSound(JA_Sound_t* sound) { for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { if (channels[i].sound == sound) JA_StopChannel(i); } - SDL_free(sound->buffer); + // buffer es destrueix automàticament via RAII (SDLFreeDeleter). delete sound; } @@ -489,7 +618,7 @@ inline void JA_StopChannel(const int channel) { channels[i].stream = nullptr; channels[i].state = JA_CHANNEL_FREE; channels[i].pos = 0; - channels[i].sound = NULL; + channels[i].sound = nullptr; } } } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { @@ -498,7 +627,7 @@ inline void JA_StopChannel(const int channel) { channels[channel].stream = nullptr; channels[channel].state = JA_CHANNEL_FREE; channels[channel].pos = 0; - channels[channel].sound = NULL; + channels[channel].sound = nullptr; } } } @@ -523,6 +652,7 @@ inline float JA_SetSoundVolume(float volume, const int group = -1) { return v; } + // Aplicar volum als canals actius. for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { if ((channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED)) { if (group == -1 || channels[i].group == group) { diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index b7024e9..78c55fc 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -17,13 +17,13 @@ #include // for basic_string, operator+, char_t... #include // for vector -#include "core/audio/jail_audio.hpp" // for JA_Init -#include "core/input/input.h" // for Input, inputs_e, INPUT_USE_GAME... -#include "core/input/mouse.hpp" // for Mouse::handleEvent, Mouse::upda... -#include "core/locale/lang.h" // for Lang, MAX_LANGUAGES, ba_BA, en_UK -#include "core/rendering/screen.h" // for Screen -#include "core/rendering/texture.h" // for Texture -#include "core/resources/asset.h" // for Asset, assetType +#include "core/audio/audio.hpp" // for Audio::init, Audio::destroy +#include "core/input/input.h" // for Input, inputs_e, INPUT_USE_GAME... +#include "core/input/mouse.hpp" // for Mouse::handleEvent, Mouse::upda... +#include "core/locale/lang.h" // for Lang, MAX_LANGUAGES, ba_BA, en_UK +#include "core/rendering/screen.h" // for Screen +#include "core/rendering/texture.h" // for Texture +#include "core/resources/asset.h" // for Asset, assetType #include "core/resources/resource.h" #include "core/resources/resource_helper.h" #include "game/defaults.hpp" // for SECTION_PROG_LOGO, GAMECANVAS_H... @@ -173,6 +173,8 @@ Director::~Director() { Lang::destroy(); delete section; + Audio::destroy(); + SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); @@ -236,7 +238,7 @@ void Director::initInput() { // Inicializa JailAudio void Director::initJailAudio() { - JA_Init(48000, SDL_AUDIO_S16, 2); + Audio::init(); } // Arranca SDL y crea la ventana diff --git a/source/external/stb_vorbis.c b/source/external/stb_vorbis.c index 49df433..7e5daa3 100644 --- a/source/external/stb_vorbis.c +++ b/source/external/stb_vorbis.c @@ -1,4 +1,4 @@ -// Ogg Vorbis audio decoder - v1.20 - public domain +// Ogg Vorbis audio decoder - v1.22 - public domain // http://nothings.org/stb_vorbis/ // // Original version written by Sean Barrett in 2007. @@ -29,12 +29,15 @@ // Bernhard Wodo Evan Balster github:alxprd // Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Phillip Bennefall Rohit Thiago Goulart -// github:manxorist saga musix github:infatum +// github:manxorist Saga Musix github:infatum // Timur Gagiev Maxwell Koo Peter Waller // github:audinowho Dougall Johnson David Reid // github:Clownacy Pedro J. Estebanez Remi Verschelde +// AnthoFoxo github:morlat Gabriel Ravier // // Partial history: +// 1.22 - 2021-07-11 - various small fixes +// 1.21 - 2021-07-02 - fix bug for files with no comments // 1.20 - 2020-07-11 - several small fixes // 1.19 - 2020-02-05 - warnings // 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc. @@ -220,6 +223,12 @@ extern int stb_vorbis_decode_frame_pushdata( // channel. In other words, (*output)[0][0] contains the first sample from // the first channel, and (*output)[1][0] contains the first sample from // the second channel. +// +// *output points into stb_vorbis's internal output buffer storage; these +// buffers are owned by stb_vorbis and application code should not free +// them or modify their contents. They are transient and will be overwritten +// once you ask for more data to get decoded, so be sure to grab any data +// you need before then. extern void stb_vorbis_flush_pushdata(stb_vorbis *f); // inform stb_vorbis that your next datablock will not be contiguous with @@ -579,7 +588,7 @@ enum STBVorbisError #if defined(_MSC_VER) || defined(__MINGW32__) #include #endif - #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) + #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) #include #endif #else // STB_VORBIS_NO_CRT @@ -646,6 +655,12 @@ typedef signed int int32; typedef float codetype; +#ifdef _MSC_VER +#define STBV_NOTUSED(v) (void)(v) +#else +#define STBV_NOTUSED(v) (void)sizeof(v) +#endif + // @NOTE // // Some arrays below are tagged "//varies", which means it's actually @@ -1046,7 +1061,7 @@ static float float32_unpack(uint32 x) uint32 sign = x & 0x80000000; uint32 exp = (x & 0x7fe00000) >> 21; double res = sign ? -(double)mantissa : (double)mantissa; - return (float) ldexp((float)res, exp-788); + return (float) ldexp((float)res, (int)exp-788); } @@ -1077,6 +1092,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) // find the first entry for (k=0; k < n; ++k) if (len[k] < NO_CODE) break; if (k == n) { assert(c->sorted_entries == 0); return TRUE; } + assert(len[k] < 32); // no error return required, code reading lens checks this // add to the list add_entry(c, 0, k, m++, len[k], values); // add all available leaves @@ -1090,6 +1106,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) uint32 res; int z = len[i], y; if (z == NO_CODE) continue; + assert(z < 32); // no error return required, code reading lens checks this // find lowest available leaf (should always be earliest, // which is what the specification calls for) // note that this property, and the fact we can never have @@ -1099,12 +1116,10 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) while (z > 0 && !available[z]) --z; if (z == 0) { return FALSE; } res = available[z]; - assert(z >= 0 && z < 32); available[z] = 0; add_entry(c, bit_reverse(res), i, m++, len[i], values); // propagate availability up the tree if (z != len[i]) { - assert(len[i] >= 0 && len[i] < 32); for (y=len[i]; y > z; --y) { assert(available[y] == 0); available[y] = res + (1 << (32-y)); @@ -2577,34 +2592,33 @@ static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, while (z > base) { float k00,k11; + float l00,l11; - k00 = z[-0] - z[-8]; - k11 = z[-1] - z[-9]; - z[-0] = z[-0] + z[-8]; - z[-1] = z[-1] + z[-9]; - z[-8] = k00; - z[-9] = k11 ; + k00 = z[-0] - z[ -8]; + k11 = z[-1] - z[ -9]; + l00 = z[-2] - z[-10]; + l11 = z[-3] - z[-11]; + z[ -0] = z[-0] + z[ -8]; + z[ -1] = z[-1] + z[ -9]; + z[ -2] = z[-2] + z[-10]; + z[ -3] = z[-3] + z[-11]; + z[ -8] = k00; + z[ -9] = k11; + z[-10] = (l00+l11) * A2; + z[-11] = (l11-l00) * A2; - k00 = z[ -2] - z[-10]; - k11 = z[ -3] - z[-11]; - z[ -2] = z[ -2] + z[-10]; - z[ -3] = z[ -3] + z[-11]; - z[-10] = (k00+k11) * A2; - z[-11] = (k11-k00) * A2; - - k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation + k00 = z[ -4] - z[-12]; k11 = z[ -5] - z[-13]; + l00 = z[ -6] - z[-14]; + l11 = z[ -7] - z[-15]; z[ -4] = z[ -4] + z[-12]; z[ -5] = z[ -5] + z[-13]; - z[-12] = k11; - z[-13] = k00; - - k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation - k11 = z[ -7] - z[-15]; z[ -6] = z[ -6] + z[-14]; z[ -7] = z[ -7] + z[-15]; - z[-14] = (k00+k11) * A2; - z[-15] = (k00-k11) * A2; + z[-12] = k11; + z[-13] = -k00; + z[-14] = (l11-l00) * A2; + z[-15] = (l00+l11) * -A2; iter_54(z); iter_54(z-8); @@ -3069,6 +3083,7 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f for (q=1; q < g->values; ++q) { j = g->sorted_order[q]; #ifndef STB_VORBIS_NO_DEFER_FLOOR + STBV_NOTUSED(step2_flag); if (finalY[j] >= 0) #else if (step2_flag[j]) @@ -3171,6 +3186,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, // WINDOWING + STBV_NOTUSED(left_end); n = f->blocksize[m->blockflag]; map = &f->mapping[m->mapping]; @@ -3368,7 +3384,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, // this isn't to spec, but spec would require us to read ahead // and decode the size of all current frames--could be done, // but presumably it's not a commonly used feature - f->current_loc = -n2; // start of first frame is positioned for discard + f->current_loc = 0u - n2; // start of first frame is positioned for discard (NB this is an intentional unsigned overflow/wrap-around) // we might have to discard samples "from" the next frame too, // if we're lapping a large block then a small at the start? f->discard_samples_deferred = n - right_end; @@ -3642,9 +3658,11 @@ static int start_decoder(vorb *f) f->vendor[len] = (char)'\0'; //user comments f->comment_list_length = get32_packet(f); - if (f->comment_list_length > 0) { - f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length)); - if (f->comment_list == NULL) return error(f, VORBIS_outofmem); + f->comment_list = NULL; + if (f->comment_list_length > 0) + { + f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length)); + if (f->comment_list == NULL) return error(f, VORBIS_outofmem); } for(i=0; i < f->comment_list_length; ++i) { @@ -3867,8 +3885,7 @@ static int start_decoder(vorb *f) unsigned int div=1; for (k=0; k < c->dimensions; ++k) { int off = (z / div) % c->lookup_values; - float val = mults[off]; - val = mults[off]*c->delta_value + c->minimum_value + last; + float val = mults[off]*c->delta_value + c->minimum_value + last; c->multiplicands[j*c->dimensions + k] = val; if (c->sequence_p) last = val; @@ -3951,7 +3968,7 @@ static int start_decoder(vorb *f) if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } for (k=0; k < 1 << g->class_subclasses[j]; ++k) { - g->subclass_books[j][k] = get_bits(f,8)-1; + g->subclass_books[j][k] = (int16)get_bits(f,8)-1; if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } } @@ -4509,6 +4526,7 @@ stb_vorbis *stb_vorbis_open_pushdata( *error = VORBIS_need_more_data; else *error = p.error; + vorbis_deinit(&p); return NULL; } f = vorbis_alloc(&p); @@ -4566,7 +4584,7 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) header[i] = get8(f); if (f->eof) return 0; if (header[4] != 0) goto invalid; - goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24); + goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24); for (i=22; i < 26; ++i) header[i] = 0; crc = 0; @@ -4970,7 +4988,7 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) // set. whoops! break; } - previous_safe = last_page_loc+1; + //previous_safe = last_page_loc+1; // NOTE: not used after this point, but note for debugging last_page_loc = stb_vorbis_get_file_offset(f); } @@ -5081,7 +5099,10 @@ stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const st stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) { stb_vorbis *f, p; - if (data == NULL) return NULL; + if (!data) { + if (error) *error = VORBIS_unexpected_eof; + return NULL; + } vorbis_init(&p, alloc); p.stream = (uint8 *) data; p.stream_end = (uint8 *) data + len; @@ -5156,11 +5177,11 @@ static void copy_samples(short *dest, float *src, int len) static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE; + #define STB_BUFFER_SIZE 32 + float buffer[STB_BUFFER_SIZE]; + int i,j,o,n = STB_BUFFER_SIZE; check_endianness(); - for (o = 0; o < len; o += BUFFER_SIZE) { + for (o = 0; o < len; o += STB_BUFFER_SIZE) { memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { @@ -5177,16 +5198,17 @@ static void compute_samples(int mask, short *output, int num_c, float **data, in output[o+i] = v; } } + #undef STB_BUFFER_SIZE } static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE >> 1; + #define STB_BUFFER_SIZE 32 + float buffer[STB_BUFFER_SIZE]; + int i,j,o,n = STB_BUFFER_SIZE >> 1; // o is the offset in the source data check_endianness(); - for (o = 0; o < len; o += BUFFER_SIZE >> 1) { + for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) { // o2 is the offset in the output data int o2 = o << 1; memset(buffer, 0, sizeof(buffer)); @@ -5216,6 +5238,7 @@ static void compute_stereo_samples(short *output, int num_c, float **data, int d output[o2+i] = v; } } + #undef STB_BUFFER_SIZE } static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) @@ -5288,8 +5311,6 @@ int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short float **outputs; int len = num_shorts / channels; int n=0; - int z = f->channels; - if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; @@ -5308,8 +5329,6 @@ int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, in { float **outputs; int n=0; - int z = f->channels; - if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index ec9e76a..211b391 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -30,17 +30,17 @@ namespace Defaults::Video { namespace Defaults::Audio { constexpr bool ENABLED = true; - constexpr int VOLUME = 100; + constexpr float VOLUME = 1.0F; } // namespace Defaults::Audio namespace Defaults::Music { constexpr bool ENABLED = true; - constexpr int VOLUME = 100; + constexpr float VOLUME = 0.8F; } // namespace Defaults::Music namespace Defaults::Sound { constexpr bool ENABLED = true; - constexpr int VOLUME = 100; + constexpr float VOLUME = 1.0F; } // namespace Defaults::Sound namespace Defaults::Loading { diff --git a/source/game/game.cpp b/source/game/game.cpp index 90fb548..5cca53b 100644 --- a/source/game/game.cpp +++ b/source/game/game.cpp @@ -8,7 +8,7 @@ #include // for basic_ostream, char_traits, operator<< #include // for accumulate -#include "core/audio/jail_audio.hpp" // for JA_PlaySound, JA_DeleteSound, JA_LoadSound +#include "core/audio/audio.hpp" // for Audio #include "core/input/global_inputs.hpp" // for GlobalInputs::handle #include "core/input/input.h" // for inputs_e, Input, REPEAT_TRUE, REPEAT_FALSE #include "core/locale/lang.h" // for Lang @@ -1307,7 +1307,7 @@ void Game::updateHiScore() { // Si se supera la máxima puntuación emite sonido if (hiScoreAchieved == false) { hiScoreAchieved = true; - JA_PlaySound(hiScoreSound); + Audio::get()->playSound(hiScoreSound); } } } @@ -1459,9 +1459,9 @@ void Game::updateStage() { } } updateHiScore(); - JA_StopMusic(); + Audio::get()->stopMusic(); } - JA_PlaySound(stageChangeSound); + Audio::get()->playSound(stageChangeSound); stageBitmapCounter = 0; enemySpeed = defaultEnemySpeed; setBalloonSpeed(enemySpeed); @@ -1499,7 +1499,7 @@ void Game::updateDeath() { if (!demo.enabled) { const Uint8 index = rand() % 4; JA_Sound_t *sound[4] = {bubble1Sound, bubble2Sound, bubble3Sound, bubble4Sound}; - JA_PlaySound(sound[index], 0); + Audio::get()->playSound(sound[index]); } } } else { @@ -1746,7 +1746,7 @@ void Game::destroyAllBalloons() { enemyDeployCounter = 255; if (!demo.enabled) { - JA_PlaySound(powerBallSound); + Audio::get()->playSound(powerBallSound); } effect.flash = true; effect.shake = true; @@ -1811,26 +1811,26 @@ void Game::checkPlayerItemCollision(Player *player) { player->addScore(1000); updateHiScore(); createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n1000Sprite->getWidth() / 2), player->getPosY(), n1000Sprite); - JA_PlaySound(itemPickUpSound); + Audio::get()->playSound(itemPickUpSound); break; case ITEM_POINTS_2_GAVINA: player->addScore(2500); updateHiScore(); createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n2500Sprite->getWidth() / 2), player->getPosY(), n2500Sprite); - JA_PlaySound(itemPickUpSound); + Audio::get()->playSound(itemPickUpSound); break; case ITEM_POINTS_3_PACMAR: player->addScore(5000); updateHiScore(); createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n5000Sprite->getWidth() / 2), player->getPosY(), n5000Sprite); - JA_PlaySound(itemPickUpSound); + Audio::get()->playSound(itemPickUpSound); break; case ITEM_CLOCK: enableTimeStopItem(); - JA_PlaySound(itemPickUpSound); + Audio::get()->playSound(itemPickUpSound); break; case ITEM_COFFEE: @@ -1840,12 +1840,12 @@ void Game::checkPlayerItemCollision(Player *player) { createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n5000Sprite->getWidth() / 2), player->getPosY(), n5000Sprite); } player->giveExtraHit(); - JA_PlaySound(itemPickUpSound); + Audio::get()->playSound(itemPickUpSound); break; case ITEM_COFFEE_MACHINE: player->setPowerUp(true); - JA_PlaySound(itemPickUpSound); + Audio::get()->playSound(itemPickUpSound); coffeeMachineEnabled = false; break; @@ -1876,7 +1876,7 @@ void Game::checkBulletBalloonCollision() { // Si no es el modo demo, genera un sonido if (!demo.enabled) { - JA_PlaySound(balloonSound); + Audio::get()->playSound(balloonSound); } // Deshabilita la bala @@ -1887,7 +1887,7 @@ void Game::checkBulletBalloonCollision() { if ((droppeditem != NO_KIND) && !(demo.enabled) && !(demo.recording)) { if (droppeditem != ITEM_COFFEE_MACHINE) { createItem(droppeditem, balloon->getPosX(), balloon->getPosY()); - JA_PlaySound(itemDropSound); + Audio::get()->playSound(itemDropSound); } else { createItem(droppeditem, players[index]->getPosX(), 0); coffeeMachineEnabled = true; @@ -1945,7 +1945,7 @@ void Game::updateItems() { if (item->isEnabled()) { item->update(); if (item->isOnFloor()) { - JA_PlaySound(coffeeMachineSound); + Audio::get()->playSound(coffeeMachineSound); effect.shake = true; } } @@ -2132,12 +2132,12 @@ void Game::killPlayer(Player *player) { player->removeExtraHit(); throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2)); if (!demo.enabled) { - JA_PlaySound(coffeeOutSound); + Audio::get()->playSound(coffeeOutSound); } } else if (deathSequence.phase == DeathPhase::None) { if (!demo.enabled) { - JA_PauseMusic(); - JA_PlaySound(playerCollisionSound); + Audio::get()->pauseMusic(); + Audio::get()->playSound(playerCollisionSound); } stopAllBalloons(10); shakeScreen(); @@ -2167,11 +2167,11 @@ void Game::updateDeathSequence() { // Espera 500ms antes de completar la muerte if (SDL_GetTicks() - deathSequence.phaseStartTicks >= 500) { if (!demo.enabled) { - JA_PlaySound(coffeeOutSound); + Audio::get()->playSound(coffeeOutSound); if (allPlayersAreDead()) { - JA_StopMusic(); + Audio::get()->stopMusic(); } else { - JA_ResumeMusic(); + Audio::get()->resumeMusic(); } } deathSequence.player->setAlive(false); @@ -2234,7 +2234,7 @@ void Game::updateEnemyDeployCounter() { // Actualiza el juego void Game::update() { // Actualiza el audio - JA_Update(); + Audio::update(); // Actualiza los efectos basados en tiempo real (no en el throttle del juego) updateDeathShake(); @@ -2541,7 +2541,7 @@ void Game::checkGameInput() { player->setFireCooldown(10); // Reproduce el sonido de disparo - JA_PlaySound(bulletSound); + Audio::get()->playSound(bulletSound); demo.keys.fire = 1; } @@ -2555,7 +2555,7 @@ void Game::checkGameInput() { player->setFireCooldown(10); // Reproduce el sonido de disparo - JA_PlaySound(bulletSound); + Audio::get()->playSound(bulletSound); demo.keys.fireLeft = 1; } @@ -2569,7 +2569,7 @@ void Game::checkGameInput() { player->setFireCooldown(10); // Reproduce el sonido de disparo - JA_PlaySound(bulletSound); + Audio::get()->playSound(bulletSound); demo.keys.fireRight = 1; } @@ -2610,11 +2610,11 @@ void Game::renderMessages() { if (timeStoppedCounter > 100) { if (timeStoppedCounter % 30 == 0) { - JA_PlaySound(clockSound, false); + Audio::get()->playSound(clockSound); } } else { if (timeStoppedCounter % 15 == 0) { - JA_PlaySound(clockSound, false); + Audio::get()->playSound(clockSound); } } } @@ -2652,8 +2652,8 @@ void Game::enableTimeStopItem() { stopAllBalloons(TIME_STOPPED_COUNTER); setTimeStopped(true); incTimeStoppedCounter(TIME_STOPPED_COUNTER); - if (JA_GetMusicState() == JA_MUSIC_PLAYING) { - JA_PauseMusic(); + if (Audio::getRealMusicState() == Audio::MusicState::PLAYING) { + Audio::get()->pauseMusic(); } } @@ -2662,8 +2662,8 @@ void Game::disableTimeStopItem() { timeStopped = false; setTimeStoppedCounter(0); startAllBalloons(); - if (JA_GetMusicState() == JA_MUSIC_PAUSED) { - JA_ResumeMusic(); + if (Audio::getRealMusicState() == Audio::MusicState::PAUSED) { + Audio::get()->resumeMusic(); } } @@ -2729,11 +2729,11 @@ void Game::iterate() { gameOverInitialized = false; // Si la música no está sonando - if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) { + if ((Audio::getRealMusicState() == Audio::MusicState::STOPPED) || (Audio::getRealMusicState() == Audio::MusicState::STOPPED)) { // Reproduce la música (nunca en modo demo: deja sonar la del título) if (!gameCompleted && !demo.enabled) { if (players[0]->isAlive()) { - JA_PlayMusic(gameMusic); + Audio::get()->playMusic(gameMusic); } } } @@ -2781,7 +2781,7 @@ void Game::handleEvent(const SDL_Event *event) { if (gameCompleted) { gameOverPostFade = 1; fade->activateFade(); - JA_PlaySound(itemPickUpSound); + Audio::get()->playSound(itemPickUpSound); } } } @@ -2810,15 +2810,15 @@ void Game::updatePausedGame() { const bool b = pauseCounter == 60; const bool c = pauseCounter == 30; if (a || b || c) { - JA_PlaySound(clockSound); + Audio::get()->playSound(clockSound); } pauseCounter--; } else { // Ha finalizado el contador section->name = SECTION_PROG_GAME; section->subsection = numPlayers == 1 ? SUBSECTION_GAME_PLAY_1P : SUBSECTION_GAME_PLAY_2P; - if (JA_GetMusicState() == JA_MUSIC_PAUSED) { - JA_ResumeMusic(); + if (Audio::getRealMusicState() == Audio::MusicState::PAUSED) { + Audio::get()->resumeMusic(); } } } else { // Actualiza la lógica del menu de pausa @@ -2847,7 +2847,7 @@ void Game::updatePausedGame() { if (fade->hasEnded()) { section->name = SECTION_PROG_TITLE; section->subsection = SUBSECTION_TITLE_1; - JA_StopMusic(); + Audio::get()->stopMusic(); } } } @@ -2897,8 +2897,8 @@ void Game::renderPausedGame() { // Inicializa el estado de pausa del juego void Game::enterPausedGame() { // Pone en pausa la música - if (JA_GetMusicState() == JA_MUSIC_PLAYING) { - JA_PauseMusic(); + if (Audio::getRealMusicState() == Audio::MusicState::PLAYING) { + Audio::get()->pauseMusic(); } // Reinicia el menu diff --git a/source/game/options.cpp b/source/game/options.cpp index 7012604..1ca4bbf 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -114,7 +114,7 @@ namespace Options { parseBoolField(aud, "enabled", audio.enabled); if (aud.contains("volume")) { try { - audio.volume = std::clamp(aud["volume"].get_value(), 0, 100); + audio.volume = std::clamp(aud["volume"].get_value(), 0.0F, 1.0F); } catch (...) {} } if (aud.contains("music")) { @@ -122,7 +122,7 @@ namespace Options { parseBoolField(mus, "enabled", audio.music.enabled); if (mus.contains("volume")) { try { - audio.music.volume = std::clamp(mus["volume"].get_value(), 0, 100); + audio.music.volume = std::clamp(mus["volume"].get_value(), 0.0F, 1.0F); } catch (...) {} } } @@ -131,7 +131,7 @@ namespace Options { parseBoolField(snd, "enabled", audio.sound.enabled); if (snd.contains("volume")) { try { - audio.sound.volume = std::clamp(snd["volume"].get_value(), 0, 100); + audio.sound.volume = std::clamp(snd["volume"].get_value(), 0.0F, 1.0F); } catch (...) {} } } @@ -307,7 +307,7 @@ namespace Options { file << " current_crtpi_preset: \"" << video.shader.current_crtpi_preset_name << "\"\n\n"; // AUDIO - file << "# AUDIO (volume range: 0..100)\n"; + file << "# AUDIO (volume range: 0.0..1.0)\n"; file << "audio:\n"; file << " enabled: " << boolToString(audio.enabled) << "\n"; file << " volume: " << audio.volume << "\n"; diff --git a/source/game/options.hpp b/source/game/options.hpp index 0e6f25d..13ee73d 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -56,17 +56,17 @@ namespace Options { struct Music { bool enabled = Defaults::Music::ENABLED; - int volume = Defaults::Music::VOLUME; + float volume = Defaults::Music::VOLUME; }; struct Sound { bool enabled = Defaults::Sound::ENABLED; - int volume = Defaults::Sound::VOLUME; + float volume = Defaults::Sound::VOLUME; }; struct Audio { bool enabled = Defaults::Audio::ENABLED; - int volume = Defaults::Audio::VOLUME; + float volume = Defaults::Audio::VOLUME; Music music; Sound sound; }; diff --git a/source/game/scenes/instructions.cpp b/source/game/scenes/instructions.cpp index 805e464..cbb6dc3 100644 --- a/source/game/scenes/instructions.cpp +++ b/source/game/scenes/instructions.cpp @@ -6,7 +6,7 @@ #include // for char_traits, basic_ostream, operator<< #include // for basic_string -#include "core/audio/jail_audio.hpp" // for JA_StopMusic +#include "core/audio/audio.hpp" // for Audio::update #include "core/input/global_inputs.hpp" // for GlobalInputs::handle #include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e #include "core/locale/lang.h" // for Lang @@ -71,7 +71,7 @@ Instructions::~Instructions() { void Instructions::update() { // Bombea el stream de música: si no se llama, el buffer se vacía y la // música se corta hasta que volvamos a una escena que sí lo haga. - JA_Update(); + Audio::update(); // Comprueba las entradas checkInput(); diff --git a/source/game/scenes/intro.cpp b/source/game/scenes/intro.cpp index 2981595..cf9f24c 100644 --- a/source/game/scenes/intro.cpp +++ b/source/game/scenes/intro.cpp @@ -4,7 +4,7 @@ #include // for basic_string -#include "core/audio/jail_audio.hpp" // for JA_StopMusic, JA_DeleteMusic, JA_LoadMusic +#include "core/audio/audio.hpp" // for Audio::get, Audio::update #include "core/input/global_inputs.hpp" // for GlobalInputs::handle #include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e #include "core/locale/lang.h" // for Lang @@ -149,7 +149,7 @@ Intro::Intro(SDL_Renderer *renderer, section_t *section) { t->center(GAMECANVAS_CENTER_X); } - JA_PlayMusic(music, 0); + Audio::get()->playMusic(music, 0); } // Destructor @@ -177,7 +177,7 @@ void Intro::checkInput() { if (GlobalInputs::handle()) { return; } if (Input::get()->checkInput(input_pause, REPEAT_FALSE) || Input::get()->checkInput(input_accept, REPEAT_FALSE) || Input::get()->checkInput(input_fire_left, REPEAT_FALSE) || Input::get()->checkInput(input_fire_center, REPEAT_FALSE) || Input::get()->checkInput(input_fire_right, REPEAT_FALSE)) { - JA_StopMusic(); + Audio::get()->stopMusic(); section->name = SECTION_PROG_TITLE; section->subsection = SUBSECTION_TITLE_1; } @@ -307,7 +307,7 @@ void Intro::updateScenes() { if (bitmaps[5]->hasFinished() && texts[8]->hasFinished()) { bitmaps[5]->setEnabled(false); texts[8]->setEnabled(false); - JA_StopMusic(); + Audio::get()->stopMusic(); section->name = SECTION_PROG_TITLE; section->subsection = SUBSECTION_TITLE_1; } @@ -321,7 +321,7 @@ void Intro::updateScenes() { // Actualiza las variables del objeto void Intro::update() { - JA_Update(); + Audio::update(); checkInput(); if (SDL_GetTicks() - ticks > ticksSpeed) { @@ -365,7 +365,7 @@ void Intro::render() { // Bucle principal void Intro::run() { - JA_PlayMusic(music, 0); + Audio::get()->playMusic(music, 0); while (section->name == SECTION_PROG_INTRO) { iterate(); diff --git a/source/game/scenes/logo.cpp b/source/game/scenes/logo.cpp index 8b32d02..82ebef6 100644 --- a/source/game/scenes/logo.cpp +++ b/source/game/scenes/logo.cpp @@ -5,7 +5,7 @@ #include // for min #include // for basic_string -#include "core/audio/jail_audio.hpp" // for JA_StopMusic +#include "core/audio/audio.hpp" // for Audio::get, Audio::update #include "core/input/global_inputs.hpp" // for GlobalInputs::handle #include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e #include "core/rendering/screen.h" // for Screen @@ -38,7 +38,7 @@ Logo::Logo(SDL_Renderer *renderer, section_t *section) { ticks = 0; ticksSpeed = 15; - JA_StopMusic(); + Audio::get()->stopMusic(); } // Destructor @@ -85,7 +85,7 @@ void Logo::renderFade() { // Actualiza las variables del objeto void Logo::update() { - JA_Update(); + Audio::update(); checkInput(); if (SDL_GetTicks() - ticks > ticksSpeed) { @@ -120,7 +120,7 @@ void Logo::render() { // Bucle para el logo del juego void Logo::run() { - JA_StopMusic(); + Audio::get()->stopMusic(); while (section->name == SECTION_PROG_LOGO) { iterate(); diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index d407c70..be31454 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -6,7 +6,7 @@ #include // for basic_ostream, operator<<, basic_ostrea... #include // for basic_string, operator+, char_traits -#include "core/audio/jail_audio.hpp" // for JA_StopMusic, JA_GetMusicState, JA_Play... +#include "core/audio/audio.hpp" // for Audio #include "core/input/global_inputs.hpp" // for GlobalInputs::handle #include "core/input/input.h" // for Input, INPUT_USE_GAMECONTROLLER, INPUT_... #include "core/locale/lang.h" // for Lang, ba_BA, en_UK, es_ES @@ -212,7 +212,7 @@ void Title::init() { // Actualiza las variables del objeto void Title::update() { // Actualiza el audio - JA_Update(); + Audio::update(); // Comprueba las entradas checkInput(); @@ -243,7 +243,7 @@ void Title::update() { Screen::get()->blit(); // Reproduce el efecto sonoro - JA_PlaySound(crashSound); + Audio::get()->playSound(crashSound); } } break; @@ -276,8 +276,8 @@ void Title::update() { // Sección 3 - La pantalla de titulo con el menú y la música case SUBSECTION_TITLE_3: { if (counter > 0) { // Reproduce la música - if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) { - JA_PlayMusic(titleMusic); + if (Audio::getRealMusicState() == Audio::MusicState::STOPPED) { + Audio::get()->playMusic(titleMusic); } dustBitmapR->update(); @@ -291,19 +291,19 @@ void Title::update() { case 0: // 1 PLAYER section->name = SECTION_PROG_GAME; section->subsection = SUBSECTION_GAME_PLAY_1P; - JA_StopMusic(); + Audio::get()->stopMusic(); break; case 1: // 2 PLAYERS section->name = SECTION_PROG_GAME; section->subsection = SUBSECTION_GAME_PLAY_2P; - JA_StopMusic(); + Audio::get()->stopMusic(); break; case 2: // QUIT #ifndef __EMSCRIPTEN__ section->name = SECTION_PROG_QUIT; - JA_StopMusic(); + Audio::get()->stopMusic(); #endif break; diff --git a/source/game/ui/menu.cpp b/source/game/ui/menu.cpp index ee58579..1b8be6a 100644 --- a/source/game/ui/menu.cpp +++ b/source/game/ui/menu.cpp @@ -5,7 +5,8 @@ #include // for accumulate #include // for basic_stringstream -#include "core/audio/jail_audio.hpp" // for JA_LoadSound, JA_PlaySound, JA_DeleteSound +#include "core/audio/audio.hpp" // for Audio::get (playSound) +#include "core/audio/jail_audio.hpp" // for JA_LoadSound, JA_DeleteSound (propietat local) #include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e #include "core/rendering/text.h" // for Text #include "core/resources/asset.h" // for Asset @@ -758,28 +759,28 @@ void Menu::checkInput() { if (Input::get()->checkInput(input_up, REPEAT_FALSE)) { decreaseSelectorIndex(); if (soundMove) { - JA_PlaySound(soundMove); + Audio::get()->playSound(soundMove); } } if (Input::get()->checkInput(input_down, REPEAT_FALSE)) { increaseSelectorIndex(); if (soundMove) { - JA_PlaySound(soundMove); + Audio::get()->playSound(soundMove); } } if (Input::get()->checkInput(input_accept, REPEAT_FALSE)) { itemSelected = selector.index; if (soundAccept) { - JA_PlaySound(soundAccept); + Audio::get()->playSound(soundAccept); } } if (Input::get()->checkInput(input_cancel, REPEAT_FALSE)) { itemSelected = defaultActionWhenCancel; if (soundCancel) { - JA_PlaySound(soundCancel); + Audio::get()->playSound(soundCancel); } } } diff --git a/source/main.cpp b/source/main.cpp index 6ac7e3d..aac7132 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -43,7 +43,6 @@ Reescribiendo el código el 27/09/2022 #include #include "core/system/director.h" -#include "external/stb_vorbis.c" SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { auto *director = new Director(argc, const_cast(argv));