#include "audio.hpp" #include #include // Para clamp #include // 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.h" // clang-format on #include "core/audio/jail_audio.hpp" // Para JA_* #include "core/options.hpp" // Para Options::audio // Singleton Audio* Audio::instance = nullptr; void Audio::init() { Audio::instance = new Audio(); } void Audio::destroy() { delete Audio::instance; } auto Audio::get() -> Audio* { return Audio::instance; } // Constructor Audio::Audio() { initSDLAudio(); } // Destructor Audio::~Audio() { // Liberar recursos de música cargados for (auto& [name, music] : music_cache_) { if (music) { JA_StopMusic(); delete music; } } // Liberar recursos de sonido cargados for (auto& [name, sound] : sound_cache_) { if (sound) { SDL_free(sound->buffer); delete sound; } } JA_Quit(); } void Audio::update() { JA_Update(); } // Reproduce una pista de música a partir de su ruta de fichero void Audio::playMusic(const std::string& path, const int loop) { bool new_loop = (loop != 0); if (music_.state == MusicState::PLAYING && music_.name == path && music_.loop == new_loop) { return; } // Cargar si no está en caché auto it = music_cache_.find(path); JA_Music_t* resource = nullptr; if (it != music_cache_.end()) { resource = it->second; } else { resource = JA_LoadMusic(path.c_str()); if (resource != nullptr) { music_cache_[path] = resource; } } if (resource == nullptr) { std::cerr << "Audio: no se pudo cargar la música: " << path << '\n'; return; } if (music_.state == MusicState::PLAYING) { JA_StopMusic(); } JA_PlayMusic(resource, loop); music_.name = path; music_.loop = new_loop; music_.state = MusicState::PLAYING; } void Audio::pauseMusic() { if (music_enabled_ && music_.state == MusicState::PLAYING) { JA_PauseMusic(); music_.state = MusicState::PAUSED; } } void Audio::resumeMusic() { if (music_enabled_ && music_.state == MusicState::PAUSED) { JA_ResumeMusic(); music_.state = MusicState::PLAYING; } } void Audio::stopMusic() { if (music_enabled_) { JA_StopMusic(); music_.state = MusicState::STOPPED; } } // Reproduce un efecto de sonido a partir de su ruta de fichero void Audio::playSound(const std::string& path, Group group) const { if (!sound_enabled_) return; auto it = sound_cache_.find(path); JA_Sound_t* resource = nullptr; if (it != sound_cache_.end()) { resource = it->second; } else { resource = JA_LoadSound(path.c_str()); if (resource != nullptr) { sound_cache_[path] = resource; } } if (resource == nullptr) { std::cerr << "Audio: no se pudo cargar el sonido: " << path << '\n'; return; } JA_PlaySound(resource, 0, static_cast(group)); } // Reproduce un sonido por puntero directo (para reutilizar recursos ya cargados) void Audio::playSound(JA_Sound_t* sound, Group group) const { if (sound_enabled_) { JA_PlaySound(sound, 0, static_cast(group)); } } void Audio::stopAllSounds() const { if (sound_enabled_) { JA_StopChannel(-1); } } void Audio::fadeOutMusic(int milliseconds) const { if (music_enabled_ && getRealMusicState() == MusicState::PLAYING) { JA_FadeOutMusic(milliseconds); } } 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; default: return MusicState::STOPPED; } } void Audio::setSoundVolume(float sound_volume, Group group) const { if (sound_enabled_) { sound_volume = std::clamp(sound_volume, MIN_VOLUME, MAX_VOLUME); JA_SetSoundVolume(sound_volume * Options::audio.volume, static_cast(group)); } } void Audio::setMusicVolume(float music_volume) const { if (music_enabled_) { music_volume = std::clamp(music_volume, MIN_VOLUME, MAX_VOLUME); JA_SetMusicVolume(music_volume * Options::audio.volume); } } void Audio::applySettings() { enable(Options::audio.enabled); } void Audio::enable(bool value) { enabled_ = value; setSoundVolume(enabled_ ? Options::audio.sound.volume : MIN_VOLUME); setMusicVolume(enabled_ ? Options::audio.music.volume : MIN_VOLUME); } void Audio::initSDLAudio() { if (!SDL_Init(SDL_INIT_AUDIO)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AUDIO could not initialize! SDL Error: %s", SDL_GetError()); } else { JA_Init(FREQUENCY, SDL_AUDIO_S16LE, 2); enable(Options::audio.enabled); std::cout << "\n** AUDIO SYSTEM **\n"; std::cout << "Audio system initialized successfully\n"; } }