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 " | ||||
| 		    "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(); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user