88#include "al_audio_system.h"
99#include "data_win.h"
1010#include "utils.h"
11- #include "wave.h"
1211
1312#include <stdio.h>
1413#include <stdlib.h>
@@ -167,10 +166,25 @@ static void maInit(AudioSystem* audio, DataWin* dataWin, FileSystem* fileSystem)
167166 ma -> fileSystem = fileSystem ;
168167
169168 ma -> alDevice = alcOpenDevice (nullptr );
169+ if (ma -> alDevice == nullptr ) {
170+ fprintf (stderr , "Audio: Failed to open OpenAL device (error %d)\n" , alGetError ());
171+ return ;
172+ }
173+
170174 ma -> alContext = alcCreateContext (ma -> alDevice , nullptr );
171- alcMakeContextCurrent (ma -> alContext );
172- if (ma -> alDevice == nullptr || ma -> alContext == nullptr ) {
173- fprintf (stderr , "Audio: Failed to initialize OpenAL engine (error %d)\n" , alGetError ());
175+ if (ma -> alContext == nullptr ) {
176+ fprintf (stderr , "Audio: Failed to create OpenAL context (error %d)\n" , alGetError ());
177+ alcCloseDevice (ma -> alDevice );
178+ ma -> alDevice = nullptr ;
179+ return ;
180+ }
181+
182+ if (!alcMakeContextCurrent (ma -> alContext )) {
183+ fprintf (stderr , "Audio: Failed to make OpenAL context current (error %d)\n" , alGetError ());
184+ alcDestroyContext (ma -> alContext );
185+ alcCloseDevice (ma -> alDevice );
186+ ma -> alContext = nullptr ;
187+ ma -> alDevice = nullptr ;
174188 return ;
175189 }
176190
@@ -278,6 +292,28 @@ static void maUpdate(AudioSystem* audio, float deltaTime) {
278292 }
279293}
280294
295+ // Walk RIFF chunks in a WAV container to find the 'data' chunk payload offset and length.
296+ // Returns pointer to the first byte of audio data, or nullptr on failure.
297+ // audioDataLenOut receives the chunk's data length.
298+ static const uint8_t * findWavDataChunk (const uint8_t * data , uint32_t dataSize , uint32_t * audioDataLenOut ) {
299+ if (data == nullptr || dataSize < 12 ) return nullptr ;
300+ if (data [0 ] != 'R' || data [1 ] != 'I' || data [2 ] != 'F' || data [3 ] != 'F' ) return nullptr ;
301+ uint32_t offset = 12 ;
302+ while (offset + 8 <= dataSize ) {
303+ uint32_t chunkLen = data [offset + 4 ] | (data [offset + 5 ] << 8 ) | (data [offset + 6 ] << 16 ) | (data [offset + 7 ] << 24 );
304+ uint32_t chunkDataOffset = offset + 8 ;
305+ uint32_t available = dataSize - chunkDataOffset ;
306+ if (chunkLen > available ) chunkLen = available ;
307+ if (data [offset ] == 'd' && data [offset + 1 ] == 'a' && data [offset + 2 ] == 't' && data [offset + 3 ] == 'a' ) {
308+ * audioDataLenOut = chunkLen ;
309+ return data + chunkDataOffset ;
310+ }
311+ offset = chunkDataOffset + chunkLen ;
312+ if (offset & 1 ) offset ++ ;
313+ }
314+ return nullptr ;
315+ }
316+
281317static int32_t maPlaySound (AudioSystem * audio , int32_t soundIndex , int32_t priority , bool loop ) {
282318 AlAudioSystem * ma = (AlAudioSystem * ) audio ;
283319
@@ -338,6 +374,15 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior
338374
339375 alGenSources (1 , & slot -> alSource );
340376 alGenBuffers (AL_STREAM_BUFFER_COUNT , slot -> streamBuffers );
377+ if (alGetError () != AL_NO_ERROR ) {
378+ fprintf (stderr , "Audio: alGenSources/alGenBuffers failed for stream\n" );
379+ stb_vorbis_close (v );
380+ free (slot -> decodeScratch );
381+ slot -> streaming = false;
382+ slot -> vorbis = nullptr ;
383+ slot -> decodeScratch = nullptr ;
384+ return -1 ;
385+ }
341386
342387 int primed = 0 ;
343388 for (int i = 0 ; AL_STREAM_BUFFER_COUNT > i ; i ++ ) {
@@ -360,6 +405,10 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior
360405 } else {
361406 alGenSources (1 , & slot -> alSource );
362407 alGenBuffers (1 , & slot -> alBuffer );
408+ if (alGetError () != AL_NO_ERROR ) {
409+ fprintf (stderr , "Audio: alGenSources/alGenBuffers failed for sound %d\n" , soundIndex );
410+ return -1 ;
411+ }
363412 bool isRegular = (sound -> flags & AUDIO_ENTRY_FLAG_REGULAR ) == AUDIO_ENTRY_FLAG_REGULAR ;
364413 bool isEmbedded = (sound -> flags & AUDIO_ENTRY_FLAG_IS_EMBEDDED ) != 0 ;
365414 bool isCompressed = (sound -> flags & AUDIO_ENTRY_FLAG_IS_COMPRESSED ) != 0 ;
@@ -373,31 +422,68 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior
373422 }
374423
375424 AudioEntry * entry = & ma -> base .audioGroups [sound -> audioGroup ]-> audo .entries [sound -> audioFile ];
376- WAVFile wav = WAV_ParseFileData (entry -> data );
425+
426+ uint32_t channels = 0 ;
427+ uint32_t sampleRate = 0 ;
428+ uint32_t bitsPerSample = 0 ;
429+ const uint8_t * audioData = nullptr ;
430+ uint32_t audioDataLen = 0 ;
431+ bool hasWavHeader = (entry -> dataSize >= 12 &&
432+ entry -> data [0 ] == 'R' && entry -> data [1 ] == 'I' &&
433+ entry -> data [2 ] == 'F' && entry -> data [3 ] == 'F' );
434+
435+ if (hasWavHeader ) {
436+ channels = entry -> data [22 ] | (entry -> data [23 ] << 8 );
437+ sampleRate = entry -> data [24 ] | (entry -> data [25 ] << 8 ) |
438+ (entry -> data [26 ] << 16 ) | (entry -> data [27 ] << 24 );
439+ bitsPerSample = entry -> data [34 ] | (entry -> data [35 ] << 8 );
440+ audioData = findWavDataChunk (entry -> data , entry -> dataSize , & audioDataLen );
441+ } else {
442+ channels = 2 ;
443+ sampleRate = 44100 ;
444+ bitsPerSample = 16 ;
445+ audioData = entry -> data ;
446+ audioDataLen = entry -> dataSize ;
447+ }
448+
449+ if (audioData == nullptr || audioDataLen == 0 ) {
450+ fprintf (stderr , "Audio: No audio data for '%s'\n" , sound -> name );
451+ return -1 ;
452+ }
453+ if (channels == 0 || sampleRate == 0 || bitsPerSample == 0 ) {
454+ fprintf (stderr , "Audio: Invalid audio params for '%s' ch=%u rate=%u bits=%u\n" ,
455+ sound -> name , channels , sampleRate , bitsPerSample );
456+ return -1 ;
457+ }
377458
378459 uint32_t format ;
379- if (wav . header . number_of_channels == 1 )
460+ if (channels == 1 )
380461 {
381- if (wav . header . bits_per_sample == 8 )
462+ if (bitsPerSample == 8 )
382463 format = AL_FORMAT_MONO8 ;
383464 else
384465 format = AL_FORMAT_MONO16 ;
385466 }
386467 else {
387- if (wav . header . bits_per_sample == 8 )
468+ if (bitsPerSample == 8 )
388469 format = AL_FORMAT_STEREO8 ;
389470 else
390471 format = AL_FORMAT_STEREO16 ;
391472 }
392473 alBufferData (
393474 slot -> alBuffer ,
394475 format ,
395- wav . data ,
396- wav . data_length ,
397- wav . header . sample_rate
476+ audioData ,
477+ audioDataLen ,
478+ sampleRate
398479 );
480+ ALenum alErr = alGetError ();
481+ if (alErr != AL_NO_ERROR ) {
482+ fprintf (stderr , "Audio: alBufferData failed for '%s' format=0x%x len=%u rate=%u err=%d\n" ,
483+ sound -> name , format , audioDataLen , sampleRate , alErr );
484+ return -1 ;
485+ }
399486 alSourcei (slot -> alSource , AL_BUFFER , slot -> alBuffer );
400- if (wav .data != NULL ) free (wav .data );
401487 } else {
402488 // External audio: load from file
403489 char * path = resolveExternalPath (ma , sound );
@@ -410,13 +496,24 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior
410496 int sample_rate ;
411497 short * data = NULL ;
412498 int len = stb_vorbis_decode_filename (path , & channels , & sample_rate , & data );
499+ if (len <= 0 || data == nullptr ) {
500+ fprintf (stderr , "Audio: stb_vorbis_decode failed for '%s' path='%s' len=%d\n" , sound -> name , path , len );
501+ free (path );
502+ return -1 ;
503+ }
413504 alBufferData (
414505 slot -> alBuffer ,
415506 (channels == 2 ) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16 ,
416507 (void * )data ,
417508 len * channels * sizeof (uint16_t ),
418509 sample_rate
419510 );
511+ if (alGetError () != AL_NO_ERROR ) {
512+ fprintf (stderr , "Audio: alBufferData failed for external '%s'\n" , sound -> name );
513+ free (data );
514+ free (path );
515+ return -1 ;
516+ }
420517 alSourcei (slot -> alSource , AL_BUFFER , slot -> alBuffer );
421518 if (data != NULL ) free (data );
422519 free (path );
@@ -451,6 +548,9 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior
451548 ma -> nextInstanceCounter ++ ;
452549
453550 alSourcePlay (slot -> alSource );
551+ if (alGetError () != AL_NO_ERROR ) {
552+ fprintf (stderr , "Audio: alSourcePlay failed for sound %d (stream=%d)\n" , soundIndex , isStream );
553+ }
454554
455555 return slot -> instanceId ;
456556}
@@ -774,11 +874,29 @@ static float maGetSoundLength(AudioSystem* audio, int32_t soundOrInstance) {
774874 if (inAudo ) {
775875 if (0 > sound -> audioFile || (uint32_t ) sound -> audioFile >= ma -> base .audioGroups [sound -> audioGroup ]-> audo .count ) return 0.0f ;
776876 AudioEntry * entry = & ma -> base .audioGroups [sound -> audioGroup ]-> audo .entries [sound -> audioFile ];
777- WAVFile wav = WAV_ParseFileData (entry -> data );
778- float seconds = 0.0f ;
779- if (wav .header .byte_rate > 0 ) seconds = (float ) wav .header .data_size / (float ) wav .header .byte_rate ;
780- if (wav .data != nullptr ) free (wav .data );
781- return seconds ;
877+
878+ bool hasWavHeader = (entry -> dataSize >= 12 &&
879+ entry -> data [0 ] == 'R' && entry -> data [1 ] == 'I' &&
880+ entry -> data [2 ] == 'F' && entry -> data [3 ] == 'F' );
881+
882+ if (hasWavHeader ) {
883+ uint32_t channels = entry -> data [22 ] | (entry -> data [23 ] << 8 );
884+ uint32_t sampleRate = entry -> data [24 ] | (entry -> data [25 ] << 8 ) |
885+ (entry -> data [26 ] << 16 ) | (entry -> data [27 ] << 24 );
886+ uint32_t bitsPerSample = entry -> data [34 ] | (entry -> data [35 ] << 8 );
887+ uint32_t audioDataLen = 0 ;
888+ findWavDataChunk (entry -> data , entry -> dataSize , & audioDataLen );
889+ if (channels > 0 && sampleRate > 0 && bitsPerSample > 0 && audioDataLen > 0 ) {
890+ uint32_t bytesPerSample = channels * (bitsPerSample / 8 );
891+ if (bytesPerSample > 0 )
892+ return (float ) audioDataLen / (float )(sampleRate * bytesPerSample );
893+ }
894+ } else {
895+ // Raw PCM: assume stereo 16-bit 44100 Hz
896+ uint32_t audioDataLen = entry -> dataSize ;
897+ return (float ) audioDataLen / (float )(44100 * 2 * 2 );
898+ }
899+ return 0.0f ;
782900 }
783901
784902 char * path = resolveExternalPath (ma , sound );
0 commit comments