Updated and fixed audio
This commit is contained in:
@ -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,19 +848,21 @@ 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();
|
||||||
|
if (!musicStarted && sys->getLoadedTrackCount() > 0) {
|
||||||
musicStarted = true;
|
musicStarted = true;
|
||||||
musicEnabled = true;
|
musicEnabled = true;
|
||||||
Settings::instance().setMusicEnabled(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)
|
||||||
if (e.key.scancode == SDL_SCANCODE_K)
|
if (e.key.scancode == SDL_SCANCODE_K)
|
||||||
{
|
{
|
||||||
@ -1322,11 +1325,15 @@ 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)) {
|
||||||
|
sys->shuffle();
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
currentTrackLoading = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == AppState::Playing)
|
if (state == AppState::Playing)
|
||||||
@ -1712,23 +1719,29 @@ void TetrisApp::Impl::runLoop()
|
|||||||
currentLoadingFile.clear();
|
currentLoadingFile.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio::instance().init();
|
if (auto sys = AudioManager::get()) {
|
||||||
|
sys->init();
|
||||||
totalTracks = 0;
|
totalTracks = 0;
|
||||||
for (int i = 1; i <= 100; ++i) {
|
for (int i = 1; i <= 100; ++i) {
|
||||||
char base[128];
|
char base[128];
|
||||||
std::snprintf(base, sizeof(base), "assets/music/music%03d", i);
|
std::snprintf(base, sizeof(base), "assets/music/music%03d", i);
|
||||||
std::string path = AssetPath::resolveWithExtensions(base, { ".mp3" });
|
std::string path = AssetPath::resolveWithExtensions(base, { ".mp3" });
|
||||||
if (path.empty()) break;
|
if (path.empty()) break;
|
||||||
Audio::instance().addTrackAsync(path);
|
sys->addTrackAsync(path);
|
||||||
totalTracks++;
|
totalTracks++;
|
||||||
}
|
}
|
||||||
totalLoadingTasks.store(baseTasks + totalTracks);
|
totalLoadingTasks.store(baseTasks + totalTracks);
|
||||||
if (totalTracks > 0) {
|
if (totalTracks > 0) {
|
||||||
Audio::instance().startBackgroundLoading();
|
sys->startBackgroundLoading();
|
||||||
musicLoadingStarted = true;
|
musicLoadingStarted = true;
|
||||||
} else {
|
} else {
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
totalTracks = 0;
|
||||||
|
totalLoadingTasks.store(baseTasks + totalTracks);
|
||||||
|
musicLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
pixelFont.init(AssetPath::resolveWithBase(Assets::FONT_ORBITRON), 22);
|
pixelFont.init(AssetPath::resolveWithBase(Assets::FONT_ORBITRON), 22);
|
||||||
loadedTasks.fetch_add(1);
|
loadedTasks.fetch_add(1);
|
||||||
@ -1879,9 +1892,10 @@ 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()) {
|
||||||
|
if (sys->isLoadingComplete()) {
|
||||||
musicProgress = 0.7;
|
musicProgress = 0.7;
|
||||||
} else if (Audio::instance().getLoadedTrackCount() > 0) {
|
} else if (sys->getLoadedTrackCount() > 0) {
|
||||||
musicProgress = 0.35;
|
musicProgress = 0.35;
|
||||||
} else {
|
} else {
|
||||||
Uint32 elapsedMs = SDL_GetTicks() - static_cast<Uint32>(loadStart);
|
Uint32 elapsedMs = SDL_GetTicks() - static_cast<Uint32>(loadStart);
|
||||||
@ -1892,6 +1906,15 @@ void TetrisApp::Impl::runLoop()
|
|||||||
musicProgress = 0.0;
|
musicProgress = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Uint32 elapsedMs = SDL_GetTicks() - static_cast<Uint32>(loadStart);
|
||||||
|
if (elapsedMs > 1500) {
|
||||||
|
musicProgress = 0.7;
|
||||||
|
musicLoaded = true;
|
||||||
|
} else {
|
||||||
|
musicProgress = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
double timeProgress = std::min(0.1, (now - loadStart) / 500.0);
|
double timeProgress = std::min(0.1, (now - loadStart) / 500.0);
|
||||||
loadingProgress = std::min(1.0, assetProgress + musicProgress + timeProgress);
|
loadingProgress = std::min(1.0, assetProgress + musicProgress + timeProgress);
|
||||||
@ -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.
|
||||||
|
|||||||
@ -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 (don’t 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)
|
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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?
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user