/src/sound/sound.cpp
C++ | 206 lines | 171 code | 35 blank | 0 comment | 10 complexity | d3fd4a573c14ea4a55d250ce44574f88 MD5 | raw file
1#include <xaudio2.h> 2#include <mmsystem.h> 3#include <stb_vorbis/stb_vorbis.h> 4#include "common.h" 5#include "sound.h" 6 7namespace snd 8{ 9 static tlsf_pool gs_sound_heap; 10 IXAudio2* g_xaudio2 = NULL; 11 IXAudio2MasteringVoice* g_mastering_voice = NULL; 12 stb_vorbis_alloc vorbis_alloc; 13 14 struct sound 15 { 16 XAUDIO2_BUFFER buffer; 17 IXAudio2SourceVoice* source_voice; 18 WAVEFORMATEX* wfx; 19 uint32 wave_data_size; 20 void* wave_data; 21 22 }; 23 24 25 26 inline void* snd_alloc(size_t size) 27 { 28 return tlsf_malloc(gs_sound_heap, size); 29 } 30 31 inline void snd_free(void* ptr) 32 { 33 tlsf_free(gs_sound_heap, ptr); 34 } 35 36 37 bool init(void* memory, size_t size, size_t decoder_size) 38 { 39 ASSERT(memory); 40 ASSERT(size); 41 gs_sound_heap = tlsf_create(memory, size); 42 vorbis_alloc.alloc_buffer = (char*)snd_alloc(decoder_size); 43 vorbis_alloc.alloc_buffer_length_in_bytes = decoder_size; 44 CoInitializeEx(0,COINIT_MULTITHREADED); 45 if(XAudio2Create(&g_xaudio2,0,XAUDIO2_DEFAULT_PROCESSOR)!=S_OK) 46 { 47 CoUninitialize(); 48 return false; 49 } 50 if(g_xaudio2->CreateMasteringVoice( &g_mastering_voice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, 0,0)!=S_OK) 51 { 52 g_xaudio2->Release(); 53 g_xaudio2 = NULL; 54 CoUninitialize(); 55 return false; 56 } 57 58 return true; 59 } 60 61 void term() 62 { 63 snd_free(vorbis_alloc.alloc_buffer); 64 vorbis_alloc.alloc_buffer = NULL; 65 vorbis_alloc.alloc_buffer_length_in_bytes = 0; 66 g_mastering_voice->DestroyVoice(); 67 g_mastering_voice = NULL; 68 g_xaudio2->Release(); 69 g_xaudio2 = NULL; 70 } 71 72 73 void set_master_volume(float volume) 74 { 75 ASSERT(g_mastering_voice); 76 g_mastering_voice->SetVolume(volume); 77 } 78 79 void get_master_volume(float* out) 80 { 81 ASSERT(g_mastering_voice && out); 82 g_mastering_voice->GetVolume(out); 83 } 84 85 sound* load_sound(char* filename) 86 { 87 sound* s = (sound*)snd_alloc(sizeof(sound)); 88 memset(s,0,sizeof(sound)); 89 90 int error = 0; 91 stb_vorbis* vb_data = stb_vorbis_open_filename(filename,&error,&vorbis_alloc); 92 if(error != VORBIS__no_error) 93 return NULL; 94 stb_vorbis_info vorbis_info = stb_vorbis_get_info(vb_data); 95 96 97 98 s->wfx = (WAVEFORMATEX*)snd_alloc(sizeof(WAVEFORMATEX)); 99 memset(s->wfx,0,sizeof(WAVEFORMATEX)); 100 s->wfx->wFormatTag = WAVE_FORMAT_PCM; 101 s->wfx->wBitsPerSample = 16; 102 s->wfx->nSamplesPerSec = vorbis_info.sample_rate; 103 s->wfx->nChannels = (WORD)vorbis_info.channels; 104 s->wfx->nBlockAlign = s->wfx->nChannels*2; 105 s->wfx->nAvgBytesPerSec = s->wfx->nBlockAlign * s->wfx->nSamplesPerSec; 106 int samples = stb_vorbis_stream_length_in_samples(vb_data); 107 108 109 s->wave_data = snd_alloc(samples * s->wfx->nChannels *2); 110 int samples_read = 0; 111 short* ptr = (short*)s->wave_data; 112 do 113 { 114 samples_read = stb_vorbis_get_samples_short_interleaved(vb_data,s->wfx->nChannels,ptr,samples); 115 ptr += samples_read*s->wfx->nChannels; 116 } 117 while(samples_read > 0); 118 s->wave_data_size = samples * s->wfx->nChannels *2; 119 stb_vorbis_close(vb_data); 120 121 HRESULT hr = g_xaudio2->CreateSourceVoice(&(s->source_voice), s->wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO); 122 if(hr != S_OK) 123 { 124 snd_free((void*)s->wave_data); 125 snd_free((void*)s->wfx); 126 snd_free((void*)s); 127 return NULL; 128 } 129 reset_sound(s); 130 return s; 131 } 132 133 void destroy_sound(sound* s) 134 { 135 snd_free((void*)s->wave_data); 136 snd_free((void*)s->wfx); 137 snd_free((void*)s); 138 } 139 140 void reset_sound(sound* s) 141 { 142 ASSERT(s); 143 memset(&s->buffer, 0, sizeof(XAUDIO2_BUFFER)); 144 s->buffer.Flags = XAUDIO2_END_OF_STREAM; 145 s->buffer.AudioBytes = s->wave_data_size; 146 s->buffer.pAudioData = (BYTE*)s->wave_data; 147 HRESULT hr = s->source_voice->SubmitSourceBuffer(&s->buffer); 148 ASSERT(hr == S_OK); 149 } 150 151 void play_sound(sound* s) 152 { 153 HRESULT hr = s->source_voice->Start( 0, XAUDIO2_COMMIT_NOW ); 154 ASSERT(hr == S_OK); 155 } 156 157 void stop_sound(sound* s) 158 { 159 ASSERT(s); 160 HRESULT hr = s->source_voice->Stop(); 161 ASSERT(hr == S_OK); 162 } 163 164 void set_volume(sound* s, float volume) 165 { 166 ASSERT(s); 167 s->source_voice->SetVolume(volume); 168 } 169 170 void get_volume(sound* s, float* out) 171 { 172 ASSERT(s); 173 s->source_voice->GetVolume(out); 174 } 175 176 bool is_playing(sound* s) 177 { 178 ASSERT(s); 179 static XAUDIO2_VOICE_STATE state; 180 s->source_voice->GetState(&state); 181 return state.BuffersQueued > 0; 182 } 183 184 uint32 get_bytes_per_sample(sound* s) 185 { 186 ASSERT(s); 187 return s->wfx->nChannels * 2; 188 } 189 190 uint32 get_data_size(sound* s) 191 { 192 ASSERT(s); 193 return s->wave_data_size; 194 } 195 196 uint64 get_pos_in_samples(sound* s) 197 { 198 ASSERT(s); 199 XAUDIO2_VOICE_STATE voice_state; 200 s->source_voice->GetState(&voice_state); 201 return voice_state.SamplesPlayed; 202 } 203 204 205 206}