esqueleto nivel 1
This commit is contained in:
190
source/core/audio/audio.cpp
Normal file
190
source/core/audio/audio.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "audio.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm> // Para clamp
|
||||
#include <iostream>
|
||||
|
||||
// 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<int>(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<int>(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<int>(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";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user