|
@@ -2,60 +2,143 @@
|
|
|
//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
|
|
//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
|
|
|
#include "BsOAAudioClip.h"
|
|
#include "BsOAAudioClip.h"
|
|
|
#include "BsOAOggVorbisWriter.h"
|
|
#include "BsOAOggVorbisWriter.h"
|
|
|
|
|
+#include "BsOAOggVorbisReader.h"
|
|
|
#include "BsDataStream.h"
|
|
#include "BsDataStream.h"
|
|
|
|
|
|
|
|
namespace BansheeEngine
|
|
namespace BansheeEngine
|
|
|
{
|
|
{
|
|
|
OAAudioClip::OAAudioClip(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples, const AUDIO_CLIP_DESC& desc)
|
|
OAAudioClip::OAAudioClip(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples, const AUDIO_CLIP_DESC& desc)
|
|
|
- :AudioClip(samples, streamSize, numSamples, desc)
|
|
|
|
|
|
|
+ :AudioClip(samples, streamSize, numSamples, desc), mNeedsDecompression(false)
|
|
|
{ }
|
|
{ }
|
|
|
|
|
|
|
|
void OAAudioClip::initialize()
|
|
void OAAudioClip::initialize()
|
|
|
{
|
|
{
|
|
|
- if (mDesc.readMode != AudioReadMode::Stream)
|
|
|
|
|
{
|
|
{
|
|
|
- // If not streaming, but input stream is a file, read all of it into an internal memory stream
|
|
|
|
|
- if (mStreamData != nullptr)
|
|
|
|
|
|
|
+ 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
|
|
|
|
|
+
|
|
|
|
|
+ AudioFileInfo info;
|
|
|
|
|
+ info.bitDepth = mDesc.bitDepth;
|
|
|
|
|
+ info.numChannels = mDesc.numChannels;
|
|
|
|
|
+ info.numSamples = mNumSamples;
|
|
|
|
|
+ info.sampleRate = mDesc.frequency;
|
|
|
|
|
+
|
|
|
|
|
+ if (mDesc.readMode != AudioReadMode::Stream)
|
|
|
{
|
|
{
|
|
|
- // Decompress if needed
|
|
|
|
|
- if (mDesc.format == AudioFormat::VORBIS && mDesc.readMode == AudioReadMode::LoadDecompressed)
|
|
|
|
|
|
|
+ // If not streaming, but input stream is a file, read all of it into an internal memory stream
|
|
|
|
|
+ if (mStreamData != nullptr)
|
|
|
{
|
|
{
|
|
|
- // TODO - Read entire stream and decompress into a new stream
|
|
|
|
|
|
|
+ // Decompress if needed
|
|
|
|
|
+ if (mDesc.format == AudioFormat::VORBIS && mDesc.readMode == AudioReadMode::LoadDecompressed)
|
|
|
|
|
+ {
|
|
|
|
|
+ mStreamData->seek(mStreamOffset);
|
|
|
|
|
+
|
|
|
|
|
+ OAOggVorbisReader reader;
|
|
|
|
|
+ if (reader.open(mStreamData, info))
|
|
|
|
|
+ {
|
|
|
|
|
+ UINT32 bufferSize = info.numSamples * info.bitDepth;
|
|
|
|
|
+ UINT8* sampleBuffer = (UINT8*)bs_alloc(bufferSize);
|
|
|
|
|
+
|
|
|
|
|
+ reader.read(sampleBuffer, info.numSamples);
|
|
|
|
|
+
|
|
|
|
|
+ mStreamData = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, bufferSize);
|
|
|
|
|
+ mStreamOffset = 0;
|
|
|
|
|
+ mStreamSize = bufferSize;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ LOGERR("Failed decompressing AudioClip stream.");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ if (mStreamData->isFile()) // If reading from file, make a copy of data in memory
|
|
|
|
|
+ {
|
|
|
|
|
+ UINT8* data = (UINT8*)bs_alloc(mStreamSize);
|
|
|
|
|
+
|
|
|
|
|
+ mStreamData->seek(mStreamOffset);
|
|
|
|
|
+ mStreamData->read(data, mStreamSize);
|
|
|
|
|
+
|
|
|
|
|
+ mStreamData = bs_shared_ptr_new<MemoryDataStream>(data, mStreamSize);
|
|
|
|
|
+ mStreamOffset = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (mDesc.format == AudioFormat::VORBIS && mDesc.readMode != AudioReadMode::LoadDecompressed)
|
|
|
|
|
+ {
|
|
|
|
|
+ mNeedsDecompression = true;
|
|
|
|
|
+
|
|
|
|
|
+ if (mStreamData != nullptr)
|
|
|
{
|
|
{
|
|
|
- if(mStreamData->isFile()) // If reading from file, make a copy of data in memory
|
|
|
|
|
- mStreamData = bs_shared_ptr_new<MemoryDataStream>(mStreamData);
|
|
|
|
|
|
|
+ if (!mVorbisReader.open(mStreamData, info))
|
|
|
|
|
+ LOGERR("Failed decompressing AudioClip stream.");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if (mStreamData != nullptr)
|
|
|
|
|
+ mStreamData->seek(mStreamOffset);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
AudioClip::initialize();
|
|
AudioClip::initialize();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void OAAudioClip::getSamples(UINT8* samples, UINT32 count, UINT32 offset) const
|
|
|
|
|
|
|
+ void OAAudioClip::getSamples(UINT8* samples, UINT32 count) const
|
|
|
{
|
|
{
|
|
|
- // TODO - Read from stream, and decompress as needed
|
|
|
|
|
|
|
+ Lock lock(mMutex);
|
|
|
|
|
|
|
|
- // TODO - This must be thread safe as it will be called from other threads. Note this in the docs.
|
|
|
|
|
|
|
+ if (mStreamData == nullptr)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ if (mNeedsDecompression)
|
|
|
|
|
+ mVorbisReader.read(samples, count);
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ UINT32 bytesPerSample = mDesc.bitDepth / 8;
|
|
|
|
|
+ UINT32 size = count * bytesPerSample;
|
|
|
|
|
+
|
|
|
|
|
+ mStreamData->read(samples, size);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void OAAudioClip::seekSamples(UINT32 offset)
|
|
|
|
|
+ {
|
|
|
|
|
+ Lock lock(mMutex);
|
|
|
|
|
+
|
|
|
|
|
+ if (mStreamData == nullptr)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ if (mNeedsDecompression)
|
|
|
|
|
+ mVorbisReader.seek(offset);
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ UINT32 bytesPerSample = mDesc.bitDepth / 8;
|
|
|
|
|
+ UINT32 streamOffset = mStreamOffset + offset * bytesPerSample;
|
|
|
|
|
+
|
|
|
|
|
+ mStreamData->seek(streamOffset);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
SPtr<DataStream> OAAudioClip::getSourceFormatData(UINT32& size)
|
|
SPtr<DataStream> OAAudioClip::getSourceFormatData(UINT32& size)
|
|
|
{
|
|
{
|
|
|
|
|
+ Lock lock(mMutex);
|
|
|
|
|
+
|
|
|
|
|
+ if (mStreamData == nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ size = 0;
|
|
|
|
|
+ return nullptr;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if(mDesc.format == AudioFormat::PCM || mDesc.readMode == AudioReadMode::LoadCompressed ||
|
|
if(mDesc.format == AudioFormat::PCM || mDesc.readMode == AudioReadMode::LoadCompressed ||
|
|
|
mDesc.readMode == AudioReadMode::Stream)
|
|
mDesc.readMode == AudioReadMode::Stream)
|
|
|
{
|
|
{
|
|
|
|
|
+ SPtr<DataStream> outStream = mStreamData->clone(false);
|
|
|
|
|
+ outStream->seek(mStreamOffset);
|
|
|
|
|
+
|
|
|
size = mStreamSize;
|
|
size = mStreamSize;
|
|
|
- return mStreamData;
|
|
|
|
|
|
|
+ return outStream;
|
|
|
}
|
|
}
|
|
|
else // Data has been decompressed, we need to re-compress it to get the original stream
|
|
else // Data has been decompressed, we need to re-compress it to get the original stream
|
|
|
{
|
|
{
|
|
|
- if (mStreamData == nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- size = 0;
|
|
|
|
|
- return nullptr;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
assert(!mStreamData->isFile());
|
|
assert(!mStreamData->isFile());
|
|
|
SPtr<MemoryDataStream> memStream = std::static_pointer_cast<MemoryDataStream>(mStreamData);
|
|
SPtr<MemoryDataStream> memStream = std::static_pointer_cast<MemoryDataStream>(mStreamData);
|
|
|
|
|
|
|
@@ -65,9 +148,15 @@ namespace BansheeEngine
|
|
|
info.numSamples = mNumSamples;
|
|
info.numSamples = mNumSamples;
|
|
|
info.sampleRate = mDesc.frequency;
|
|
info.sampleRate = mDesc.frequency;
|
|
|
|
|
|
|
|
|
|
+ UINT32 orgOffset = (UINT32)memStream->tell();
|
|
|
|
|
+ memStream->seek(mStreamOffset);
|
|
|
|
|
+
|
|
|
UINT32 bufferSize = 0;
|
|
UINT32 bufferSize = 0;
|
|
|
- UINT8* encodedSamples = OAOggVorbisWriter::PCMToOggVorbis(memStream->getPtr(), info, bufferSize);
|
|
|
|
|
|
|
+ UINT8* encodedSamples = OAOggVorbisWriter::PCMToOggVorbis(memStream->getCurrentPtr(), info, bufferSize);
|
|
|
|
|
+
|
|
|
|
|
+ memStream->seek(orgOffset);
|
|
|
|
|
|
|
|
|
|
+ size = bufferSize;
|
|
|
return bs_shared_ptr_new<MemoryDataStream>(encodedSamples, bufferSize);
|
|
return bs_shared_ptr_new<MemoryDataStream>(encodedSamples, bufferSize);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|