Audio fix

This commit is contained in:
2026-03-14 19:11:59 +01:00
parent 52df67da09
commit b19f595daf
6 changed files with 67 additions and 37 deletions

View File

@@ -15,7 +15,7 @@ namespace Game::Audio {
SDL_AudioDeviceID getAudioDevice() const { return mDevice; } SDL_AudioDeviceID getAudioDevice() const { return mDevice; }
private: private:
SDL_AudioSpec mAudioSpec; SDL_AudioSpec mAudioSpec{};
SDL_AudioDeviceID mDevice; SDL_AudioDeviceID mDevice = 0;
}; };
}; };

View File

@@ -32,6 +32,7 @@ namespace Game::Object {
Uint8* mAudioBuffer = nullptr; Uint8* mAudioBuffer = nullptr;
Uint32 mAudioLength = 0; Uint32 mAudioLength = 0;
SDL_AudioStream* mAudioStream = nullptr; SDL_AudioStream* mAudioStream = nullptr;
SDL_AudioSpec mSourceSpec{};
int mVolume; int mVolume;
}; };
} }

View File

@@ -10,6 +10,7 @@
#include <state/gamestate.hpp> #include <state/gamestate.hpp>
#include <game/gamemanager.hpp> #include <game/gamemanager.hpp>
#include <audio/audio.hpp> #include <audio/audio.hpp>
#include <chrono>
namespace Game::Window { namespace Game::Window {
class Window { class Window {
@@ -24,14 +25,19 @@ namespace Game::Window {
void setTargetFPS(int fps) { mTargetFPS = fps; } void setTargetFPS(int fps) { mTargetFPS = fps; }
int getTargetFPS() { return mTargetFPS; } int getTargetFPS() { return mTargetFPS; }
static SDL_Window* getSDLWindowBackend() { return sWindowBackend; }
Renderer::Renderer* getRenderer() { return &mRenderer; } Renderer::Renderer* getRenderer() { return &mRenderer; }
private: private:
static inline SDL_Window* sWindowBackend = nullptr;
SDL_Window* mWindow; SDL_Window* mWindow;
Renderer::Renderer mRenderer; Renderer::Renderer mRenderer;
Game::GameManager mGameManager; Game::GameManager mGameManager;
std::jthread mGameThread; std::jthread mGameThread;
bool mRunning; bool mRunning;
int mTargetFPS = 60; int mTargetFPS = 60;
size_t mFrameCount = 0;
std::chrono::steady_clock::time_point mLastFPSTime;
}; };
} }

View File

@@ -1,13 +1,20 @@
#include <game/agame/player.hpp> #include <game/agame/player.hpp>
#include <window/window.hpp>
#include <cmath>
namespace Game::AGame { namespace Game::AGame {
void Player::start() { void Player::start() {
mSound = Object::Sound("../resources/example.wav", Object::Format::WAV); mSound = Object::Sound("../resources/example.wav", Object::Format::WAV);
mSound.play(); mSound.play();
int w, h;
SDL_GetWindowSizeInPixels(Window::Window::getSDLWindowBackend(), &w, &h);
mTransform.x = 640.f - (mTex->getWidth() / 2.f * mTransform.scaleX); // Start in the middle of the screen mTransform.x = w / 2.f - (mTex->getWidth() / 2.f * mTransform.scaleX * 0.25f); // Start in the middle of the screen
mTransform.y = 360.f - (mTex->getHeight() / 2.f * mTransform.scaleY); mTransform.y = h / 2.f - (mTex->getHeight() / 2.f * mTransform.scaleY * 0.25f);
mTransform.rotation = 0.f; mTransform.rotation = 0.f;
LOG("W: " << w << " H: " << h);
} }
void Player::update(float deltaTime) { void Player::update(float deltaTime) {
@@ -18,6 +25,6 @@ namespace Game::AGame {
//LOG(mName << " position: " << mTransform.x << ' ' << mTransform.y); //LOG(mName << " position: " << mTransform.x << ' ' << mTransform.y);
//LOG("DeltaTime: " << deltaTime); //LOG("DeltaTime: " << deltaTime);
mTransform.scaleX = 1.f + 1.f * std::sin(RUNNING_TIME() / 0.5f); // Pulsate scale for testing mTransform.scaleX = 1.f + 1.f * std::sin(RUNNING_TIME() / 0.5f); // Pulsate scale for testing
//mTransform.scaleY = 1.f + 1.f * std::sin(SDL_GetTicks() / 500.f); mTransform.scaleY = 1.f + 0.5f * std::cos(RUNNING_TIME() / 0.5f); // Pulsate scale for testing
} }
} }

View File

@@ -1,37 +1,25 @@
#include <object/sound.hpp> #include <object/sound.hpp>
namespace Game::Object { namespace Game::Object {
namespace {
static SDL_AudioSpec makeFloatStereo44100() {
SDL_AudioSpec spec{};
spec.freq = 44100;
spec.channels = 2;
spec.format = SDL_AUDIO_F32;
return spec;
}
}
Sound::Sound(std::string path, Format format, int volume) Sound::Sound(std::string path, Format format, int volume)
: mAudioBuffer(nullptr), mAudioLength(0), mAudioStream(nullptr), mVolume(volume) { : mAudioBuffer(nullptr), mAudioLength(0), mAudioStream(nullptr), mSourceSpec{}, mVolume(volume) {
if (format == Format::WAV) { if (format == Format::WAV) {
SDL_AudioSpec wavSpec = makeFloatStereo44100(); if (!SDL_LoadWAV(path.c_str(), &mSourceSpec, &mAudioBuffer, &mAudioLength)) {
if (!SDL_LoadWAV(path.c_str(), &wavSpec, &mAudioBuffer, &mAudioLength)) {
ERROR("Failed to load WAV file: " << SDL_GetError()); ERROR("Failed to load WAV file: " << SDL_GetError());
return; return;
} }
LOG("WAV file loaded successfully"); LOG("WAV file loaded successfully");
SDL_AudioSpec spec = makeFloatStereo44100();
mAudioStream = SDL_OpenAudioDeviceStream( mAudioStream = SDL_OpenAudioDeviceStream(
Audio::Audio::getInstance().getAudioDevice(), &spec, nullptr, nullptr Audio::Audio::getInstance().getAudioDevice(), &mSourceSpec, nullptr, nullptr
); );
if (!mAudioStream) { if (!mAudioStream) {
ERROR("Failed to create audio stream: " << SDL_GetError()); ERROR("Failed to create audio stream: " << SDL_GetError());
SDL_free(mAudioBuffer); SDL_free(mAudioBuffer);
mAudioBuffer = nullptr; mAudioBuffer = nullptr;
mAudioLength = 0; mAudioLength = 0;
mSourceSpec = {};
} }
} else { } else {
ERROR("Unsupported audio format"); ERROR("Unsupported audio format");
@@ -39,7 +27,7 @@ namespace Game::Object {
} }
Sound::Sound(const Sound& other) Sound::Sound(const Sound& other)
: mAudioBuffer(nullptr), mAudioLength(0), mAudioStream(nullptr), mVolume(other.mVolume) { : mAudioBuffer(nullptr), mAudioLength(0), mAudioStream(nullptr), mSourceSpec(other.mSourceSpec), mVolume(other.mVolume) {
if (&other == this) return; if (&other == this) return;
if (other.mAudioBuffer && other.mAudioLength > 0) { if (other.mAudioBuffer && other.mAudioLength > 0) {
@@ -53,9 +41,8 @@ namespace Game::Object {
mAudioLength = other.mAudioLength; mAudioLength = other.mAudioLength;
} }
SDL_AudioSpec wavSpec = makeFloatStereo44100();
mAudioStream = SDL_OpenAudioDeviceStream( mAudioStream = SDL_OpenAudioDeviceStream(
Audio::Audio::getInstance().getAudioDevice(), &wavSpec, nullptr, nullptr Audio::Audio::getInstance().getAudioDevice(), &mSourceSpec, nullptr, nullptr
); );
if (!mAudioStream) { if (!mAudioStream) {
ERROR("Failed to create audio stream for copied Sound: " << SDL_GetError()); ERROR("Failed to create audio stream for copied Sound: " << SDL_GetError());
@@ -78,10 +65,8 @@ namespace Game::Object {
newLength = other.mAudioLength; newLength = other.mAudioLength;
} }
SDL_AudioStream* newStream = nullptr; SDL_AudioStream* newStream = SDL_OpenAudioDeviceStream(
SDL_AudioSpec wavSpec = makeFloatStereo44100(); Audio::Audio::getInstance().getAudioDevice(), &other.mSourceSpec, nullptr, nullptr
newStream = SDL_OpenAudioDeviceStream(
Audio::Audio::getInstance().getAudioDevice(), &wavSpec, nullptr, nullptr
); );
if (!newStream) { if (!newStream) {
ERROR("Failed to create audio stream for copied Sound: " << SDL_GetError()); ERROR("Failed to create audio stream for copied Sound: " << SDL_GetError());
@@ -95,20 +80,23 @@ namespace Game::Object {
mAudioBuffer = newBuffer; mAudioBuffer = newBuffer;
mAudioLength = newLength; mAudioLength = newLength;
mAudioStream = newStream; mAudioStream = newStream;
mSourceSpec = other.mSourceSpec;
mVolume = other.mVolume; mVolume = other.mVolume;
return *this; return *this;
} }
Sound::Sound(Sound&& other) Sound::Sound(Sound&& other)
: mAudioBuffer(other.mAudioBuffer), : mAudioBuffer(other.mAudioBuffer),
mAudioLength(other.mAudioLength), mAudioLength(other.mAudioLength),
mAudioStream(other.mAudioStream), mAudioStream(other.mAudioStream),
mVolume(other.mVolume) { mSourceSpec(other.mSourceSpec),
other.mAudioBuffer = nullptr; mVolume(other.mVolume) {
other.mAudioLength = 0; other.mAudioBuffer = nullptr;
other.mAudioStream = nullptr; other.mAudioLength = 0;
} other.mAudioStream = nullptr;
other.mSourceSpec = {};
}
Sound& Sound::operator=(Sound&& other) { Sound& Sound::operator=(Sound&& other) {
if (this != &other) { if (this != &other) {
@@ -118,11 +106,13 @@ namespace Game::Object {
mAudioBuffer = other.mAudioBuffer; mAudioBuffer = other.mAudioBuffer;
mAudioLength = other.mAudioLength; mAudioLength = other.mAudioLength;
mAudioStream = other.mAudioStream; mAudioStream = other.mAudioStream;
mSourceSpec = other.mSourceSpec;
mVolume = other.mVolume; mVolume = other.mVolume;
other.mAudioBuffer = nullptr; other.mAudioBuffer = nullptr;
other.mAudioLength = 0; other.mAudioLength = 0;
other.mAudioStream = nullptr; other.mAudioStream = nullptr;
other.mSourceSpec = {};
} }
return *this; return *this;
} }
@@ -142,8 +132,20 @@ namespace Game::Object {
void Sound::play() { void Sound::play() {
if (mAudioStream && mAudioBuffer && mAudioLength > 0) { if (mAudioStream && mAudioBuffer && mAudioLength > 0) {
SDL_ClearAudioStream(mAudioStream);
if (!SDL_PutAudioStreamData(mAudioStream, mAudioBuffer, mAudioLength)) { if (!SDL_PutAudioStreamData(mAudioStream, mAudioBuffer, mAudioLength)) {
ERROR("Failed to queue audio data: " << SDL_GetError()); ERROR("Failed to queue audio data: " << SDL_GetError());
return;
}
if (!SDL_FlushAudioStream(mAudioStream)) {
ERROR("Failed to flush audio stream: " << SDL_GetError());
return;
}
if (!SDL_ResumeAudioStreamDevice(mAudioStream)) {
ERROR("Failed to resume audio stream device: " << SDL_GetError());
} }
} }
} }

View File

@@ -16,6 +16,7 @@ namespace Game::Window {
if (mWindow) { if (mWindow) {
SDL_DestroyWindow(mWindow); SDL_DestroyWindow(mWindow);
mWindow = nullptr; mWindow = nullptr;
sWindowBackend = nullptr;
LOG("Window destroyed successfully"); LOG("Window destroyed successfully");
} }
SDL_Quit(); SDL_Quit();
@@ -41,12 +42,14 @@ namespace Game::Window {
SDL_Quit(); SDL_Quit();
return false; return false;
} }
sWindowBackend = mWindow;
LOG("Window created successfully"); LOG("Window created successfully");
if (!mRenderer.init(mWindow)) { if (!mRenderer.init(mWindow)) {
SDL_DestroyWindow(mWindow); SDL_DestroyWindow(mWindow);
mWindow = nullptr; mWindow = nullptr;
sWindowBackend = nullptr;
SDL_Quit(); SDL_Quit();
return false; return false;
} }
@@ -77,6 +80,17 @@ namespace Game::Window {
mRenderer.renderFrame(); mRenderer.renderFrame();
SDL_Delay(1000 / mTargetFPS); // Delay to cap the frame rate to the target FPS SDL_Delay(1000 / mTargetFPS); // Delay to cap the frame rate to the target FPS
// Set the window title to show the current FPS for testing
mFrameCount++;
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - mLastFPSTime).count();
if (elapsed >= 1) {
int fps = static_cast<int>(mFrameCount / elapsed);
SDL_SetWindowTitle(mWindow, ("Game Window - FPS: " + std::to_string(fps)).c_str());
mFrameCount = 0;
mLastFPSTime = now;
}
} }
} }
} }