Files
aee-arcade/source/core/audio/audio.hpp
T
JailDesignerandClaude Opus 4.7 893e5b27e4 refactor(core/audio): helper effectiveVolume compartit (DUP-02)
setSoundVolume i setMusicVolume repetien la mateixa lògica de clamp +
gate (enabled_ && channel_enabled_) + multiplicació pel master
config_.volume. S'extreu effectiveVolume(volume, channel_enabled) privat
i els dos setters es limiten a la crida Ja::*.

Any canvi futur a la política (p.ex. una corba logarítmica) queda en un
sol lloc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 12:01:06 +02:00

141 lines
7.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <cmath> // Para std::lround
#include <cstdint> // Para int8_t, uint8_t
#include <memory> // Para std::unique_ptr
#include <string> // Para string
#include <utility> // Para move
// Forward-declares per no incloure core/audio/jail_audio.hpp al header (conté
// l'engine complet de streaming amb stb_vorbis).
namespace Ja {
struct Music;
struct Sound;
} // namespace Ja
// --- Clase Audio: gestor de audio (singleton) ---
// Port del subsistema d'àudio del projecte ../aee, desacoblat d'Options:
// la configuració 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ó.
//
// 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:
// --- Configuració 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, // 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)
// --- Singleton ---
static void init(const Config& config); // Inicialitza amb la configuració rebuda
static void destroy(); // Libera el objeto Audio
static auto get() -> Audio*; // Obtiene el puntero al objeto Audio
~Audio(); // Destructor (públic per a std::unique_ptr)
Audio(const Audio&) = delete; // Evitar copia
Audio(Audio&&) = delete;
auto operator=(const Audio&) -> Audio& = delete; // Evitar asignación
auto operator=(Audio&&) -> Audio& = delete;
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(Ja::Music* 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(Ja::Sound* 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.
// No són constexpr perquè std::lround no ho és en C++20; s'usen en runtime.
static auto toPercent(float volume) -> int {
return static_cast<int>(std::lround(volume * 100.0F));
}
static auto fromPercent(int percent) -> float {
return static_cast<float>(percent) / 100.0F;
}
// --- Configuración general ---
void enable(bool value); // Establecer estado general (reaplica volums)
void toggleEnabled() { enable(!enabled_); } // Alternar estado general (reaplica volums)
void applySettings(const Config& config); // Aplica una nova configuració
// --- Configuración de sonidos ---
void enableSound() { enableSound(true); } // Habilitar sonidos
void disableSound() { enableSound(false); } // Deshabilitar sonidos
void enableSound(bool value); // Establecer estado de sonidos (reaplica volum)
void toggleSound() { enableSound(!sound_enabled_); } // Alternar estado de sonidos (reaplica volum)
// --- Configuración de música ---
void enableMusic() { enableMusic(true); } // Habilitar música
void disableMusic() { enableMusic(false); } // Deshabilitar música
void enableMusic(bool value); // Establecer estado de música (reaplica volum)
void toggleMusic() { enableMusic(!music_enabled_); } // Alternar estado de música (reaplica volum)
// --- 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 ---
explicit Audio(const Config& config); // Constructor privat: rep la config
void initSDLAudio(); // Inicializa 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 miembro ---
static std::unique_ptr<Audio> instance; // Instància única d'Audio
Config config_{}; // Configuració injectada (volums, enables)
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
};