neteja tidy a source/core/system i audio amb fixes d'arrel

This commit is contained in:
2026-05-14 21:02:43 +02:00
parent dc622c7bae
commit 0ee117135c
11 changed files with 145 additions and 115 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
// 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"
#include "external/stb_vorbis.h"
// 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
+3 -2
View File
@@ -1,5 +1,6 @@
#pragma once
#include <cmath> // Para lround
#include <cstdint> // Para int8_t, uint8_t
#include <string> // Para string
#include <utility> // Para move
@@ -59,8 +60,8 @@ class Audio {
// --- 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<int>((volume * 100.0F) + 0.5F);
static auto toPercent(float volume) -> int {
return static_cast<int>(std::lround(volume * 100.0F));
}
static constexpr auto fromPercent(int percent) -> float {
return static_cast<float>(percent) / 100.0F;
+85 -62
View File
@@ -12,7 +12,7 @@
#include <vector> // Para std::vector
#define STB_VORBIS_HEADER_ONLY
#include "external/stb_vorbis.c" // Para stb_vorbis_open_memory i streaming
#include "external/stb_vorbis.h" // Para stb_vorbis_open_memory i streaming
// Deleter stateless per a buffers reservats amb `SDL_malloc` / `SDL_LoadWAV*`.
// Compatible amb `std::unique_ptr<Uint8[], SDLFreeDeleter>` — zero size
@@ -26,14 +26,14 @@ struct SDLFreeDeleter {
};
// --- Public Enums ---
enum JA_Channel_state {
enum JA_Channel_state : std::uint8_t {
JA_CHANNEL_INVALID,
JA_CHANNEL_FREE,
JA_CHANNEL_PLAYING,
JA_CHANNEL_PAUSED,
JA_SOUND_DISABLED,
};
enum JA_Music_state {
enum JA_Music_state : std::uint8_t {
JA_MUSIC_INVALID,
JA_MUSIC_PLAYING,
JA_MUSIC_PAUSED,
@@ -42,7 +42,7 @@ enum JA_Music_state {
};
// --- Struct Definitions ---
enum {
enum : std::uint8_t {
JA_MAX_SIMULTANEOUS_CHANNELS = 20,
JA_MAX_GROUPS = 2
};
@@ -57,10 +57,10 @@ struct JA_Sound_t {
struct JA_Channel_t {
JA_Sound_t* sound{nullptr};
SDL_AudioStream* stream{nullptr};
int pos{0};
int times{0};
int group{0};
SDL_AudioStream* stream{nullptr};
JA_Channel_state state{JA_CHANNEL_FREE};
};
@@ -199,63 +199,86 @@ inline void JA_PreFillOutgoing(JA_Music_t* music, int duration_ms) {
// --- Core Functions ---
// Fade-out de la música sortint (crossfade o fade-out a silenci). En acabar
// destrueix l'AudioStream sortint.
inline void JA_UpdateOutgoingFade() {
if ((outgoing_music.stream == nullptr) || !outgoing_music.fade.active) {
return;
}
const Uint64 elapsed = SDL_GetTicks() - outgoing_music.fade.start_time;
if (elapsed >= static_cast<Uint64>(outgoing_music.fade.duration_ms)) {
SDL_DestroyAudioStream(outgoing_music.stream);
outgoing_music.stream = nullptr;
outgoing_music.fade.active = false;
return;
}
const float percent = static_cast<float>(elapsed) / static_cast<float>(outgoing_music.fade.duration_ms);
SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0F - percent));
}
// Fade-in de la música entrant (segona meitat d'un crossfade).
inline void JA_UpdateIncomingFade() {
if (!incoming_fade.active) {
return;
}
const Uint64 elapsed = SDL_GetTicks() - incoming_fade.start_time;
if (elapsed >= static_cast<Uint64>(incoming_fade.duration_ms)) {
incoming_fade.active = false;
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
return;
}
const float percent = static_cast<float>(elapsed) / static_cast<float>(incoming_fade.duration_ms);
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * percent);
}
// Manté l'stream de la música activa alimentat i para la reproducció si
// el vorbis s'ha esgotat i no queden loops.
inline void JA_UpdateCurrentMusic() {
if (!JA_musicEnabled || current_music == nullptr || current_music->state != JA_MUSIC_PLAYING) {
return;
}
JA_UpdateIncomingFade();
JA_PumpMusic(current_music);
if (current_music->times == 0 && SDL_GetAudioStreamAvailable(current_music->stream) == 0) {
JA_StopMusic();
}
}
// Avança l'estat d'un sol canal de so: alimenta més samples mentre quedin
// loops; si ja no queden i l'stream s'ha buidat, atura el canal.
inline void JA_UpdateSoundChannel(int channel_index) {
JA_Channel_t& ch = channels[channel_index];
if (ch.state != JA_CHANNEL_PLAYING) {
return;
}
if (ch.times == 0) {
if (SDL_GetAudioStreamAvailable(ch.stream) == 0) {
JA_StopChannel(channel_index);
}
return;
}
if (static_cast<Uint32>(SDL_GetAudioStreamAvailable(ch.stream)) < (ch.sound->length / 2)) {
SDL_PutAudioStreamData(ch.stream, ch.sound->buffer.get(), ch.sound->length);
if (ch.times > 0) {
ch.times--;
}
}
}
// Avança tots els canals de so actius.
inline void JA_UpdateSoundChannels() {
if (!JA_soundEnabled) {
return;
}
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) {
JA_UpdateSoundChannel(i);
}
}
inline void JA_Update() {
// --- Outgoing music fade-out (crossfade o fade-out a silencio) ---
if ((outgoing_music.stream != nullptr) && 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 != nullptr) && current_music->state == JA_MUSIC_PLAYING) {
// 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 {
float percent = (float)elapsed / (float)incoming_fade.duration_ms;
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * percent);
}
}
// Streaming: rellenem l'stream fins al low-water-mark i parem si el
// vorbis s'ha esgotat i no queden loops.
JA_PumpMusic(current_music);
if (current_music->times == 0 && SDL_GetAudioStreamAvailable(current_music->stream) == 0) {
JA_StopMusic();
}
}
// --- 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.get(), channels[i].sound->length);
if (channels[i].times > 0) {
channels[i].times--;
}
}
} else {
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) {
JA_StopChannel(i);
}
}
}
}
}
JA_UpdateOutgoingFade();
JA_UpdateCurrentMusic();
JA_UpdateSoundChannels();
}
inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) {
@@ -586,7 +609,7 @@ inline void JA_EnableMusic(const bool value) {
inline auto JA_LoadSound(uint8_t* buffer, uint32_t size) -> JA_Sound_t* {
auto sound = std::make_unique<JA_Sound_t>();
Uint8* raw = nullptr;
if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) {
if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), true, &sound->spec, &raw, &sound->length)) {
std::cout << "Failed to load WAV from memory: " << SDL_GetError() << '\n';
return nullptr;
}