| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsOAAudioClip.h"
- #include "BsOggVorbisEncoder.h"
- #include "BsOggVorbisDecoder.h"
- #include "FileSystem/BsDataStream.h"
- #include "BsOAAudio.h"
- #include "AL/al.h"
- namespace bs
- {
- OAAudioClip::OAAudioClip(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples, const AUDIO_CLIP_DESC& desc)
- :AudioClip(samples, streamSize, numSamples, desc), mNeedsDecompression(false), mBufferId((UINT32)-1), mSourceStreamSize(0)
- { }
- OAAudioClip::~OAAudioClip()
- {
- if (mBufferId != (UINT32)-1)
- alDeleteBuffers(1, &mBufferId);
- }
- void OAAudioClip::initialize()
- {
- {
- Lock lock(mMutex); // Needs to be called even if stream data is null, to ensure memory fence is added so the
- // other thread sees properly initialized AudioClip members
- AudioDataInfo info;
- info.bitDepth = mDesc.bitDepth;
- info.numChannels = mDesc.numChannels;
- info.numSamples = mNumSamples;
- info.sampleRate = mDesc.frequency;
- // If we need to keep source data, read everything into memory and keep a copy
- if (mKeepSourceData)
- {
- mStreamData->seek(mStreamOffset);
- UINT8* sampleBuffer = (UINT8*)bs_alloc(mStreamSize);
- mStreamData->read(sampleBuffer, mStreamSize);
- mSourceStreamData = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, mStreamSize);
- mSourceStreamSize = mStreamSize;
- }
- // Load decompressed data into a sound buffer
- bool loadDecompressed =
- mDesc.readMode == AudioReadMode::LoadDecompressed ||
- (mDesc.readMode == AudioReadMode::LoadCompressed && mDesc.format == AudioFormat::PCM);
- if(loadDecompressed)
- {
- // Read all data into memory
- SPtr<DataStream> stream;
- UINT32 offset = 0;
- if (mSourceStreamData != nullptr) // If it's already loaded in memory, use it directly
- stream = mSourceStreamData;
- else
- {
- stream = mStreamData;
- offset = mStreamOffset;
- }
- UINT32 bufferSize = info.numSamples * (info.bitDepth / 8);
- UINT8* sampleBuffer = (UINT8*)bs_stack_alloc(bufferSize);
- // Decompress from Ogg
- if (mDesc.format == AudioFormat::VORBIS)
- {
- OggVorbisDecoder reader;
- if (reader.open(stream, info, offset))
- reader.read(sampleBuffer, info.numSamples);
- else
- LOGERR("Failed decompressing AudioClip stream.");
- }
- // Load directly
- else
- {
- stream->seek(offset);
- stream->read(sampleBuffer, bufferSize);
- }
- alGenBuffers(1, &mBufferId);
- gOAAudio()._writeToOpenALBuffer(mBufferId, sampleBuffer, info);
- mStreamData = nullptr;
- mStreamOffset = 0;
- mStreamSize = 0;
- bs_stack_free(sampleBuffer);
- }
- // Load compressed data for streaming from memory
- else if(mDesc.readMode == AudioReadMode::LoadCompressed)
- {
- // If reading from file, make a copy of data in memory, otherwise just take ownership of the existing buffer
- if (mStreamData->isFile())
- {
- if (mSourceStreamData != nullptr) // If it's already loaded in memory, use it directly
- mStreamData = mSourceStreamData;
- else
- {
- UINT8* data = (UINT8*)bs_alloc(mStreamSize);
- mStreamData->seek(mStreamOffset);
- mStreamData->read(data, mStreamSize);
- mStreamData = bs_shared_ptr_new<MemoryDataStream>(data, mStreamSize);
- }
- mStreamOffset = 0;
- }
- }
- // Keep original stream for streaming from file
- else
- {
- // Do nothing
- }
- if (mDesc.format == AudioFormat::VORBIS && mDesc.readMode != AudioReadMode::LoadDecompressed)
- {
- mNeedsDecompression = true;
- if (mStreamData != nullptr)
- {
- if (!mVorbisReader.open(mStreamData, info, mStreamOffset))
- LOGERR("Failed decompressing AudioClip stream.");
- }
- }
- }
- AudioClip::initialize();
- }
- void OAAudioClip::getSamples(UINT8* samples, UINT32 offset, UINT32 count) const
- {
- Lock lock(mMutex);
- // Try to read from normal stream, and if that fails read from in-memory stream if it exists
- if (mStreamData != nullptr)
- {
- if (mNeedsDecompression)
- {
- mVorbisReader.seek(offset);
- mVorbisReader.read(samples, count);
- }
- else
- {
- UINT32 bytesPerSample = mDesc.bitDepth / 8;
- UINT32 size = count * bytesPerSample;
- UINT32 streamOffset = mStreamOffset + offset * bytesPerSample;
- mStreamData->seek(streamOffset);
- mStreamData->read(samples, size);
- }
- return;
- }
- if (mSourceStreamData != nullptr)
- {
- assert(!mNeedsDecompression); // Normal stream must exist if decompressing
- UINT32 bytesPerSample = mDesc.bitDepth / 8;
- UINT32 size = count * bytesPerSample;
- UINT32 streamOffset = offset * bytesPerSample;
- mSourceStreamData->seek(streamOffset);
- mSourceStreamData->read(samples, size);
- return;
- }
- LOGWRN("Attempting to read samples while sample data is not available.");
- }
- SPtr<DataStream> OAAudioClip::getSourceStream(UINT32& size)
- {
- Lock lock(mMutex);
- size = mSourceStreamSize;
- mSourceStreamData->seek(0);
- return mSourceStreamData;
- }
- }
|