#pragma once #include // Para std::lround #include // Para int8_t, uint8_t #include // Para std::function #include // Para std::unique_ptr #include // Para string #include // Para move // Forward-declares per no incloure core/audio/jail_audio.hpp al header. Els // tres símbols (Music/Sound para el punter que exposa la API i Engine per al // std::unique_ptr membre) s'usen solo per punter al header, así que // el forward-decl basta. El ~Audio() en .cpp veu la definició completa i // instancia correctament el dtor de l'unique_ptr. namespace Ja { class Engine; struct Music; struct Sound; } // namespace Ja // --- Clase Audio: gestor d'àudio (singleton) --- // Port del subsistema d'àudio del projecte ../aee, desacoblat d'Options: // la configuración entra per la struct Audio::Config a init()/applySettings(), // en lloc de llegir directament Options::audio. Això deixa audio.cpp independent // del layout d'Options i permet substituir la font de configuración. // // Els volums es manegen internament como a float 0.0–1.0; la capa de // presentació (menús, notificacions) usa las helpers toPercent/fromPercent // per mostrar 0–100 a l'usuari. class Audio { public: // --- Configuración injectada (Options la construeix via buildAudioConfig) --- struct Config { bool enabled{true}; float volume{1.0F}; // Master 0..1 bool music_enabled{true}; float music_volume{0.8F}; bool sound_enabled{true}; float sound_volume{1.0F}; }; // --- Enums --- enum class Group : std::int8_t { ALL = -1, // Tots los grups GAME = 0, // Sons del joc INTERFACE = 1 // Sons de la interfície }; enum class MusicState : std::uint8_t { PLAYING, // Reproduint música PAUSED, // Música pausada STOPPED, // Música aturada }; // --- Constants --- static constexpr float MAX_VOLUME = 1.0F; // Volum màxim (float 0..1) static constexpr float MIN_VOLUME = 0.0F; // Volum mínim (float 0..1) // --- Singleton --- static void init(const Config& config); // Inicialitza con la configuración rebuda static void destroy(); // Allibera l'objecte Audio static auto get() -> Audio*; // Obté el punter a l'objecte Audio ~Audio(); // Destructor (públic para std::unique_ptr) Audio(const Audio&) = delete; // Evitar còpia Audio(Audio&&) = delete; auto operator=(const Audio&) -> Audio& = delete; // Evitar assignació auto operator=(Audio&&) -> Audio& = delete; static void update(); // Actualització del sistema d'àudio // --- Control de música --- void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0); // Reproduir música per nom (amb crossfade opcional) void playMusic(Ja::Music* music, int loop = -1, int crossfade_ms = 0); // Reproduir música per punter (amb crossfade opcional) void pauseMusic(); // Pausar la reproducció de música void resumeMusic(); // Continua la música pausada void stopMusic(); // Aturar completament la música void fadeOutMusic(int milliseconds); // Fosa de sortida de la música (muta globals de Ja) void setOnMusicEnded(std::function callback); // Callback disparat cuando la pista actual acaba de drenar (CONV-03) // Multiplicador de velocitat de la música actual. 1.0 = normal, // 1.5 = un 50% més ràpid (efecte "chipmunk" — también puja el to). // Es reseteja a 1.0 implícitament a cada `playMusic`. No-op si no // hay música activa. void setMusicSpeed(float ratio); // --- Control de sons --- void playSound(const std::string& name, Group group = Group::GAME); // Reproduir so puntual per nom (muta globals de Ja) void playSound(Ja::Sound* sound, Group group = Group::GAME); // Reproduir so puntual per punter (muta globals de Ja) // Reprodueix un so con la velocitat (i to) escalats per `speed`: // 1.0 = normal, 0.95 ≈ -5% (més greu i lent), 1.05 ≈ +5% (més // agut i ràpid). Mateixa semàntica que `setMusicSpeed`. Útil per a // variacions subtils que eviten la fatiga d'escoltar el mismo // sample idèntic (p.ex. obertures de sarcòfag, picks d'ítems). void playSound(const std::string& name, Group group, float speed); // Reprodueix un so processat per un efecte definit a data/config/sounds.yaml // (preset_name busca a SoundEffectsConfig). Si el preset no existeix // o el motor está al sin de canals con efecte, fa fallback a playSound // sec — l'usuari sent el so igualment, sin la cua. void playSoundWithEcho(const std::string& name, const std::string& preset_name, Group group = Group::GAME); void playSoundWithReverb(const std::string& name, const std::string& preset_name, Group group = Group::GAME); void stopAllSounds(); // Aturar tots los sons (muta globals de Ja) // --- Control de volum (API interna: float 0.0..1.0) --- void setSoundVolume(float volume, Group group = Group::ALL); // Ajusta el volum dels efectes void setMusicVolume(float volume); // Ajusta el volum de la música // --- Helpers de conversió para la capa de presentació --- // UI (menús, notificacions) manega enters 0..100; internament viu float 0..1. // No són constexpr porque std::lround no ho es en C++20; s'usen en runtime. static auto toPercent(float volume) -> int { return static_cast(std::lround(volume * 100.0F)); } static auto fromPercent(int percent) -> float { return static_cast(percent) / 100.0F; } // --- Configuración general --- void enable(bool value); // Estableix l'estat general (reaplica volums) void toggleEnabled() { enable(!enabled_); } // Alterna l'estat general (reaplica volums) void applySettings(const Config& config); // Aplica una nueva configuración // --- Configuración de sons --- void enableSound(bool value); // Estableix l'estat dels sons (reaplica volum) void toggleSound() { enableSound(!sound_enabled_); } // Alterna l'estat dels sons (reaplica volum) // --- Configuración de música --- void enableMusic(bool value); // Estableix l'estat de la música (reaplica volum) void toggleMusic() { enableMusic(!music_enabled_); } // Alterna l'estat de la música (reaplica volum) // --- Consultes d'estat --- [[nodiscard]] auto isEnabled() const -> bool { return enabled_; } [[nodiscard]] auto isSoundEnabled() const -> bool { return sound_enabled_; } [[nodiscard]] auto isMusicEnabled() const -> bool { return music_enabled_; } [[nodiscard]] static auto getMusicState() -> MusicState; // Estat real consultat a Ja:: [[nodiscard]] auto getCurrentMusicName() const -> const std::string& { return music_.name; } // Duración de la pista resolta per nom (mil·lisegons). 0 si la pista no // existeix al cache de recursos o si el seu header OGG no permet // calcular-la. Pensat para clients que necessiten un timeline // determinista (p. ex. RoomFsm) sin dependre de callbacks de fi. [[nodiscard]] static auto getMusicDurationMs(const std::string& name) -> int; private: // --- Tipus anidats --- struct Music { std::string name; // Última pista de música reproduïda (buida si es va passar per punter sin filename) bool loop{false}; // Si el play actual es en bucle }; // --- Mètodes --- explicit Audio(const Config& config); // Constructor privat: rep la config void initSDLAudio(); // Inicialitza SDL Audio void playMusicInternal(Ja::Music* music, int loop, int crossfade_ms); // Camí comú dels dos overloads de playMusic [[nodiscard]] auto effectiveVolume(float volume, bool channel_enabled) const -> float; // Gate master+channel: 0 si algun está off, clamp 0..1 altrament // --- Variables membre --- static std::unique_ptr