Updated and fixed audio

This commit is contained in:
2025-12-25 19:41:19 +01:00
parent 68b35ea57b
commit 735e966608
8 changed files with 75 additions and 52 deletions

View File

@ -31,6 +31,7 @@
#include "audio/Audio.h" #include "audio/Audio.h"
#include "audio/MenuWrappers.h" #include "audio/MenuWrappers.h"
#include "audio/SoundEffect.h" #include "audio/SoundEffect.h"
#include "audio/AudioManager.h"
#include "core/Config.h" #include "core/Config.h"
#include "core/Settings.h" #include "core/Settings.h"
@ -847,17 +848,19 @@ void TetrisApp::Impl::runLoop()
if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) { if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) {
if (e.key.scancode == SDL_SCANCODE_M) if (e.key.scancode == SDL_SCANCODE_M)
{ {
Audio::instance().toggleMute(); if (auto sys = AudioManager::get()) sys->toggleMute();
musicEnabled = !musicEnabled; musicEnabled = !musicEnabled;
Settings::instance().setMusicEnabled(musicEnabled); Settings::instance().setMusicEnabled(musicEnabled);
} }
if (e.key.scancode == SDL_SCANCODE_N) if (e.key.scancode == SDL_SCANCODE_N)
{ {
Audio::instance().skipToNextTrack(); if (auto sys = AudioManager::get()) {
if (!musicStarted && Audio::instance().getLoadedTrackCount() > 0) { sys->skipToNextTrack();
musicStarted = true; if (!musicStarted && sys->getLoadedTrackCount() > 0) {
musicEnabled = true; musicStarted = true;
Settings::instance().setMusicEnabled(true); musicEnabled = true;
Settings::instance().setMusicEnabled(true);
}
} }
} }
// K: Toggle sound effects (S is reserved for co-op movement) // K: Toggle sound effects (S is reserved for co-op movement)
@ -1322,10 +1325,14 @@ void TetrisApp::Impl::runLoop()
game->softDropBoost(frameMs); game->softDropBoost(frameMs);
if (musicLoadingStarted && !musicLoaded) { if (musicLoadingStarted && !musicLoaded) {
currentTrackLoading = Audio::instance().getLoadedTrackCount(); if (auto sys = AudioManager::get()) {
if (Audio::instance().isLoadingComplete() || (totalTracks > 0 && currentTrackLoading >= totalTracks)) { currentTrackLoading = sys->getLoadedTrackCount();
Audio::instance().shuffle(); if (sys->isLoadingComplete() || (totalTracks > 0 && currentTrackLoading >= totalTracks)) {
musicLoaded = true; sys->shuffle();
musicLoaded = true;
}
} else {
currentTrackLoading = 0;
} }
} }
@ -1712,21 +1719,27 @@ void TetrisApp::Impl::runLoop()
currentLoadingFile.clear(); currentLoadingFile.clear();
} }
Audio::instance().init(); if (auto sys = AudioManager::get()) {
totalTracks = 0; sys->init();
for (int i = 1; i <= 100; ++i) { totalTracks = 0;
char base[128]; for (int i = 1; i <= 100; ++i) {
std::snprintf(base, sizeof(base), "assets/music/music%03d", i); char base[128];
std::string path = AssetPath::resolveWithExtensions(base, { ".mp3" }); std::snprintf(base, sizeof(base), "assets/music/music%03d", i);
if (path.empty()) break; std::string path = AssetPath::resolveWithExtensions(base, { ".mp3" });
Audio::instance().addTrackAsync(path); if (path.empty()) break;
totalTracks++; sys->addTrackAsync(path);
} totalTracks++;
totalLoadingTasks.store(baseTasks + totalTracks); }
if (totalTracks > 0) { totalLoadingTasks.store(baseTasks + totalTracks);
Audio::instance().startBackgroundLoading(); if (totalTracks > 0) {
musicLoadingStarted = true; sys->startBackgroundLoading();
musicLoadingStarted = true;
} else {
musicLoaded = true;
}
} else { } else {
totalTracks = 0;
totalLoadingTasks.store(baseTasks + totalTracks);
musicLoaded = true; musicLoaded = true;
} }
@ -1879,10 +1892,20 @@ void TetrisApp::Impl::runLoop()
if (totalTracks > 0) { if (totalTracks > 0) {
musicProgress = musicLoaded ? 0.7 : std::min(0.7, (double)currentTrackLoading / totalTracks * 0.7); musicProgress = musicLoaded ? 0.7 : std::min(0.7, (double)currentTrackLoading / totalTracks * 0.7);
} else { } else {
if (Audio::instance().isLoadingComplete()) { if (auto sys = AudioManager::get()) {
musicProgress = 0.7; if (sys->isLoadingComplete()) {
} else if (Audio::instance().getLoadedTrackCount() > 0) { musicProgress = 0.7;
musicProgress = 0.35; } else if (sys->getLoadedTrackCount() > 0) {
musicProgress = 0.35;
} else {
Uint32 elapsedMs = SDL_GetTicks() - static_cast<Uint32>(loadStart);
if (elapsedMs > 1500) {
musicProgress = 0.7;
musicLoaded = true;
} else {
musicProgress = 0.0;
}
}
} else { } else {
Uint32 elapsedMs = SDL_GetTicks() - static_cast<Uint32>(loadStart); Uint32 elapsedMs = SDL_GetTicks() - static_cast<Uint32>(loadStart);
if (elapsedMs > 1500) { if (elapsedMs > 1500) {
@ -1924,7 +1947,7 @@ void TetrisApp::Impl::runLoop()
menuTrackLoader = std::jthread([]() { menuTrackLoader = std::jthread([]() {
std::string menuTrack = AssetPath::resolveWithExtensions("assets/music/Every Block You Take", { ".mp3" }); std::string menuTrack = AssetPath::resolveWithExtensions("assets/music/Every Block You Take", { ".mp3" });
if (!menuTrack.empty()) { if (!menuTrack.empty()) {
Audio::instance().setMenuTrack(menuTrack); if (auto sys = AudioManager::get()) sys->setMenuTrack(menuTrack);
} else { } else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Menu track not found (Every Block You Take)"); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Menu track not found (Every Block You Take)");
} }
@ -1933,9 +1956,9 @@ void TetrisApp::Impl::runLoop()
} }
if (state == AppState::Menu) { if (state == AppState::Menu) {
Audio::instance().playMenuMusic(); if (auto sys = AudioManager::get()) sys->playMenuMusic();
} else { } else {
Audio::instance().playGameMusic(); if (auto sys = AudioManager::get()) sys->playGameMusic();
} }
musicStarted = true; musicStarted = true;
} }
@ -1944,9 +1967,9 @@ void TetrisApp::Impl::runLoop()
static AppState previousState = AppState::Loading; static AppState previousState = AppState::Loading;
if (state != previousState && musicStarted) { if (state != previousState && musicStarted) {
if (state == AppState::Menu && previousState == AppState::Playing) { if (state == AppState::Menu && previousState == AppState::Playing) {
Audio::instance().playMenuMusic(); if (auto sys = AudioManager::get()) sys->playMenuMusic();
} else if (state == AppState::Playing && previousState == AppState::Menu) { } else if (state == AppState::Playing && previousState == AppState::Menu) {
Audio::instance().playGameMusic(); if (auto sys = AudioManager::get()) sys->playGameMusic();
} }
} }
previousState = state; previousState = state;
@ -2720,7 +2743,7 @@ void TetrisApp::Impl::shutdown()
} }
lineEffect.shutdown(); lineEffect.shutdown();
Audio::instance().shutdown(); if (auto sys = AudioManager::get()) sys->shutdown();
SoundEffectManager::instance().shutdown(); SoundEffectManager::instance().shutdown();
// Destroy textures before tearing down the renderer/window. // Destroy textures before tearing down the renderer/window.

View File

@ -268,7 +268,7 @@ void ApplicationManager::shutdown() {
m_running = false; m_running = false;
// Stop audio systems before tearing down SDL to avoid aborts/asserts // Stop audio systems before tearing down SDL to avoid aborts/asserts
if (auto sys = ::AudioManager::get()) sys->shutdown(); if (auto sys = AudioManager::get()) sys->shutdown();
SoundEffectManager::instance().shutdown(); SoundEffectManager::instance().shutdown();
// Cleanup in reverse order of initialization // Cleanup in reverse order of initialization
@ -382,11 +382,11 @@ bool ApplicationManager::initializeManagers() {
// M: Toggle/mute music; start playback if unmuting and not started yet // M: Toggle/mute music; start playback if unmuting and not started yet
if (!consume && sc == SDL_SCANCODE_M) { if (!consume && sc == SDL_SCANCODE_M) {
if (auto sys = ::AudioManager::get()) sys->toggleMute(); if (auto sys = AudioManager::get()) sys->toggleMute();
m_musicEnabled = !m_musicEnabled; m_musicEnabled = !m_musicEnabled;
if (m_musicEnabled && !m_musicStarted && ::AudioManager::get() && ::AudioManager::get()->getLoadedTrackCount() > 0) { if (m_musicEnabled && !m_musicStarted && AudioManager::get() && AudioManager::get()->getLoadedTrackCount() > 0) {
::AudioManager::get()->shuffle(); AudioManager::get()->shuffle();
::AudioManager::get()->start(); AudioManager::get()->start();
m_musicStarted = true; m_musicStarted = true;
} }
consume = true; consume = true;
@ -394,7 +394,7 @@ bool ApplicationManager::initializeManagers() {
// N: Skip to next song in the playlist (or restart menu track) // N: Skip to next song in the playlist (or restart menu track)
if (!consume && sc == SDL_SCANCODE_N) { if (!consume && sc == SDL_SCANCODE_N) {
if (auto sys = ::AudioManager::get()) { sys->skipToNextTrack(); if (!m_musicStarted && sys->getLoadedTrackCount() > 0) { m_musicStarted = true; m_musicEnabled = true; } } if (auto sys = AudioManager::get()) { sys->skipToNextTrack(); if (!m_musicStarted && sys->getLoadedTrackCount() > 0) { m_musicStarted = true; m_musicEnabled = true; } }
consume = true; consume = true;
} }
@ -615,7 +615,7 @@ bool ApplicationManager::initializeGame() {
// as lambdas that reference members here. // as lambdas that reference members here.
// Start background music loading similar to main.cpp: Audio init + file discovery // Start background music loading similar to main.cpp: Audio init + file discovery
if (auto sys = ::AudioManager::get()) sys->init(); if (auto sys = AudioManager::get()) sys->init();
// Discover available tracks (up to 100) and queue for background loading // Discover available tracks (up to 100) and queue for background loading
m_totalTracks = 0; m_totalTracks = 0;
std::vector<std::string> trackPaths; std::vector<std::string> trackPaths;
@ -631,14 +631,14 @@ bool ApplicationManager::initializeGame() {
} }
m_totalTracks = static_cast<int>(trackPaths.size()); m_totalTracks = static_cast<int>(trackPaths.size());
for (const auto& path : trackPaths) { for (const auto& path : trackPaths) {
if (auto sys = ::AudioManager::get()) sys->addTrackAsync(path); if (auto sys = AudioManager::get()) sys->addTrackAsync(path);
} }
if (m_totalTracks > 0) { if (m_totalTracks > 0) {
if (auto sys = ::AudioManager::get()) sys->startBackgroundLoading(); if (auto sys = AudioManager::get()) sys->startBackgroundLoading();
// Kick off playback now; Audio will pick a track once decoded. // Kick off playback now; Audio will pick a track once decoded.
// Do not mark as started yet; we'll flip the flag once a track is actually loaded. // Do not mark as started yet; we'll flip the flag once a track is actually loaded.
if (m_musicEnabled) { if (m_musicEnabled) {
if (auto sys = ::AudioManager::get()) { sys->shuffle(); sys->start(); } if (auto sys = AudioManager::get()) { sys->shuffle(); sys->start(); }
m_musicStarted = true; m_musicStarted = true;
} }
m_currentTrackLoading = 1; // mark started m_currentTrackLoading = 1; // mark started
@ -938,13 +938,13 @@ void ApplicationManager::setupStateHandlers() {
// Start music as soon as at least one track has decoded (dont wait for all) // Start music as soon as at least one track has decoded (dont wait for all)
// Start music as soon as at least one track has decoded (don't wait for all) // Start music as soon as at least one track has decoded (don't wait for all)
if (m_musicEnabled && !m_musicStarted) { if (m_musicEnabled && !m_musicStarted) {
if (auto sys = ::AudioManager::get()) { if (auto sys = AudioManager::get()) {
if (sys->getLoadedTrackCount() > 0) { sys->shuffle(); sys->start(); m_musicStarted = true; } if (sys->getLoadedTrackCount() > 0) { sys->shuffle(); sys->start(); m_musicStarted = true; }
} }
} }
// Track completion status for UI // Track completion status for UI
if (!m_musicLoaded) { if (!m_musicLoaded) {
if (auto sys = ::AudioManager::get()) { if (auto sys = AudioManager::get()) {
if (sys->isLoadingComplete()) m_musicLoaded = true; if (sys->isLoadingComplete()) m_musicLoaded = true;
} }
} }

View File

@ -41,7 +41,7 @@ bool AssetManager::initialize(SDL_Renderer* renderer) {
m_renderer = renderer; m_renderer = renderer;
// Get references to singleton systems // Get references to singleton systems
m_audioSystem = ::AudioManager::get(); m_audioSystem = AudioManager::get();
m_soundSystem = &SoundEffectManager::instance(); m_soundSystem = &SoundEffectManager::instance();
m_initialized = true; m_initialized = true;

View File

@ -267,6 +267,6 @@ void LineEffect::playLineClearSound(int lineCount) {
const std::vector<int16_t>* sample = (lineCount == 4) ? &tetrisSample : &lineClearSample; const std::vector<int16_t>* sample = (lineCount == 4) ? &tetrisSample : &lineClearSample;
if (sample && !sample->empty()) { if (sample && !sample->empty()) {
// Mix via shared Audio device so it layers with music // Mix via shared Audio device so it layers with music
if (auto sys = ::AudioManager::get()) sys->playSfx(*sample, 2, 44100, (lineCount == 4) ? 0.9f : 0.7f); if (auto sys = AudioManager::get()) sys->playSfx(*sample, 2, 44100, (lineCount == 4) ? 0.9f : 0.7f);
} }
} }

View File

@ -462,7 +462,7 @@ void LineEffect::playLineClearSound(int lineCount) {
const std::vector<int16_t>* sample = (lineCount == 4) ? &tetrisSample : &lineClearSample; const std::vector<int16_t>* sample = (lineCount == 4) ? &tetrisSample : &lineClearSample;
if (sample && !sample->empty()) { if (sample && !sample->empty()) {
// Mix via shared Audio device so it layers with music // Mix via shared Audio device so it layers with music
if (auto sys = ::AudioManager::get()) sys->playSfx(*sample, 2, 44100, (lineCount == 4) ? 0.9f : 0.7f); if (auto sys = AudioManager::get()) sys->playSfx(*sample, 2, 44100, (lineCount == 4) ? 0.9f : 0.7f);
} }
} }

View File

@ -181,7 +181,7 @@ void MenuState::showCoopSetupPanel(bool show, bool resumeMusic) {
coopSetupStep = CoopSetupStep::ChoosePartner; coopSetupStep = CoopSetupStep::ChoosePartner;
// Resume menu music only when requested (ESC should pass resumeMusic=false) // Resume menu music only when requested (ESC should pass resumeMusic=false)
if (resumeMusic && ctx.musicEnabled && *ctx.musicEnabled) { if (resumeMusic && ctx.musicEnabled && *ctx.musicEnabled) {
if (auto sys = ::AudioManager::get()) sys->playMenuMusic(); if (auto sys = AudioManager::get()) sys->playMenuMusic();
} }
} }
} }

View File

@ -221,7 +221,7 @@ void OptionsState::toggleFullscreen() {
} }
void OptionsState::toggleMusic() { void OptionsState::toggleMusic() {
if (auto sys = ::AudioManager::get()) sys->toggleMute(); if (auto sys = AudioManager::get()) sys->toggleMute();
// If muted, music is disabled. If not muted, music is enabled. // If muted, music is disabled. If not muted, music is enabled.
// Note: Audio::instance().isMuted() returns true if muted. // Note: Audio::instance().isMuted() returns true if muted.
// But Audio class doesn't expose isMuted directly in header usually? // But Audio class doesn't expose isMuted directly in header usually?

View File

@ -105,7 +105,7 @@ void VideoState::startAudioIfReady() {
if (m_audioPcm.empty()) return; if (m_audioPcm.empty()) return;
// Use the existing audio output path (same device as music/SFX). // Use the existing audio output path (same device as music/SFX).
if (auto sys = ::AudioManager::get()) sys->playSfx(m_audioPcm, m_audioChannels, m_audioRate, 1.0f); if (auto sys = AudioManager::get()) sys->playSfx(m_audioPcm, m_audioChannels, m_audioRate, 1.0f);
m_audioStarted = true; m_audioStarted = true;
} }