diff --git a/src/Audio.c b/src/Audio.c index f3a14de..4ad4647 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -99,6 +99,7 @@ const i32 audio_init(AudioManager *audioManager) for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++) { alGenSources(1, &audioManager->sourceList[i].id); + AL_CHECK_ERROR(); // NOTE(doyle): If last entry, loop the free source to front of list if (i + 1 >= ARRAY_COUNT(audioManager->sourceList)) @@ -111,10 +112,24 @@ const i32 audio_init(AudioManager *audioManager) return 0; } +INTERNAL inline u32 getSourceId(AudioManager *audioManager, + AudioRenderer *audioRenderer) +{ + u32 result = audioManager->sourceList[audioRenderer->sourceIndex].id; + return result; +} + INTERNAL i32 rendererAcquire(AudioManager *audioManager, AudioRenderer *audioRenderer) { + i32 vacantSource = audioManager->freeSourceIndex; + +#ifdef DENGINE_DEBUG + ASSERT(audioManager && audioRenderer); + ASSERT(vacantSource >= 0); +#endif + if (audioManager->sourceList[vacantSource].nextFreeIndex == AUDIO_NO_FREE_SOURCE) { @@ -144,17 +159,35 @@ INTERNAL i32 rendererAcquire(AudioManager *audioManager, INTERNAL void rendererRelease(AudioManager *audioManager, AudioRenderer *audioRenderer) { - u32 sourceIndexToFree = audioRenderer->sourceIndex; + + u32 alSourceId = getSourceId(audioManager, audioRenderer); + + alSourceUnqueueBuffers(alSourceId, ARRAY_COUNT(audioRenderer->bufferId), + audioRenderer->bufferId); + AL_CHECK_ERROR(); + alDeleteBuffers(ARRAY_COUNT(audioRenderer->bufferId), + audioRenderer->bufferId); + AL_CHECK_ERROR(); + + for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++) + { + audioRenderer->bufferId[i] = 0; + } + + audioRenderer->audio = NULL; + audioRenderer->numPlays = 0; + + u32 sourceIndexToFree = audioRenderer->sourceIndex; + audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; audioManager->sourceList[sourceIndexToFree].nextFreeIndex = audioManager->freeSourceIndex; - audioManager->freeSourceIndex = sourceIndexToFree; - audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; + } #define AUDIO_CHUNK_SIZE_ 65536 -void audio_beginVorbisStream(AudioManager *audioManager, +void audio_streamPlayVorbis(AudioManager *audioManager, AudioRenderer *audioRenderer, AudioVorbis *vorbis, i32 numPlays) { @@ -162,14 +195,14 @@ void audio_beginVorbisStream(AudioManager *audioManager, ASSERT(audioManager && audioRenderer && vorbis); if (numPlays != AUDIO_REPEAT_INFINITE && numPlays <= 0) { - DEBUG_LOG("audio_beginVorbisStream() warning: Number of plays is less than 0"); + DEBUG_LOG("audio_streamPlayVorbis() warning: Number of plays is less than 0"); } #endif i32 result = rendererAcquire(audioManager, audioRenderer); if (result) { - DEBUG_LOG("audio_beginVorbisStream() failed: Could not acquire renderer"); + DEBUG_LOG("audio_streamPlayVorbis() failed: Could not acquire renderer"); return; } @@ -181,7 +214,7 @@ void audio_beginVorbisStream(AudioManager *audioManager, { #ifdef DENGINE_DEBUG DEBUG_LOG( - "audio_beginVorbisStream() warning: Unaccounted channel format"); + "audio_streamPlayVorbis() warning: Unaccounted channel format"); ASSERT(INVALID_CODE_PATH); #endif } @@ -190,17 +223,20 @@ void audio_beginVorbisStream(AudioManager *audioManager, audioRenderer->numPlays = numPlays; } +void audio_streamStopVorbis(AudioManager *audioManager, + AudioRenderer *audioRenderer) +{ + u32 alSourceId = getSourceId(audioManager, audioRenderer); + alSourceStop(alSourceId); + AL_CHECK_ERROR(); + rendererRelease(audioManager, audioRenderer); +} + void audio_updateAndPlay(AudioManager *audioManager, AudioRenderer *audioRenderer) { AudioVorbis *audio = audioRenderer->audio; - if (!audio) - { -#ifdef DENGINE_DEBUG - DEBUG_LOG("audio_updateAndPlay() early exit: No audio stream connected"); -#endif - return; - } + if (!audio) return; if (audioRenderer->numPlays != AUDIO_REPEAT_INFINITE && audioRenderer->numPlays <= 0) @@ -209,27 +245,29 @@ void audio_updateAndPlay(AudioManager *audioManager, return; } - u32 alSourceId = audioManager->sourceList[audioRenderer->sourceIndex].id; - + u32 alSourceId = getSourceId(audioManager, audioRenderer); ALint audioState; alGetSourcei(alSourceId, AL_SOURCE_STATE, &audioState); + AL_CHECK_ERROR(); if (audioState == AL_STOPPED || audioState == AL_INITIAL) { - // TODO(doyle): Delete and recreate fixes clicking when reusing buffers if (audioState == AL_STOPPED) { - if (audioRenderer->numPlays != AUDIO_REPEAT_INFINITE) audioRenderer->numPlays--; - alDeleteBuffers(ARRAY_COUNT(audioRenderer->bufferId), - audioRenderer->bufferId); - if (audioRenderer->numPlays == AUDIO_REPEAT_INFINITE || audioRenderer->numPlays > 0) { + // TODO(doyle): Delete and recreate fixes clicking when reusing + // buffers + alDeleteBuffers(ARRAY_COUNT(audioRenderer->bufferId), + audioRenderer->bufferId); + AL_CHECK_ERROR(); + alGenBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); + AL_CHECK_ERROR(); } else { @@ -251,23 +289,28 @@ void audio_updateAndPlay(AudioManager *audioManager, alBufferData(audioRenderer->bufferId[i], audioRenderer->format, audioChunk, AUDIO_CHUNK_SIZE_ * sizeof(i16), audio->info.sample_rate); + AL_CHECK_ERROR(); } alSourceQueueBuffers(alSourceId, ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); + AL_CHECK_ERROR(); alSourcePlay(alSourceId); + AL_CHECK_ERROR(); } else if (audioState == AL_PLAYING) { ALint numProcessedBuffers; alGetSourcei(alSourceId, AL_BUFFERS_PROCESSED, &numProcessedBuffers); + AL_CHECK_ERROR(); if (numProcessedBuffers > 0) { ALint numBuffersToUnqueue = 1; ALuint emptyBufferId; alSourceUnqueueBuffers(alSourceId, numBuffersToUnqueue, &emptyBufferId); + AL_CHECK_ERROR(); i16 audioChunk[AUDIO_CHUNK_SIZE_] = {0}; i32 sampleCount = stb_vorbis_get_samples_short_interleaved( @@ -280,7 +323,9 @@ void audio_updateAndPlay(AudioManager *audioManager, alBufferData(emptyBufferId, audioRenderer->format, audioChunk, sampleCount * audio->info.channels * sizeof(i16), audio->info.sample_rate); + AL_CHECK_ERROR(); alSourceQueueBuffers(alSourceId, 1, &emptyBufferId); + AL_CHECK_ERROR(); } } } diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index df08fd8..a7277d9 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -365,11 +365,13 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize) Entity *soundscape = addEntity(arena, world, pos, size, type, dir, tex, collides); + world->soundscape = soundscape; + soundscape->audio = PLATFORM_MEM_ALLOC(arena, 1, AudioRenderer); soundscape->audio->sourceIndex = AUDIO_SOURCE_UNASSIGNED; - audio_beginVorbisStream(&state->audioManager, soundscape->audio, - asset_getVorbis(assetManager, audiolist_battle), - AUDIO_REPEAT_INFINITE); + audio_streamPlayVorbis(&state->audioManager, soundscape->audio, + asset_getVorbis(assetManager, audiolist_battle), + AUDIO_REPEAT_INFINITE); /* Init hero entity */ world->heroIndex = world->freeEntityIndex; @@ -494,16 +496,34 @@ INTERNAL void parseInput(GameState *state, const f32 dt) } // TODO(doyle): Revisit key input with state checking for last ended down - if (state->keys[GLFW_KEY_SPACE]) + if (state->keys[GLFW_KEY_SPACE] && spaceBarWasDown == FALSE) { +#if 0 Renderer *renderer = &state->renderer; f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h); f32 xModifier = 5.0f - CAST(f32)(rand() % 3); v2 pos = V2(renderer->size.w - (renderer->size.w / xModifier), yPos); addGenericMob(&state->arena, &state->assetManager, world, pos); +#endif + if (world->soundscape->audio->sourceIndex == AUDIO_SOURCE_UNASSIGNED) + { + audio_streamPlayVorbis( + &state->audioManager, world->soundscape->audio, + asset_getVorbis(&state->assetManager, audiolist_battle), + AUDIO_REPEAT_INFINITE); + } + else + { + audio_streamStopVorbis(&state->audioManager, + world->soundscape->audio); + } spaceBarWasDown = TRUE; } + else if (!state->keys[GLFW_KEY_SPACE]) + { + spaceBarWasDown = FALSE; + } } // NOTE(doyle): Clipping threshold for snapping velocity to 0 diff --git a/src/include/Dengine/Audio.h b/src/include/Dengine/Audio.h index 4ba35f4..4b91b71 100644 --- a/src/include/Dengine/Audio.h +++ b/src/include/Dengine/Audio.h @@ -36,9 +36,11 @@ struct AudioRenderer typedef struct AudioRenderer AudioRenderer; const i32 audio_init(AudioManager *audioManager); -void audio_beginVorbisStream(AudioManager *audioManager, - AudioRenderer *audioRenderer, AudioVorbis *vorbis, - i32 numPlays); +void audio_streamPlayVorbis(AudioManager *audioManager, + AudioRenderer *audioRenderer, AudioVorbis *vorbis, + i32 numPlays); +void audio_streamStopVorbis(AudioManager *audioManager, + AudioRenderer *audioRenderer); void audio_updateAndPlay(AudioManager *audioManager, AudioRenderer *audioRenderer); #endif diff --git a/src/include/WorldTraveller/WorldTraveller.h b/src/include/WorldTraveller/WorldTraveller.h index 4c4ebf4..f808418 100644 --- a/src/include/WorldTraveller/WorldTraveller.h +++ b/src/include/WorldTraveller/WorldTraveller.h @@ -31,6 +31,8 @@ typedef struct World i32 heroIndex; i32 freeEntityIndex; u32 uniqueIdAccumulator; + + Entity *soundscape; } World; typedef struct GameState