소스 검색

OpenAudio importer implemented

BearishSun 9 년 전
부모
커밋
6f00387451

+ 15 - 0
Source/BansheeCore/CMakeSources.cmake

@@ -467,6 +467,18 @@ set(BS_BANSHEECORE_SRC_SCENE
 	"Source/BsPrefabUtility.cpp"
 	"Source/BsPrefabUtility.cpp"
 )
 )
 
 
+set(BS_BANSHEECORE_INC_AUDIO
+	"Include/BsAudio.h"
+	"Include/BsAudioClip.h"
+	"Include/BsAudioClipImportOptions.h"
+)
+
+set(BS_BANSHEECORE_SRC_AUDIO
+	"Source/BsAudio.cpp"
+	"Source/BsAudioClip.cpp"
+	"Source/BsAudioClipImportOptions.cpp"
+)
+
 source_group("Header Files\\Components" FILES ${BS_BANSHEECORE_INC_COMPONENTS})
 source_group("Header Files\\Components" FILES ${BS_BANSHEECORE_INC_COMPONENTS})
 source_group("Header Files\\Physics" FILES ${BS_BANSHEECORE_INC_PHYSICS})
 source_group("Header Files\\Physics" FILES ${BS_BANSHEECORE_INC_PHYSICS})
 source_group("Header Files\\CoreThread" FILES ${BS_BANSHEECORE_INC_CORETHREAD})
 source_group("Header Files\\CoreThread" FILES ${BS_BANSHEECORE_INC_CORETHREAD})
@@ -501,6 +513,8 @@ source_group("Source Files\\RenderAPI" FILES ${BS_BANSHEECORE_SRC_RENDERAPI})
 source_group("Source Files" FILES ${BS_BANSHEECORE_SRC_NOFILTER})
 source_group("Source Files" FILES ${BS_BANSHEECORE_SRC_NOFILTER})
 source_group("Source Files\\Physics" FILES ${BS_BANSHEECORE_SRC_PHYSICS})
 source_group("Source Files\\Physics" FILES ${BS_BANSHEECORE_SRC_PHYSICS})
 source_group("Source Files\\Scene" FILES ${BS_BANSHEECORE_SRC_SCENE})
 source_group("Source Files\\Scene" FILES ${BS_BANSHEECORE_SRC_SCENE})
+source_group("Header Files\\Audio" FILES ${BS_BANSHEECORE_INC_AUDIO})
+source_group("Source Files\\Audio" FILES ${BS_BANSHEECORE_SRC_AUDIO})
 
 
 set(BS_BANSHEECORE_SRC
 set(BS_BANSHEECORE_SRC
 	${BS_BANSHEECORE_INC_COMPONENTS}
 	${BS_BANSHEECORE_INC_COMPONENTS}
@@ -537,4 +551,5 @@ set(BS_BANSHEECORE_SRC
 	${BS_BANSHEECORE_SRC_NOFILTER}
 	${BS_BANSHEECORE_SRC_NOFILTER}
 	${BS_BANSHEECORE_SRC_PHYSICS}
 	${BS_BANSHEECORE_SRC_PHYSICS}
 	${BS_BANSHEECORE_SRC_SCENE}
 	${BS_BANSHEECORE_SRC_SCENE}
+	${BS_BANSHEECORE_SRC_AUDIO}
 )
 )

+ 4 - 4
Source/BansheeCore/Include/BsAudioClipImportOptions.h

@@ -24,6 +24,10 @@ namespace BansheeEngine
 
 
 		// Note: Add options to resample to a different frequency, reduce/increase bit depth, and stereo -> mono conversion
 		// Note: Add options to resample to a different frequency, reduce/increase bit depth, and stereo -> mono conversion
 
 
+	private:
+		AudioFormat mFormat = AudioFormat::PCM;
+		AudioReadMode mReadMode = AudioReadMode::LoadDecompressed;
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
 		/* 								SERIALIZATION                      		*/
 		/************************************************************************/
 		/************************************************************************/
@@ -31,10 +35,6 @@ namespace BansheeEngine
 		friend class AudioClipImportOptionsRTTI;
 		friend class AudioClipImportOptionsRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
 		RTTITypeBase* getRTTI() const override;
 		RTTITypeBase* getRTTI() const override;
-
-	private:
-		AudioFormat mFormat = AudioFormat::PCM;
-		AudioReadMode mReadMode = AudioReadMode::LoadDecompressed;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 2 - 1
Source/BansheeOpenAudio/Include/BsOAOggVorbisWriter.h

@@ -18,7 +18,7 @@ namespace BansheeEngine
 		OAOggVorbisWriter();
 		OAOggVorbisWriter();
 		~OAOggVorbisWriter();
 		~OAOggVorbisWriter();
 
 
-		bool open(std::function<void(UINT8*, UINT32)> writeCallback, UINT32 sampleRate, UINT32 numChannels);
+		bool open(std::function<void(UINT8*, UINT32)> writeCallback, UINT32 sampleRate, UINT32 bitDepth, UINT32 numChannels);
 
 
 		void write(UINT8* samples, UINT32 numSamples); // Assumes 16-bit samples
 		void write(UINT8* samples, UINT32 numSamples); // Assumes 16-bit samples
 		void flush();
 		void flush();
@@ -32,6 +32,7 @@ namespace BansheeEngine
 		UINT8 mBuffer[BUFFER_SIZE];
 		UINT8 mBuffer[BUFFER_SIZE];
 		UINT32 mBufferOffset;
 		UINT32 mBufferOffset;
 		UINT32 mNumChannels;
 		UINT32 mNumChannels;
+		UINT32 mBitDepth;
 
 
 		ogg_stream_state mOggState;
 		ogg_stream_state mOggState;
 		vorbis_info mVorbisInfo;
 		vorbis_info mVorbisInfo;

+ 9 - 9
Source/BansheeOpenAudio/Source/BsOAFLACReader.cpp

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 {
 	FLAC__StreamDecoderReadStatus streamRead(const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t* bytes, void* clientData)
 	FLAC__StreamDecoderReadStatus streamRead(const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t* bytes, void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
 
 		INT64 count = (INT64)data->stream->read(buffer, *bytes);
 		INT64 count = (INT64)data->stream->read(buffer, *bytes);
 		if (count > 0)
 		if (count > 0)
@@ -24,7 +24,7 @@ namespace BansheeEngine
 
 
 	FLAC__StreamDecoderSeekStatus streamSeek(const FLAC__StreamDecoder*, FLAC__uint64 absoluteByteOffset, void* clientData)
 	FLAC__StreamDecoderSeekStatus streamSeek(const FLAC__StreamDecoder*, FLAC__uint64 absoluteByteOffset, void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
 
 		data->stream->seek(absoluteByteOffset);
 		data->stream->seek(absoluteByteOffset);
 		INT64 position = (INT64)data->stream->tell();
 		INT64 position = (INT64)data->stream->tell();
@@ -36,7 +36,7 @@ namespace BansheeEngine
 
 
 	FLAC__StreamDecoderTellStatus streamTell(const FLAC__StreamDecoder*, FLAC__uint64* absoluteByteOffset, void* clientData)
 	FLAC__StreamDecoderTellStatus streamTell(const FLAC__StreamDecoder*, FLAC__uint64* absoluteByteOffset, void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
 
 		INT64 position = (INT64)data->stream->tell();
 		INT64 position = (INT64)data->stream->tell();
 		if (position >= 0)
 		if (position >= 0)
@@ -52,7 +52,7 @@ namespace BansheeEngine
 
 
 	FLAC__StreamDecoderLengthStatus streamLength(const FLAC__StreamDecoder*, FLAC__uint64* streamLength, void* clientData)
 	FLAC__StreamDecoderLengthStatus streamLength(const FLAC__StreamDecoder*, FLAC__uint64* streamLength, void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
 
 		*streamLength = data->stream->size();
 		*streamLength = data->stream->size();
 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
@@ -60,14 +60,14 @@ namespace BansheeEngine
 
 
 	FLAC__bool streamEof(const FLAC__StreamDecoder*, void* clientData)
 	FLAC__bool streamEof(const FLAC__StreamDecoder*, void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
 
 		return data->stream->eof();
 		return data->stream->eof();
 	}
 	}
 
 
 	FLAC__StreamDecoderWriteStatus streamWrite(const FLAC__StreamDecoder*, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* clientData)
 	FLAC__StreamDecoderWriteStatus streamWrite(const FLAC__StreamDecoder*, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
 
 		if (!data->output) // Seek
 		if (!data->output) // Seek
 			return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 			return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
@@ -111,7 +111,7 @@ namespace BansheeEngine
 
 
 	void streamMetadata(const FLAC__StreamDecoder*, const FLAC__StreamMetadata* meta, void* clientData)
 	void streamMetadata(const FLAC__StreamDecoder*, const FLAC__StreamMetadata* meta, void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
 
 		if (meta->type == FLAC__METADATA_TYPE_STREAMINFO)
 		if (meta->type == FLAC__METADATA_TYPE_STREAMINFO)
 		{
 		{
@@ -124,7 +124,7 @@ namespace BansheeEngine
 
 
 	void streamError(const FLAC__StreamDecoder*, FLAC__StreamDecoderErrorStatus, void* clientData)
 	void streamError(const FLAC__StreamDecoder*, FLAC__StreamDecoderErrorStatus, void* clientData)
 	{
 	{
-		FLACDecoderData* data = static_cast<FLACDecoderData*>(clientData);
+		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 		data->error = true;
 		data->error = true;
 	}
 	}
 
 
@@ -148,7 +148,7 @@ namespace BansheeEngine
 		FLACDecoderData data;
 		FLACDecoderData data;
 		data.stream = stream;
 		data.stream = stream;
 		FLAC__stream_decoder_init_stream(decoder, &streamRead, &streamSeek, &streamTell, &streamLength, &streamEof, 
 		FLAC__stream_decoder_init_stream(decoder, &streamRead, &streamSeek, &streamTell, &streamLength, &streamEof, 
-			&streamWrite, NULL, &streamError, &data);
+			&streamWrite, nullptr, &streamError, &data);
 
 
 		bool valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder) != 0;
 		bool valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder) != 0;
 
 

+ 84 - 19
Source/BansheeOpenAudio/Source/BsOAImporter.cpp

@@ -6,6 +6,8 @@
 #include "BsOAWaveReader.h"
 #include "BsOAWaveReader.h"
 #include "BsOAFLACReader.h"
 #include "BsOAFLACReader.h"
 #include "BsOAOggVorbisReader.h"
 #include "BsOAOggVorbisReader.h"
+#include "BsOAOggVorbisWriter.h"
+#include "BsAudioClipImportOptions.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -41,30 +43,93 @@ namespace BansheeEngine
 		WString extension = filePath.getWExtension();
 		WString extension = filePath.getWExtension();
 		StringUtil::toLowerCase(extension);
 		StringUtil::toLowerCase(extension);
 
 
-		// TODO - Respect import options and read mode
-		AudioFileInfo info;
-		UINT8* samples = nullptr;
+		UPtr<OAFileReader> reader(nullptr, nullptr);
 		if(extension == L"wav")
 		if(extension == L"wav")
-		{
-			OAWaveReader reader;
-			if (!reader.isValid(stream))
-				return nullptr;
-
-			if (!reader.open(stream, info))
-				return nullptr;
-
-			//samples = bs_alloc(info.)
-			//reader.read()
-		}
+			reader = bs_unique_ptr<OAFileReader>(bs_new<OAWaveReader>());
 		else if(extension == L"flac")
 		else if(extension == L"flac")
-		{
-			
-		}
+			reader = bs_unique_ptr<OAFileReader>(bs_new<OAFLACReader>());
 		else if(extension == L"ogg")
 		else if(extension == L"ogg")
+			reader = bs_unique_ptr<OAFileReader>(bs_new<OAOggVorbisReader>());
+
+		if (reader == nullptr)
+			return nullptr;
+
+		AudioFileInfo info;
+		if (!reader->isValid(stream))
+			return nullptr;
+
+		if (!reader->open(stream, info))
+			return nullptr;
+
+		UINT32 bufferSize = info.numSamples * info.bitDepth;
+		UINT8* sampleBuffer = (UINT8*)bs_alloc(bufferSize);
+		reader->read(sampleBuffer, info.numSamples);
+
+		SPtr<const AudioClipImportOptions> clipIO = std::static_pointer_cast<const AudioClipImportOptions>(importOptions);
+
+		// Encode to Ogg Vorbis if needed
+		if(clipIO->getFormat() == AudioFormat::VORBIS)
 		{
 		{
-			
+			struct EncodedBlock
+			{
+				UINT8* data;
+				UINT32 size;
+			};
+
+			Vector<EncodedBlock> blocks;
+			UINT32 totalEncodedSize = 0;
+			auto writeCallback = [&](UINT8* buffer, UINT32 size)
+			{
+				EncodedBlock newBlock;
+				newBlock.data = bs_frame_alloc(size);
+				newBlock.size = size;
+
+				memcpy(newBlock.data, buffer, size);
+				blocks.push_back(newBlock);
+				totalEncodedSize += size;
+			};
+
+			bs_frame_mark();
+
+			// Note: If the original source was in Ogg Vorbis we could just copy it here, but instead we decode to PCM and
+			// then re-encode which is redundant. If later we decide to copy be aware that the engine encodes Ogg in a
+			// specific quality, and the the import source might have lower or higher bitrate/quality.
+			OAOggVorbisWriter writer;
+			writer.open(writeCallback, info.sampleRate, info.bitDepth, info.numChannels);
+
+			writer.write(sampleBuffer, info.numSamples);
+			writer.close();
+
+			bs_free(sampleBuffer);
+			bufferSize = totalEncodedSize;
+
+			sampleBuffer = (UINT8*)bs_alloc(bufferSize);
+			UINT32 offset = 0;
+			for(auto& block : blocks)
+			{
+				memcpy(sampleBuffer + offset, block.data, block.size);
+				offset += block.size;
+
+				bs_frame_free(block.data);
+			}
+
+			bs_frame_clear();
 		}
 		}
 
 
-		return nullptr;
+		SPtr<MemoryDataStream> sampleStream = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, bufferSize);
+
+		AUDIO_CLIP_DESC clipDesc;
+		clipDesc.bitDepth = info.bitDepth;
+		clipDesc.format = clipIO->getFormat();
+		clipDesc.frequency = info.sampleRate;
+		clipDesc.numChannels = info.numChannels;
+		clipDesc.readMode = clipIO->getReadMode();
+
+		SPtr<AudioClip> clip = AudioClip::_createPtr(sampleStream, info.numSamples, clipDesc);
+
+		WString fileName = filePath.getWFilename(false);
+		clip->setName(fileName);
+
+		return clip;
 	}
 	}
 }
 }

+ 57 - 7
Source/BansheeOpenAudio/Source/BsOAOggVorbisWriter.cpp

@@ -16,7 +16,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	OAOggVorbisWriter::OAOggVorbisWriter()
 	OAOggVorbisWriter::OAOggVorbisWriter()
-		:mBufferOffset(0), mNumChannels(0)
+		:mBufferOffset(0), mNumChannels(0), mBitDepth(0)
 	{ }
 	{ }
 
 
 	OAOggVorbisWriter::~OAOggVorbisWriter()
 	OAOggVorbisWriter::~OAOggVorbisWriter()
@@ -24,9 +24,11 @@ namespace BansheeEngine
 		close();
 		close();
 	}
 	}
 
 
-	bool OAOggVorbisWriter::open(std::function<void(UINT8*, UINT32)> writeCallback, UINT32 sampleRate, UINT32 numChannels)
+	bool OAOggVorbisWriter::open(std::function<void(UINT8*, UINT32)> writeCallback, UINT32 sampleRate, UINT32 bitDepth, 
+		UINT32 numChannels)
 	{
 	{
 		mNumChannels = numChannels;
 		mNumChannels = numChannels;
+		mBitDepth = bitDepth;
 		mWriteCallback = writeCallback;
 		mWriteCallback = writeCallback;
 
 
 		ogg_stream_init(&mOggState, std::rand());
 		ogg_stream_init(&mOggState, std::rand());
@@ -79,16 +81,64 @@ namespace BansheeEngine
 		UINT32 numFrames = numSamples / mNumChannels;
 		UINT32 numFrames = numSamples / mNumChannels;
 		float** buffer = vorbis_analysis_buffer(&mVorbisState, numFrames);
 		float** buffer = vorbis_analysis_buffer(&mVorbisState, numFrames);
 
 
-		for (UINT32 i = 0; i < numFrames; i++)
+		if (mBitDepth == 8)
 		{
 		{
-			for (UINT32 j = 0; j < mNumChannels; j++)
+			for (UINT32 i = 0; i < numFrames; i++)
 			{
 			{
-				float encodedSample = *samples / 32767.0f;
-				buffer[j][i] = encodedSample;
+				for (UINT32 j = 0; j < mNumChannels; j++)
+				{
+					INT8 sample = *(INT8*)samples;
+					float encodedSample = sample / 127.0f;
+					buffer[j][i] = encodedSample;
+
+					samples++;
+				}
+			}
+		}
+		else if (mBitDepth == 16)
+		{
+			for (UINT32 i = 0; i < numFrames; i++)
+			{
+				for (UINT32 j = 0; j < mNumChannels; j++)
+				{
+					INT16 sample = *(INT16*)samples;
+					float encodedSample = sample / 32767.0f;
+					buffer[j][i] = encodedSample;
 
 
-				samples++;
+					samples++;
+				}
+			}
+		}
+		else if (mBitDepth == 24)
+		{
+			for (UINT32 i = 0; i < numFrames; i++)
+			{
+				for (UINT32 j = 0; j < mNumChannels; j++)
+				{
+					INT32 sample = (*(INT32*)samples) & 0x00FFFFFF;
+					float encodedSample = sample / 8388607.0f;
+					buffer[j][i] = encodedSample;
+
+					samples++;
+				}
+			}
+		}
+		else if (mBitDepth == 32)
+		{
+			for (UINT32 i = 0; i < numFrames; i++)
+			{
+				for (UINT32 j = 0; j < mNumChannels; j++)
+				{
+					INT32 sample = *(INT32*)samples;
+					float encodedSample = sample / 2147483647.0f;
+					buffer[j][i] = encodedSample;
+
+					samples++;
+				}
 			}
 			}
 		}
 		}
+		else
+			assert(false);
 
 
 		// Signal how many frames were written
 		// Signal how many frames were written
 		vorbis_analysis_wrote(&mVorbisState, numFrames);
 		vorbis_analysis_wrote(&mVorbisState, numFrames);

+ 2 - 2
Source/BansheeUtility/Include/BsMemStack.h

@@ -262,7 +262,7 @@ namespace BansheeEngine
 	 */
 	 */
 
 
 	/** @copydoc MemStackInternal::alloc() */
 	/** @copydoc MemStackInternal::alloc() */
-	BS_UTILITY_EXPORT inline void* bs_stack_alloc(UINT32 amount)
+	inline void* bs_stack_alloc(UINT32 amount)
 	{
 	{
 		return (void*)MemStack::alloc(amount);
 		return (void*)MemStack::alloc(amount);
 	}
 	}
@@ -351,7 +351,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	/** @copydoc MemStackInternal::dealloc() */
 	/** @copydoc MemStackInternal::dealloc() */
-	BS_UTILITY_EXPORT inline void bs_stack_free(void* data)
+	inline void bs_stack_free(void* data)
 	{
 	{
 		return MemStack::deallocLast((UINT8*)data);
 		return MemStack::deallocLast((UINT8*)data);
 	}
 	}