Skip to content

Commit fea3a0c

Browse files
committed
- vorbis support
1 parent a5c2363 commit fea3a0c

2 files changed

Lines changed: 5641 additions & 20 deletions

File tree

core/put/source/audio/audio_fmod.cpp

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#define DR_MP3_IMPLEMENTATION
1818
#include "dr_libs/dr_mp3.h"
19+
#include "stb/stb_vorbis.c"
1920

2021
#include <thread>
2122
#include <mutex>
@@ -128,14 +129,19 @@ namespace
128129
enum class audio_file_type
129130
{
130131
unknown,
131-
mp3
132+
mp3,
133+
ogg
132134
};
133135

134136
audio_file_type detect_audio_type(const u8* header, u32 header_size)
135137
{
136138
if (header_size < 4)
137139
return audio_file_type::unknown;
138140

141+
// Check for Ogg container (OggS magic)
142+
if (header[0] == 'O' && header[1] == 'g' && header[2] == 'g' && header[3] == 'S')
143+
return audio_file_type::ogg;
144+
139145
// Check for ID3 tag (ID3v2 at start of file)
140146
if (header[0] == 'I' && header[1] == 'D' && header[2] == '3')
141147
return audio_file_type::mp3;
@@ -192,38 +198,60 @@ namespace
192198
// Detect file type from header
193199
audio_file_type file_type = detect_audio_type((const u8*)file_buf, file_size);
194200

195-
if (file_type != audio_file_type::mp3)
201+
if (file_type == audio_file_type::unknown)
196202
{
197203
pen::memory_free(file_buf);
198204
_waveform_data[resource_slot].state = e_waveform_state::error;
199205
continue;
200206
}
201207

202-
// Initialize dr_mp3 decoder from memory
203-
drmp3 mp3;
204-
if (!drmp3_init_memory(&mp3, file_buf, file_size, nullptr))
208+
// Initialize decoder and get metadata
209+
drmp3 mp3 = {};
210+
stb_vorbis* vorbis = nullptr;
211+
u64 total_frames = 0;
212+
u32 num_channels = 0;
213+
u32 sample_rate = 0;
214+
215+
if (file_type == audio_file_type::mp3)
205216
{
206-
pen::memory_free(file_buf);
207-
_waveform_data[resource_slot].state = e_waveform_state::error;
208-
continue;
217+
if (!drmp3_init_memory(&mp3, file_buf, file_size, nullptr))
218+
{
219+
pen::memory_free(file_buf);
220+
_waveform_data[resource_slot].state = e_waveform_state::error;
221+
continue;
222+
}
223+
total_frames = drmp3_get_pcm_frame_count(&mp3);
224+
num_channels = mp3.channels;
225+
sample_rate = mp3.sampleRate;
226+
}
227+
else if (file_type == audio_file_type::ogg)
228+
{
229+
int vorbis_error = 0;
230+
vorbis = stb_vorbis_open_memory((const unsigned char*)file_buf, file_size, &vorbis_error, nullptr);
231+
if (!vorbis)
232+
{
233+
pen::memory_free(file_buf);
234+
_waveform_data[resource_slot].state = e_waveform_state::error;
235+
continue;
236+
}
237+
stb_vorbis_info info = stb_vorbis_get_info(vorbis);
238+
total_frames = stb_vorbis_stream_length_in_samples(vorbis);
239+
num_channels = info.channels;
240+
sample_rate = info.sample_rate;
209241
}
210242

211-
// Get total frame count for calculating bucket sizes
212-
drmp3_uint64 total_frames = drmp3_get_pcm_frame_count(&mp3);
213-
if (total_frames == 0)
243+
if (total_frames == 0 || num_channels == 0)
214244
{
215-
drmp3_uninit(&mp3);
245+
if (file_type == audio_file_type::mp3) drmp3_uninit(&mp3);
246+
if (vorbis) stb_vorbis_close(vorbis);
216247
pen::memory_free(file_buf);
217248
_waveform_data[resource_slot].state = e_waveform_state::error;
218249
continue;
219250
}
220251

221-
u32 num_channels = mp3.channels;
222-
u32 sample_rate = mp3.sampleRate;
223252
u32 length_ms = (u32)((total_frames * 1000) / sample_rate);
224253

225254
// Allocate local bucket storage (min/max pairs)
226-
// Keep local until complete to avoid races with cleanup
227255
f32* buckets = (f32*)pen::memory_alloc(resolution * 2 * sizeof(f32));
228256

229257
// Initialize buckets
@@ -234,15 +262,15 @@ namespace
234262
}
235263

236264
// Calculate frames per bucket
237-
drmp3_uint64 frames_per_bucket = total_frames / resolution;
265+
u64 frames_per_bucket = total_frames / resolution;
238266
if (frames_per_bucket == 0) frames_per_bucket = 1;
239267

240268
// Decode in chunks
241269
constexpr u32 chunk_frames = 4096;
242270
f32* chunk_buffer = (f32*)pen::memory_alloc(chunk_frames * num_channels * sizeof(f32));
243271

244272
u32 current_bucket = 0;
245-
drmp3_uint64 frames_in_current_bucket = 0;
273+
u64 frames_in_current_bucket = 0;
246274
f32 bucket_min = 1.0f;
247275
f32 bucket_max = -1.0f;
248276
f32 inv_num_channels = 1.0f / (f32)num_channels;
@@ -262,13 +290,21 @@ namespace
262290
}
263291

264292
// Read a chunk of PCM frames
265-
drmp3_uint64 frames_read = drmp3_read_pcm_frames_f32(&mp3, chunk_frames, chunk_buffer);
293+
u32 frames_read = 0;
294+
if (file_type == audio_file_type::mp3)
295+
{
296+
frames_read = (u32)drmp3_read_pcm_frames_f32(&mp3, chunk_frames, chunk_buffer);
297+
}
298+
else if (file_type == audio_file_type::ogg)
299+
{
300+
frames_read = stb_vorbis_get_samples_float_interleaved(vorbis, num_channels, chunk_buffer, chunk_frames * num_channels) ;
301+
}
266302

267303
if (frames_read == 0)
268304
break; // End of file
269305

270306
// Process the chunk into buckets
271-
for (drmp3_uint64 frame = 0; frame < frames_read; frame += sample_stride)
307+
for (u32 frame = 0; frame < frames_read; frame += sample_stride)
272308
{
273309
// Average channels for this sample
274310
f32 sample_value = 0.0f;
@@ -308,7 +344,8 @@ namespace
308344

309345
// Clean up decode resources
310346
pen::memory_free(chunk_buffer);
311-
drmp3_uninit(&mp3);
347+
if (file_type == audio_file_type::mp3) drmp3_uninit(&mp3);
348+
if (vorbis) stb_vorbis_close(vorbis);
312349
pen::memory_free(file_buf);
313350

314351
// Final cancel check before exposing buckets

0 commit comments

Comments
 (0)