Add one-shot audio playback (i.e. buffer all data)
This commit is contained in:
parent
1900de6a92
commit
b5db6e0e2b
115
src/Audio.c
115
src/Audio.c
@ -130,7 +130,7 @@ INTERNAL i32 rendererAcquire(MemoryArena *arena, AudioManager *audioManager,
|
|||||||
"rendererAcquire(): Renderer has not been released before "
|
"rendererAcquire(): Renderer has not been released before "
|
||||||
"acquiring, force release by stopping stream");
|
"acquiring, force release by stopping stream");
|
||||||
#endif
|
#endif
|
||||||
audio_streamStopVorbis(arena, audioManager, audioRenderer);
|
audio_stopVorbis(arena, audioManager, audioRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(doyle): Super bad linear O(n) search for every audio-enabled entity
|
// 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;
|
audioRenderer->bufferId[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stb_vorbis_close(audioRenderer->audio->file);
|
if (audioRenderer->isStreaming)
|
||||||
PLATFORM_MEM_FREE(arena, audioRenderer->audio, sizeof(AudioVorbis));
|
{
|
||||||
|
stb_vorbis_close(audioRenderer->audio->file);
|
||||||
|
PLATFORM_MEM_FREE(arena, audioRenderer->audio, sizeof(AudioVorbis));
|
||||||
|
}
|
||||||
|
|
||||||
audioRenderer->audio = NULL;
|
audioRenderer->audio = NULL;
|
||||||
audioRenderer->numPlays = 0;
|
audioRenderer->numPlays = 0;
|
||||||
@ -223,10 +226,10 @@ INTERNAL const i32 rendererRelease(MemoryArena *arena, AudioManager *audioManage
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AUDIO_CHUNK_SIZE_ 65536
|
INTERNAL i32 initRendererForPlayback(MemoryArena *arena,
|
||||||
const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
|
AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer,
|
AudioRenderer *audioRenderer,
|
||||||
AudioVorbis *vorbis, i32 numPlays)
|
AudioVorbis *vorbis, i32 numPlays)
|
||||||
{
|
{
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
ASSERT(audioManager && audioRenderer && vorbis);
|
ASSERT(audioManager && audioRenderer && vorbis);
|
||||||
@ -255,6 +258,39 @@ const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
|
|||||||
#endif
|
#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
|
// 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
|
// data except the file pointer. If the same sound is playing twice
|
||||||
// simultaneously, we need unique file pointers into the data to track song
|
// 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 =
|
copyAudio->file =
|
||||||
stb_vorbis_open_memory(copyAudio->data, copyAudio->size, &error, NULL);
|
stb_vorbis_open_memory(copyAudio->data, copyAudio->size, &error, NULL);
|
||||||
|
|
||||||
audioRenderer->audio = copyAudio;
|
audioRenderer->audio = copyAudio;
|
||||||
audioRenderer->numPlays = numPlays;
|
audioRenderer->isStreaming = TRUE;
|
||||||
|
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager,
|
const i32 audio_stopVorbis(MemoryArena *arena, AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer)
|
AudioRenderer *audioRenderer)
|
||||||
{
|
{
|
||||||
i32 result = 0;
|
i32 result = 0;
|
||||||
u32 alSourceId = getSourceId(audioManager, audioRenderer);
|
u32 alSourceId = getSourceId(audioManager, audioRenderer);
|
||||||
@ -291,15 +327,22 @@ const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager,
|
|||||||
}
|
}
|
||||||
else
|
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;
|
result = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const i32 audio_streamPauseVorbis(AudioManager *audioManager,
|
const i32 audio_pauseVorbis(AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer)
|
AudioRenderer *audioRenderer)
|
||||||
{
|
{
|
||||||
i32 result = 0;
|
i32 result = 0;
|
||||||
u32 alSourceId = getSourceId(audioManager, audioRenderer);
|
u32 alSourceId = getSourceId(audioManager, audioRenderer);
|
||||||
@ -316,8 +359,8 @@ const i32 audio_streamPauseVorbis(AudioManager *audioManager,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const i32 audio_streamResumeVorbis(AudioManager *audioManager,
|
const i32 audio_resumeVorbis(AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer)
|
AudioRenderer *audioRenderer)
|
||||||
{
|
{
|
||||||
i32 result = 0;
|
i32 result = 0;
|
||||||
u32 alSourceId = getSourceId(audioManager, audioRenderer);
|
u32 alSourceId = getSourceId(audioManager, audioRenderer);
|
||||||
@ -328,13 +371,16 @@ const i32 audio_streamResumeVorbis(AudioManager *audioManager,
|
|||||||
}
|
}
|
||||||
else
|
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;
|
result = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define AUDIO_CHUNK_SIZE_ 65536
|
||||||
const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
|
const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer)
|
AudioRenderer *audioRenderer)
|
||||||
{
|
{
|
||||||
@ -388,22 +434,31 @@ const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stb_vorbis_seek_start(audio->file);
|
if (audioRenderer->isStreaming)
|
||||||
for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++)
|
|
||||||
{
|
{
|
||||||
i16 audioChunk[AUDIO_CHUNK_SIZE_] = {0};
|
stb_vorbis_seek_start(audio->file);
|
||||||
stb_vorbis_get_samples_short_interleaved(
|
for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++)
|
||||||
audio->file, audio->info.channels, audioChunk,
|
{
|
||||||
AUDIO_CHUNK_SIZE_);
|
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,
|
alBufferData(audioRenderer->bufferId[i], audioRenderer->format,
|
||||||
audioChunk, AUDIO_CHUNK_SIZE_ * sizeof(i16),
|
audioChunk, AUDIO_CHUNK_SIZE_ * sizeof(i16),
|
||||||
audio->info.sample_rate);
|
audio->info.sample_rate);
|
||||||
AL_CHECK_ERROR();
|
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();
|
AL_CHECK_ERROR();
|
||||||
alSourcePlay(alSourceId);
|
alSourcePlay(alSourceId);
|
||||||
AL_CHECK_ERROR();
|
AL_CHECK_ERROR();
|
||||||
|
@ -13,6 +13,7 @@ enum State
|
|||||||
|
|
||||||
enum EventType
|
enum EventType
|
||||||
{
|
{
|
||||||
|
eventtype_null = 0,
|
||||||
eventtype_start_attack,
|
eventtype_start_attack,
|
||||||
eventtype_end_attack,
|
eventtype_end_attack,
|
||||||
eventtype_start_anim,
|
eventtype_start_anim,
|
||||||
@ -1035,10 +1036,10 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
if (!event.data) continue;
|
if (!event.data) continue;
|
||||||
|
|
||||||
Entity *entity = (CAST(Entity *) event.data);
|
Entity *entity = (CAST(Entity *) event.data);
|
||||||
audio_streamPlayVorbis(
|
audio_playVorbis(
|
||||||
arena, audioManager, entity->audioRenderer,
|
arena, audioManager, entity->audioRenderer,
|
||||||
asset_getVorbis(assetManager, audiolist_tackle), 1);
|
asset_getVorbis(assetManager, audiolist_tackle), 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// NOTE(doyle): We delete dead entities at the end of the update
|
// NOTE(doyle): We delete dead entities at the end of the update
|
||||||
// loop incase a later indexed entity deletes an earlier indexed
|
// 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;
|
if (!event.data) continue;
|
||||||
|
|
||||||
Entity *entity = (CAST(Entity *) event.data);
|
Entity *entity = (CAST(Entity *) event.data);
|
||||||
audio_streamStopVorbis(&state->arena, audioManager,
|
audio_stopVorbis(&state->arena, audioManager,
|
||||||
entity->audioRenderer);
|
entity->audioRenderer);
|
||||||
entity_clearData(&state->arena, world, entity);
|
entity_clearData(&state->arena, world, entity);
|
||||||
numDeadEntities++;
|
numDeadEntities++;
|
||||||
break;
|
break;
|
||||||
|
@ -29,23 +29,28 @@ typedef struct AudioManager
|
|||||||
typedef struct AudioRenderer
|
typedef struct AudioRenderer
|
||||||
{
|
{
|
||||||
i32 sourceIndex;
|
i32 sourceIndex;
|
||||||
ALuint bufferId[4];
|
ALuint bufferId[3];
|
||||||
|
|
||||||
AudioVorbis *audio;
|
AudioVorbis *audio;
|
||||||
ALuint format;
|
ALuint format;
|
||||||
i32 numPlays;
|
i32 numPlays;
|
||||||
|
|
||||||
|
b32 isStreaming;
|
||||||
} AudioRenderer;
|
} AudioRenderer;
|
||||||
|
|
||||||
|
|
||||||
const i32 audio_init(AudioManager *audioManager);
|
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,
|
const i32 audio_streamPlayVorbis(MemoryArena *arena, AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer,
|
AudioRenderer *audioRenderer,
|
||||||
AudioVorbis *vorbis, i32 numPlays);
|
AudioVorbis *vorbis, i32 numPlays);
|
||||||
const i32 audio_streamStopVorbis(MemoryArena *arena, AudioManager *audioManager,
|
const i32 audio_stopVorbis(MemoryArena *arena, AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer);
|
AudioRenderer *audioRenderer);
|
||||||
const i32 audio_streamPauseVorbis(AudioManager *audioManager,
|
const i32 audio_pauseVorbis(AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer);
|
AudioRenderer *audioRenderer);
|
||||||
const i32 audio_streamResumeVorbis(AudioManager *audioManager,
|
const i32 audio_resumeVorbis(AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer);
|
AudioRenderer *audioRenderer);
|
||||||
const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
|
const i32 audio_updateAndPlay(MemoryArena *arena, AudioManager *audioManager,
|
||||||
AudioRenderer *audioRenderer);
|
AudioRenderer *audioRenderer);
|
||||||
|
@ -9,9 +9,6 @@
|
|||||||
#include "Dengine/MemoryArena.h"
|
#include "Dengine/MemoryArena.h"
|
||||||
#include "Dengine/Renderer.h"
|
#include "Dengine/Renderer.h"
|
||||||
|
|
||||||
/* Forward Declaration */
|
|
||||||
typedef struct MemoryArena MemoryArena;
|
|
||||||
|
|
||||||
#define NUM_KEYS 1024
|
#define NUM_KEYS 1024
|
||||||
#define METERS_TO_PIXEL 240
|
#define METERS_TO_PIXEL 240
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user