1
+ // audio_file.cpp
1
2
#include " audio_file.h"
2
3
3
4
#include < algorithm>
4
5
#include < cstring>
5
6
#include < fstream>
6
-
7
7
#include < vorbis/vorbisfile.h>
8
8
9
9
namespace ste {
@@ -18,10 +18,10 @@ struct WAVHeader {
18
18
char fmt[4 ]; // "fmt "
19
19
uint32_t fmtSize; // Format chunk size
20
20
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
23
23
uint32_t byteRate; // Bytes per second
24
- uint16_t blockAlign; // Bytes per sample * m_channels
24
+ uint16_t blockAlign; // Bytes per sample * channels
25
25
uint16_t bitsPerSample; // Bits per sample
26
26
};
27
27
#pragma pack(pop)
@@ -33,21 +33,42 @@ bool fileExists(const std::string &path) {
33
33
}
34
34
} // namespace
35
35
36
- AudioFile::AudioFile (const std::string &path) : m_filename(path) {
36
+ std::optional<AudioFile> AudioFile::createFromFile (const std::string &path,
37
+ CreateInfo &createInfo) {
37
38
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;
39
42
}
40
43
44
+ std::vector<float > samples;
45
+ uint32_t sampleRate;
46
+ uint32_t channels;
47
+ bool success = false ;
48
+
41
49
std::string ext = getFileExtension (path);
42
50
if (ext == " wav" ) {
43
- loadWAV (path);
51
+ success = loadWAV (path, samples, sampleRate, channels, createInfo );
44
52
} else if (ext == " ogg" ) {
45
- loadOGG (path);
53
+ success = loadOGG (path, samples, sampleRate, channels, createInfo );
46
54
} else {
47
- throw AudioFileException (" Unsupported file format: " + ext);
55
+ createInfo.success = false ;
56
+ createInfo.errorMsg = " Unsupported file format: " + ext;
57
+ return std::nullopt;
48
58
}
59
+
60
+ if (!success) {
61
+ return std::nullopt;
62
+ }
63
+
64
+ return AudioFile (path, std::move (samples), sampleRate, channels);
49
65
}
50
66
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
+
51
72
AudioFile::~AudioFile () = default ;
52
73
53
74
AudioFile::AudioFile (AudioFile &&other) noexcept
@@ -66,10 +87,14 @@ AudioFile &AudioFile::operator=(AudioFile &&other) noexcept {
66
87
return *this ;
67
88
}
68
89
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) {
70
93
std::ifstream file (path, std::ios::binary);
71
94
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 ;
73
98
}
74
99
75
100
// Read and validate header
@@ -79,15 +104,21 @@ void AudioFile::loadWAV(const std::string &path) {
79
104
if (std::strncmp (header.riff , " RIFF" , 4 ) != 0 ||
80
105
std::strncmp (header.wave , " WAVE" , 4 ) != 0 ||
81
106
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 ;
83
110
}
84
111
85
112
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 ;
87
116
}
88
117
89
118
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 ;
91
122
}
92
123
93
124
// Find data chunk
@@ -106,23 +137,35 @@ void AudioFile::loadWAV(const std::string &path) {
106
137
file.read (reinterpret_cast <char *>(pcmData.data ()), chunkSize);
107
138
108
139
// Store audio properties
109
- m_sampleRate = header.m_sampleRate ;
110
- m_channels = header.numChannels ;
140
+ sampleRate = header.sampleRate ;
141
+ channels = header.numChannels ;
111
142
112
- // Convert to float m_samples
113
- convertToFloat (pcmData);
143
+ // Convert to float samples
144
+ convertToFloat (pcmData, samples);
145
+ return true ;
114
146
}
115
147
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) {
117
151
OggVorbis_File vf;
118
152
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 ;
120
156
}
121
157
122
158
// Get file info
123
159
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 );
126
169
127
170
// Read all PCM data
128
171
std::vector<int16_t > pcmData;
@@ -132,25 +175,34 @@ void AudioFile::loadOGG(const std::string &path) {
132
175
133
176
while ((bytesRead = ov_read (&vf, buffer, sizeof (buffer), 0 , 2 , 1 ,
134
177
¤tSection)) > 0 ) {
135
- size_t m_samplesRead = bytesRead / sizeof (int16_t );
178
+ size_t samplesRead = bytesRead / sizeof (int16_t );
136
179
size_t currentSize = pcmData.size ();
137
- pcmData.resize (currentSize + m_samplesRead );
180
+ pcmData.resize (currentSize + samplesRead );
138
181
std::memcpy (pcmData.data () + currentSize, buffer, bytesRead);
139
182
}
140
183
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
+
141
191
ov_clear (&vf);
142
192
143
- // Convert to float m_samples
144
- convertToFloat (pcmData);
193
+ // Convert to float samples
194
+ convertToFloat (pcmData, samples);
195
+ return true ;
145
196
}
146
197
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 ());
149
201
const float scale = 1 .0f / 32768 .0f ; // Scale factor for 16-bit audio
150
202
151
- // Convert m_samples from int16 to float
203
+ // Convert samples from int16 to float
152
204
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;
154
206
}
155
207
}
156
208
@@ -164,4 +216,4 @@ std::string AudioFile::getFileExtension(const std::string &path) {
164
216
return " " ;
165
217
}
166
218
167
- }; // namespace ste
219
+ } // namespace ste
0 commit comments