Add one-shot audio playback (i.e. buffer all data)

This commit is contained in:
Doyle Thai 2016-08-04 00:32:13 +10:00
parent 1900de6a92
commit b5db6e0e2b
4 changed files with 99 additions and 41 deletions

View File

@ -130,7 +130,7 @@ INTERNAL i32 rendererAcquire(MemoryArena *arena, AudioManager *audioManager,
"rendererAcquire(): Renderer has not been released before "
"acquiring, force release by stopping stream");
#endif
audio_streamStopVorbis(arena, audioManager, audioRenderer);
audio_stopVorbis(arena, audioManager, audioRenderer);
}
// TODO(doyle): Super bad linear O(n) search for every audio-enabled entity
@ -209,8 +209,11 @@ INTERNAL const i32 rendererRelease(MemoryArena *arena, AudioManager *audioManage
audioRenderer->bufferId[i] = 0;
}
stb_vorbis_close(audioRenderer->audio->file);
PLATFORM_MEM_FREE(arena, audioRenderer->audio, sizeof(AudioVorbis));
if (audioRenderer->isStreaming)
{
stb_vorbis_close(audioRenderer->audio->file);
PLATFORM_MEM_FREE(arena, audioRenderer->audio, sizeof(AudioVorbis));
}
audioRenderer->audio = NULL;
audioRenderer->numPlays = 0;
@ -223,10 +226,10 @@ INTERNAL const i32 rendererRelease(MemoryArena *arena, AudioManager *audioManage
return result;
}
#define AUDIO_CHUNK_SIZE_ 65536
const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer,
AudioVorbis *vorbis, i32 numPlays)
INTERNAL i32 initRendererForPlayback(MemoryArena *arena,
AudioManager *audioManager,
AudioRenderer *audioRenderer,
AudioVorbis *vorbis, i32 numPlays)
{
#ifdef DENGINE_DEBUG
ASSERT(audioManager && audioRenderer && vorbis);
@ -255,6 +258,39 @@ const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
#endif
}
audioRenderer->numPlays = numPlays;
return result;
}
const i32 audio_playVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer, AudioVorbis *vorbis,
i32 numPlays)
{
i32 result = initRendererForPlayback(arena, audioManager, audioRenderer,
vorbis, numPlays);
i16 *soundSamples;
i32 channels, sampleRate;
i32 numSamples = stb_vorbis_decode_memory(
vorbis->data, vorbis->size, &channels, &sampleRate, &soundSamples);
alBufferData(audioRenderer->bufferId[0], audioRenderer->format,
soundSamples, numSamples * vorbis->info.channels * sizeof(i16),
vorbis->info.sample_rate);
audioRenderer->audio = vorbis;
audioRenderer->isStreaming = FALSE;
return result;
}
const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer,
AudioVorbis *vorbis, i32 numPlays)
{
i32 result = initRendererForPlayback(arena, audioManager, audioRenderer,
vorbis, numPlays);
// NOTE(doyle): We make a copy of the audio vorbis file using all the same
// data except the file pointer. If the same sound is playing twice
// simultaneously, we need unique file pointers into the data to track song
@ -272,14 +308,14 @@ const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
copyAudio->file =
stb_vorbis_open_memory(copyAudio->data, copyAudio->size, &error, NULL);
audioRenderer->audio = copyAudio;
audioRenderer->numPlays = numPlays;
audioRenderer->audio = copyAudio;
audioRenderer->isStreaming = TRUE;
return 0;
return result;
}
const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer)
const i32 audio_stopVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer)
{
i32 result = 0;
u32 alSourceId = getSourceId(audioManager, audioRenderer);
@ -291,15 +327,22 @@ const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager,
}
else
{
DEBUG_LOG("audio_streamStopVorbis(): Tried to stop invalid source");
#ifdef DENGINE_DEBUG
if (audioRenderer->audio)
{
DEBUG_LOG(
"audio_streamStopVorbis(): Tried to stop invalid source, but "
"renderer has valid audio ptr");
}
#endif
result = -1;
}
return result;
}
const i32 audio_streamPauseVorbis(AudioManager *audioManager,
AudioRenderer *audioRenderer)
const i32 audio_pauseVorbis(AudioManager *audioManager,
AudioRenderer *audioRenderer)
{
i32 result = 0;
u32 alSourceId = getSourceId(audioManager, audioRenderer);
@ -316,8 +359,8 @@ const i32 audio_streamPauseVorbis(AudioManager *audioManager,
return result;
}
const i32 audio_streamResumeVorbis(AudioManager *audioManager,
AudioRenderer *audioRenderer)
const i32 audio_resumeVorbis(AudioManager *audioManager,
AudioRenderer *audioRenderer)
{
i32 result = 0;
u32 alSourceId = getSourceId(audioManager, audioRenderer);
@ -328,13 +371,16 @@ const i32 audio_streamResumeVorbis(AudioManager *audioManager,
}
else
{
DEBUG_LOG("audio_streamResumeVorbis(): Tried to resume invalid source");
#ifdef DENGINE_DEBUG
DEBUG_LOG("audio_resumeVorbis(): Tried to resume invalid source")
#endif
result = -1;
}
return result;
}
#define AUDIO_CHUNK_SIZE_ 65536
const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer)
{
@ -388,22 +434,31 @@ const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
}
}
stb_vorbis_seek_start(audio->file);
for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++)
if (audioRenderer->isStreaming)
{
i16 audioChunk[AUDIO_CHUNK_SIZE_] = {0};
stb_vorbis_get_samples_short_interleaved(
audio->file, audio->info.channels, audioChunk,
AUDIO_CHUNK_SIZE_);
stb_vorbis_seek_start(audio->file);
for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++)
{
i16 audioChunk[AUDIO_CHUNK_SIZE_] = {0};
stb_vorbis_get_samples_short_interleaved(
audio->file, audio->info.channels, audioChunk,
AUDIO_CHUNK_SIZE_);
alBufferData(audioRenderer->bufferId[i], audioRenderer->format,
audioChunk, AUDIO_CHUNK_SIZE_ * sizeof(i16),
audio->info.sample_rate);
AL_CHECK_ERROR();
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);
}
else
{
alSourceQueueBuffers(alSourceId, 1, audioRenderer->bufferId);
}
alSourceQueueBuffers(alSourceId, ARRAY_COUNT(audioRenderer->bufferId),
audioRenderer->bufferId);
AL_CHECK_ERROR();
alSourcePlay(alSourceId);
AL_CHECK_ERROR();

View File

@ -13,6 +13,7 @@ enum State
enum EventType
{
eventtype_null = 0,
eventtype_start_attack,
eventtype_end_attack,
eventtype_start_anim,
@ -1035,10 +1036,10 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
if (!event.data) continue;
Entity *entity = (CAST(Entity *) event.data);
audio_streamPlayVorbis(
audio_playVorbis(
arena, audioManager, entity->audioRenderer,
asset_getVorbis(assetManager, audiolist_tackle), 1);
break;
break;
}
// NOTE(doyle): We delete dead entities at the end of the update
// loop incase a later indexed entity deletes an earlier indexed
@ -1049,8 +1050,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
if (!event.data) continue;
Entity *entity = (CAST(Entity *) event.data);
audio_streamStopVorbis(&state->arena, audioManager,
entity->audioRenderer);
audio_stopVorbis(&state->arena, audioManager,
entity->audioRenderer);
entity_clearData(&state->arena, world, entity);
numDeadEntities++;
break;

View File

@ -29,23 +29,28 @@ typedef struct AudioManager
typedef struct AudioRenderer
{
i32 sourceIndex;
ALuint bufferId[4];
ALuint bufferId[3];
AudioVorbis *audio;
ALuint format;
i32 numPlays;
b32 isStreaming;
} AudioRenderer;
const i32 audio_init(AudioManager *audioManager);
const i32 audio_playVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer, AudioVorbis *vorbis,
i32 numPlays);
const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer,
AudioVorbis *vorbis, i32 numPlays);
const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager,
const i32 audio_stopVorbis(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer);
const i32 audio_streamPauseVorbis(AudioManager *audioManager,
const i32 audio_pauseVorbis(AudioManager *audioManager,
AudioRenderer *audioRenderer);
const i32 audio_streamResumeVorbis(AudioManager *audioManager,
const i32 audio_resumeVorbis(AudioManager *audioManager,
AudioRenderer *audioRenderer);
const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
AudioRenderer *audioRenderer);

View File

@ -9,9 +9,6 @@
#include "Dengine/MemoryArena.h"
#include "Dengine/Renderer.h"
/* Forward Declaration */
typedef struct MemoryArena MemoryArena;
#define NUM_KEYS 1024
#define METERS_TO_PIXEL 240