OggVorbisSoundStream.cpp 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Audio/OggVorbisSoundStream.h"
  5. #include "../Audio/Sound.h"
  6. #include <STB/stb_vorbis.h>
  7. #include "../DebugNew.h"
  8. namespace Urho3D
  9. {
  10. OggVorbisSoundStream::OggVorbisSoundStream(const Sound* sound)
  11. {
  12. assert(sound && sound->IsCompressed());
  13. SetFormat(sound->GetIntFrequency(), sound->IsSixteenBit(), sound->IsStereo());
  14. // If the sound is looped, the stream will automatically rewind at end
  15. SetStopAtEnd(!sound->IsLooped());
  16. // Initialize decoder
  17. data_ = sound->GetData();
  18. dataSize_ = sound->GetDataSize();
  19. int error;
  20. decoder_ = stb_vorbis_open_memory((unsigned char*)data_.Get(), dataSize_, &error, nullptr);
  21. }
  22. OggVorbisSoundStream::~OggVorbisSoundStream()
  23. {
  24. // Close decoder
  25. if (decoder_)
  26. {
  27. auto* vorbis = static_cast<stb_vorbis*>(decoder_);
  28. stb_vorbis_close(vorbis);
  29. decoder_ = nullptr;
  30. }
  31. }
  32. bool OggVorbisSoundStream::Seek(unsigned sample_number)
  33. {
  34. if (!decoder_)
  35. return false;
  36. auto* vorbis = static_cast<stb_vorbis*>(decoder_);
  37. return stb_vorbis_seek(vorbis, sample_number) == 1;
  38. }
  39. unsigned OggVorbisSoundStream::GetData(signed char* dest, unsigned numBytes)
  40. {
  41. if (!decoder_)
  42. return 0;
  43. auto* vorbis = static_cast<stb_vorbis*>(decoder_);
  44. unsigned channels = stereo_ ? 2 : 1;
  45. auto outSamples = (unsigned)stb_vorbis_get_samples_short_interleaved(vorbis, channels, (short*)dest, numBytes >> 1u);
  46. unsigned outBytes = (outSamples * channels) << 1u;
  47. // Rewind and retry if is looping and produced less output than should have
  48. if (outBytes < numBytes && !stopAtEnd_)
  49. {
  50. numBytes -= outBytes;
  51. stb_vorbis_seek_start(vorbis);
  52. outSamples =
  53. (unsigned)stb_vorbis_get_samples_short_interleaved(vorbis, channels, (short*)(dest + outBytes), numBytes >> 1u);
  54. outBytes += (outSamples * channels) << 1u;
  55. }
  56. return outBytes;
  57. }
  58. }