mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Replace process-spawning audio with miniaudio for non-blocking playback
Eliminates severe stuttering from fork/exec + disk I/O by streaming audio directly from memory using miniaudio library.
This commit is contained in:
parent
c047446fb7
commit
bd3f1921d1
11 changed files with 96445 additions and 133 deletions
89
include/audio/audio_engine.hpp
Normal file
89
include/audio/audio_engine.hpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
// Forward declare miniaudio types to avoid exposing implementation in header
|
||||
struct ma_engine;
|
||||
struct ma_sound;
|
||||
|
||||
namespace wowee {
|
||||
namespace audio {
|
||||
|
||||
/**
|
||||
* AudioEngine: Singleton managing miniaudio device and playback.
|
||||
* Replaces process-spawning audio system with proper non-blocking library.
|
||||
*/
|
||||
class AudioEngine {
|
||||
public:
|
||||
static AudioEngine& instance();
|
||||
|
||||
~AudioEngine();
|
||||
|
||||
// Initialization
|
||||
bool initialize();
|
||||
void shutdown();
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
// Master volume (0.0 = silent, 1.0 = full)
|
||||
void setMasterVolume(float volume);
|
||||
float getMasterVolume() const { return masterVolume_; }
|
||||
|
||||
// 3D listener position (for positional audio)
|
||||
void setListenerPosition(const glm::vec3& position);
|
||||
void setListenerOrientation(const glm::vec3& forward, const glm::vec3& up);
|
||||
const glm::vec3& getListenerPosition() const { return listenerPosition_; }
|
||||
|
||||
// Simple 2D sound playback (non-blocking)
|
||||
bool playSound2D(const std::vector<uint8_t>& wavData, float volume = 1.0f, float pitch = 1.0f);
|
||||
bool playSound2D(const std::string& mpqPath, float volume = 1.0f, float pitch = 1.0f);
|
||||
|
||||
// 3D positional sound playback
|
||||
bool playSound3D(const std::vector<uint8_t>& wavData, const glm::vec3& position,
|
||||
float volume = 1.0f, float pitch = 1.0f, float maxDistance = 100.0f);
|
||||
bool playSound3D(const std::string& mpqPath, const glm::vec3& position,
|
||||
float volume = 1.0f, float pitch = 1.0f, float maxDistance = 100.0f);
|
||||
|
||||
// Music streaming (for background music)
|
||||
bool playMusic(const std::vector<uint8_t>& musicData, float volume = 1.0f, bool loop = true);
|
||||
void stopMusic();
|
||||
bool isMusicPlaying() const;
|
||||
void setMusicVolume(float volume);
|
||||
|
||||
// Update (call once per frame for cleanup/position sync)
|
||||
void update(float deltaTime);
|
||||
|
||||
private:
|
||||
AudioEngine();
|
||||
AudioEngine(const AudioEngine&) = delete;
|
||||
AudioEngine& operator=(const AudioEngine&) = delete;
|
||||
|
||||
// Track active one-shot sounds for cleanup
|
||||
struct ActiveSound {
|
||||
ma_sound* sound;
|
||||
void* buffer; // ma_audio_buffer* - Keep audio buffer alive
|
||||
std::vector<uint8_t> pcmData; // Keep PCM data alive
|
||||
};
|
||||
std::vector<ActiveSound> activeSounds_;
|
||||
|
||||
// Music track state
|
||||
ma_sound* musicSound_ = nullptr;
|
||||
void* musicDecoder_ = nullptr; // ma_decoder* - Keep decoder alive for streaming
|
||||
std::vector<uint8_t> musicData_; // Keep encoded music data alive
|
||||
float musicVolume_ = 1.0f;
|
||||
|
||||
bool initialized_ = false;
|
||||
float masterVolume_ = 1.0f;
|
||||
glm::vec3 listenerPosition_{0.0f, 0.0f, 0.0f};
|
||||
glm::vec3 listenerForward_{0.0f, 0.0f, -1.0f};
|
||||
glm::vec3 listenerUp_{0.0f, 1.0f, 0.0f};
|
||||
|
||||
// miniaudio engine (opaque pointer)
|
||||
ma_engine* engine_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace audio
|
||||
} // namespace wowee
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "platform/process.hpp"
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
|
@ -49,8 +48,6 @@ private:
|
|||
};
|
||||
|
||||
void preloadSurface(FootstepSurface surface, const std::vector<std::string>& candidates);
|
||||
void stopCurrentProcess();
|
||||
void reapFinishedProcess();
|
||||
bool playRandomStep(FootstepSurface surface, bool sprinting);
|
||||
static const char* surfaceName(FootstepSurface surface);
|
||||
|
||||
|
|
@ -58,8 +55,6 @@ private:
|
|||
SurfaceSamples surfaces[7];
|
||||
size_t sampleCount = 0;
|
||||
|
||||
std::string tempFilePath = platform::getTempFilePath("wowee_footstep.wav");
|
||||
ProcessHandle playerPid = INVALID_PROCESS;
|
||||
std::chrono::steady_clock::time_point lastPlayTime = std::chrono::steady_clock::time_point{};
|
||||
|
||||
std::mt19937 rng;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "platform/process.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace wowee {
|
||||
namespace pipeline { class AssetManager; }
|
||||
|
|
@ -30,13 +28,9 @@ public:
|
|||
const std::string& getCurrentTrack() const { return currentTrack; }
|
||||
|
||||
private:
|
||||
void stopCurrentProcess();
|
||||
|
||||
pipeline::AssetManager* assetManager = nullptr;
|
||||
std::string currentTrack;
|
||||
bool currentTrackIsFile = false;
|
||||
std::string tempFilePath;
|
||||
ProcessHandle playerPid = INVALID_PROCESS;
|
||||
bool playing = false;
|
||||
int volumePercent = 30;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue