Skip to content

Commit ce65fa8

Browse files
committed
🔨 Move audio asset loading to AssetManager, update audio engine APIs accordingly
1 parent 760cad4 commit ce65fa8

9 files changed

+183
-94
lines changed

Diff for: src/engine/assets/asset_manager.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ AssetHandle<T> AssetManager::load(const std::string &path) {
7777
m_totalAssets--;
7878
throw std::runtime_error(createInfo.errorMsg);
7979
}
80+
// Load AudioFile
81+
} else if constexpr (std::is_same_v<T, AudioFile>) {
82+
AudioFile::CreateInfo createInfo;
83+
if (auto audioFile = AudioFile::createFromFile(path, createInfo)) {
84+
auto asset = std::make_shared<AudioFile>(std::move(*audioFile));
85+
m_assets.try_emplace(path, asset, 1);
86+
m_loadedAssets++;
87+
return AssetHandle<T>(asset);
88+
} else {
89+
m_totalAssets--;
90+
throw std::runtime_error(createInfo.errorMsg);
91+
}
8092
} else {
8193
// Asset type-specific loading logic here
8294
throw std::runtime_error("Unsupported asset type");
@@ -143,4 +155,11 @@ AssetManager::loadAsync<Texture>(const std::string &);
143155
template bool AssetManager::exists<Texture>(const std::string &) const;
144156
template void AssetManager::remove<Texture>(const std::string &);
145157

158+
template AssetHandle<AudioFile>
159+
AssetManager::load<AudioFile>(const std::string &);
160+
template std::future<AssetHandle<AudioFile>>
161+
AssetManager::loadAsync<AudioFile>(const std::string &);
162+
template bool AssetManager::exists<AudioFile>(const std::string &) const;
163+
template void AssetManager::remove<AudioFile>(const std::string &);
164+
146165
} // namespace ste

Diff for: src/engine/assets/asset_manager.h

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <vector>
1212

1313
#include "engine/async/thread_pool.h"
14+
#include "engine/audio/audio_file.h"
1415
#include "engine/rendering/shader.h"
1516
#include "engine/rendering/texture.h"
1617

Diff for: src/engine/audio/audio_engine.cpp

+27-27
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,11 @@ void AudioChannel::mix(float *buffer, size_t frames) {
7979
m_position = static_cast<size_t>(readPosition);
8080
}
8181

82-
void AudioChannel::play(std::shared_ptr<AudioFile> file, float vol) {
83-
m_currentFile = std::move(file);
82+
void AudioChannel::play(AudioFile *file, float vol) {
83+
if (!file)
84+
return;
85+
86+
m_currentFile = file;
8487
m_position = 0;
8588
m_volume = vol;
8689
m_targetVolume = vol;
@@ -90,7 +93,7 @@ void AudioChannel::play(std::shared_ptr<AudioFile> file, float vol) {
9093

9194
void AudioChannel::stop() {
9295
m_active = false;
93-
m_currentFile.reset();
96+
m_currentFile = nullptr;
9497
m_position = 0;
9598
}
9699

@@ -217,37 +220,34 @@ AudioEngine::~AudioEngine() {
217220
stopAll();
218221
}
219222

220-
void AudioEngine::playSound(const std::string &path, float m_volume) {
221-
try {
222-
auto file = std::make_shared<AudioFile>(path);
223-
int channel = findFreeChannel();
224-
if (channel != -1) {
225-
m_commandQueue.pushPlay(file, m_volume, channel);
226-
}
227-
} catch (const AudioFileException &e) {
228-
std::cerr << "Failed to load sound file: " << e.what() << std::endl;
229-
// Handle or propagate error
230-
// Could log error or throw depending on your error handling strategy
223+
void AudioEngine::playSound(AssetHandle<AudioFile> sound, float volume) {
224+
if (!sound.isValid()) {
225+
std::cerr << "Attempted to play invalid sound asset" << std::endl;
226+
return;
227+
}
228+
229+
int channel = findFreeChannel();
230+
if (channel != -1) {
231+
m_commandQueue.pushPlay(sound.operator->(), volume, channel);
231232
}
232233
}
233234

234-
void AudioEngine::playMusic(const std::string &path, bool loop) {
235-
try {
236-
auto file = std::make_shared<AudioFile>(path);
237-
file->setLooping(loop);
235+
void AudioEngine::playMusic(AssetHandle<AudioFile> music, bool loop) {
236+
if (!music.isValid()) {
237+
std::cerr << "Attempted to play invalid music asset" << std::endl;
238+
return;
239+
}
238240

239-
// Stop any currently playing music
240-
stopChannel(0);
241+
// Set looping state on the audio file
242+
music->setLooping(loop);
241243

242-
// Queue the new music
243-
m_commandQueue.pushPlay(file, 1.0f, 0); // Channel 0 reserved for music
244-
} catch (const AudioFileException &e) {
245-
std::cerr << "Failed to load sound file: " << e.what() << std::endl;
244+
// Stop any currently playing music
245+
stopChannel(0);
246246

247-
// Handle or propagate error
248-
}
247+
// Queue the new music
248+
m_commandQueue.pushPlay(music.operator->(), 1.0f,
249+
0); // Channel 0 reserved for music
249250
}
250-
251251
void AudioEngine::stopChannel(int channelId) {
252252
if (channelId >= 0 && channelId < static_cast<int>(MAX_CHANNELS)) {
253253
m_commandQueue.pushStop(channelId);

Diff for: src/engine/audio/audio_engine.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "audio_file.h"
99
#include "audio_queue.h"
10+
#include "engine/assets/asset_manager.h"
1011

1112
namespace ste {
1213

@@ -18,7 +19,7 @@ class AudioChannel {
1819
// Core audio functions
1920
void update(float deltaTime);
2021
void mix(float *buffer, size_t frames);
21-
void play(std::shared_ptr<AudioFile> file, float vol = 1.0f);
22+
void play(AudioFile *file, float vol = 1.0f);
2223
void stop();
2324

2425
// State control
@@ -36,7 +37,7 @@ class AudioChannel {
3637

3738
private:
3839
// Audio data
39-
std::shared_ptr<AudioFile> m_currentFile;
40+
AudioFile *m_currentFile = nullptr;
4041
size_t m_position = 0;
4142

4243
// Volume control
@@ -76,8 +77,8 @@ class AudioEngine {
7677
AudioEngine &operator=(AudioEngine &&) = delete;
7778

7879
// Main interface
79-
void playSound(const std::string &path, float volume = 1.0f);
80-
void playMusic(const std::string &path, bool loop = true);
80+
void playSound(AssetHandle<AudioFile> sound, float volume = 1.0f);
81+
void playMusic(AssetHandle<AudioFile> music, bool loop = true);
8182
void stopChannel(int channelId);
8283
void stopAll();
8384
void setChannelVolume(int channelId, float volume);

Diff for: src/engine/audio/audio_file.cpp

+83-31
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
// audio_file.cpp
12
#include "audio_file.h"
23

34
#include <algorithm>
45
#include <cstring>
56
#include <fstream>
6-
77
#include <vorbis/vorbisfile.h>
88

99
namespace ste {
@@ -18,10 +18,10 @@ struct WAVHeader {
1818
char fmt[4]; // "fmt "
1919
uint32_t fmtSize; // Format chunk size
2020
uint16_t audioFormat; // Audio format (1 = PCM)
21-
uint16_t numChannels; // Number of m_channels
22-
uint32_t m_sampleRate; // Sample rate
21+
uint16_t numChannels; // Number of channels
22+
uint32_t sampleRate; // Sample rate
2323
uint32_t byteRate; // Bytes per second
24-
uint16_t blockAlign; // Bytes per sample * m_channels
24+
uint16_t blockAlign; // Bytes per sample * channels
2525
uint16_t bitsPerSample; // Bits per sample
2626
};
2727
#pragma pack(pop)
@@ -33,21 +33,42 @@ bool fileExists(const std::string &path) {
3333
}
3434
} // namespace
3535

36-
AudioFile::AudioFile(const std::string &path) : m_filename(path) {
36+
std::optional<AudioFile> AudioFile::createFromFile(const std::string &path,
37+
CreateInfo &createInfo) {
3738
if (!fileExists(path)) {
38-
throw AudioFileException("File not found: " + path);
39+
createInfo.success = false;
40+
createInfo.errorMsg = "File not found: " + path;
41+
return std::nullopt;
3942
}
4043

44+
std::vector<float> samples;
45+
uint32_t sampleRate;
46+
uint32_t channels;
47+
bool success = false;
48+
4149
std::string ext = getFileExtension(path);
4250
if (ext == "wav") {
43-
loadWAV(path);
51+
success = loadWAV(path, samples, sampleRate, channels, createInfo);
4452
} else if (ext == "ogg") {
45-
loadOGG(path);
53+
success = loadOGG(path, samples, sampleRate, channels, createInfo);
4654
} else {
47-
throw AudioFileException("Unsupported file format: " + ext);
55+
createInfo.success = false;
56+
createInfo.errorMsg = "Unsupported file format: " + ext;
57+
return std::nullopt;
4858
}
59+
60+
if (!success) {
61+
return std::nullopt;
62+
}
63+
64+
return AudioFile(path, std::move(samples), sampleRate, channels);
4965
}
5066

67+
AudioFile::AudioFile(const std::string &filename, std::vector<float> &&samples,
68+
uint32_t sampleRate, uint32_t channels)
69+
: m_samples(std::move(samples)), m_filename(filename),
70+
m_sampleRate(sampleRate), m_channels(channels) {}
71+
5172
AudioFile::~AudioFile() = default;
5273

5374
AudioFile::AudioFile(AudioFile &&other) noexcept
@@ -66,10 +87,14 @@ AudioFile &AudioFile::operator=(AudioFile &&other) noexcept {
6687
return *this;
6788
}
6889

69-
void AudioFile::loadWAV(const std::string &path) {
90+
bool AudioFile::loadWAV(const std::string &path, std::vector<float> &samples,
91+
uint32_t &sampleRate, uint32_t &channels,
92+
CreateInfo &createInfo) {
7093
std::ifstream file(path, std::ios::binary);
7194
if (!file) {
72-
throw AudioFileException("Failed to open WAV file: " + path);
95+
createInfo.success = false;
96+
createInfo.errorMsg = "Failed to open WAV file: " + path;
97+
return false;
7398
}
7499

75100
// Read and validate header
@@ -79,15 +104,21 @@ void AudioFile::loadWAV(const std::string &path) {
79104
if (std::strncmp(header.riff, "RIFF", 4) != 0 ||
80105
std::strncmp(header.wave, "WAVE", 4) != 0 ||
81106
std::strncmp(header.fmt, "fmt ", 4) != 0) {
82-
throw AudioFileException("Invalid WAV file format");
107+
createInfo.success = false;
108+
createInfo.errorMsg = "Invalid WAV file format";
109+
return false;
83110
}
84111

85112
if (header.audioFormat != 1) { // PCM = 1
86-
throw AudioFileException("Unsupported WAV format: non-PCM");
113+
createInfo.success = false;
114+
createInfo.errorMsg = "Unsupported WAV format: non-PCM";
115+
return false;
87116
}
88117

89118
if (header.bitsPerSample != 16) {
90-
throw AudioFileException("Unsupported WAV format: not 16-bit");
119+
createInfo.success = false;
120+
createInfo.errorMsg = "Unsupported WAV format: not 16-bit";
121+
return false;
91122
}
92123

93124
// Find data chunk
@@ -106,23 +137,35 @@ void AudioFile::loadWAV(const std::string &path) {
106137
file.read(reinterpret_cast<char *>(pcmData.data()), chunkSize);
107138

108139
// Store audio properties
109-
m_sampleRate = header.m_sampleRate;
110-
m_channels = header.numChannels;
140+
sampleRate = header.sampleRate;
141+
channels = header.numChannels;
111142

112-
// Convert to float m_samples
113-
convertToFloat(pcmData);
143+
// Convert to float samples
144+
convertToFloat(pcmData, samples);
145+
return true;
114146
}
115147

116-
void AudioFile::loadOGG(const std::string &path) {
148+
bool AudioFile::loadOGG(const std::string &path, std::vector<float> &samples,
149+
uint32_t &sampleRate, uint32_t &channels,
150+
CreateInfo &createInfo) {
117151
OggVorbis_File vf;
118152
if (ov_fopen(path.c_str(), &vf) != 0) {
119-
throw AudioFileException("Failed to open OGG file: " + path);
153+
createInfo.success = false;
154+
createInfo.errorMsg = "Failed to open OGG file: " + path;
155+
return false;
120156
}
121157

122158
// Get file info
123159
vorbis_info *vi = ov_info(&vf, -1);
124-
m_sampleRate = static_cast<uint32_t>(vi->rate);
125-
m_channels = static_cast<uint32_t>(vi->channels);
160+
if (!vi) {
161+
createInfo.success = false;
162+
createInfo.errorMsg = "Failed to get OGG file info";
163+
ov_clear(&vf);
164+
return false;
165+
}
166+
167+
sampleRate = static_cast<uint32_t>(vi->rate);
168+
channels = static_cast<uint32_t>(vi->channels);
126169

127170
// Read all PCM data
128171
std::vector<int16_t> pcmData;
@@ -132,25 +175,34 @@ void AudioFile::loadOGG(const std::string &path) {
132175

133176
while ((bytesRead = ov_read(&vf, buffer, sizeof(buffer), 0, 2, 1,
134177
&currentSection)) > 0) {
135-
size_t m_samplesRead = bytesRead / sizeof(int16_t);
178+
size_t samplesRead = bytesRead / sizeof(int16_t);
136179
size_t currentSize = pcmData.size();
137-
pcmData.resize(currentSize + m_samplesRead);
180+
pcmData.resize(currentSize + samplesRead);
138181
std::memcpy(pcmData.data() + currentSize, buffer, bytesRead);
139182
}
140183

184+
if (bytesRead < 0) {
185+
createInfo.success = false;
186+
createInfo.errorMsg = "Error reading OGG file data";
187+
ov_clear(&vf);
188+
return false;
189+
}
190+
141191
ov_clear(&vf);
142192

143-
// Convert to float m_samples
144-
convertToFloat(pcmData);
193+
// Convert to float samples
194+
convertToFloat(pcmData, samples);
195+
return true;
145196
}
146197

147-
void AudioFile::convertToFloat(const std::vector<int16_t> &pcmData) {
148-
m_samples.resize(pcmData.size());
198+
void AudioFile::convertToFloat(const std::vector<int16_t> &pcmData,
199+
std::vector<float> &samples) {
200+
samples.resize(pcmData.size());
149201
const float scale = 1.0f / 32768.0f; // Scale factor for 16-bit audio
150202

151-
// Convert m_samples from int16 to float
203+
// Convert samples from int16 to float
152204
for (size_t i = 0; i < pcmData.size(); ++i) {
153-
m_samples[i] = static_cast<float>(pcmData[i]) * scale;
205+
samples[i] = static_cast<float>(pcmData[i]) * scale;
154206
}
155207
}
156208

@@ -164,4 +216,4 @@ std::string AudioFile::getFileExtension(const std::string &path) {
164216
return "";
165217
}
166218

167-
}; // namespace ste
219+
} // namespace ste

0 commit comments

Comments
 (0)