/src/sound/sound.cpp

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