Ver código fonte

8-bit PCM samples are now stored in signed format to be compatible with FMOD
FMOD fixes:
- Global audio pause works
- Sound buffer creation works
- Source pitch adjustment works properly

BearishSun 9 anos atrás
pai
commit
7677db2b9e

+ 1 - 2
Source/BansheeCore/Include/BsAudioClip.h

@@ -119,8 +119,7 @@ namespace BansheeEngine
 		 * @param[in]	numSamples	Total number of samples (including all channels).
 		 * @param[in]	desc		Descriptor containing meta-data for the provided samples.
 		 *
-		 * @note	If the provided samples are in PCM format, they should be unsigned for 8-bit data, and signed for
-		 *			higher bit depths.
+		 * @note	If the provided samples are in PCM format, they should be signed integers of provided bit depth.
 		 */
 		static HAudioClip create(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples,
 			const AUDIO_CLIP_DESC& desc); // Note that ownership of stream is taken by the AudioClip

+ 1 - 2
Source/BansheeCore/Include/BsAudioUtility.h

@@ -45,8 +45,7 @@ namespace BansheeEngine
 		 * Converts a set of audio samples of a certain bit depth to a set of floating point samples in range [-1, 1].
 		 *
 		 * @param[in]	input		A set of input samples. Total size of the buffer should be @p numSamples *
-		 *							@p inBitDepth / 8. 8-bit samples should be unsigned, while signed samples should be
-		 *							provided for higher bit depths.
+		 *							@p inBitDepth / 8. All input samples should be signed integers.
 		 * @param[in]	inBitDepth	Size of a single sample in the @p input array, in bits.
 		 * @param[out]	output		Pre-allocated buffer to store the output samples in. Total size of the buffer should be
 		 *							@p numSamples * sizeof(float).

+ 9 - 12
Source/BansheeCore/Source/BsAudioUtility.cpp

@@ -4,11 +4,11 @@
 
 namespace BansheeEngine
 {
-	void convertToMono8(const UINT8* input, UINT8* output, UINT32 numSamples, UINT32 numChannels)
+	void convertToMono8(const INT8* input, UINT8* output, UINT32 numSamples, UINT32 numChannels)
 	{
 		for (UINT32 i = 0; i < numSamples; i++)
 		{
-			UINT16 sum = 0;
+			INT16 sum = 0;
 			for (UINT32 j = 0; j < numChannels; j++)
 			{
 				sum += *input;
@@ -77,11 +77,11 @@ namespace BansheeEngine
 		}
 	}
 
-	void convert8To32Bits(const UINT8* input, INT32* output, UINT32 numSamples)
+	void convert8To32Bits(const INT8* input, INT32* output, UINT32 numSamples)
 	{
 		for (UINT32 i = 0; i < numSamples; i++)
 		{
-			INT8 val = (INT8)(input[i] - 128);
+			INT8 val = input[i];
 			output[i] = val << 24;
 		}
 	}
@@ -104,10 +104,7 @@ namespace BansheeEngine
 	void convert32To8Bits(const INT32* input, UINT8* output, UINT32 numSamples)
 	{
 		for (UINT32 i = 0; i < numSamples; i++)
-		{
-			INT8 val = (INT8)(input[i] >> 24);
-			output[i] = (UINT8)(val + 128);
-		}
+			output[i] = (INT8)(input[i] >> 24);
 	}
 
 	void convert32To16Bits(const INT32* input, INT16* output, UINT32 numSamples)
@@ -130,7 +127,7 @@ namespace BansheeEngine
 		switch (bitDepth)
 		{
 		case 8:
-			convertToMono8(input, output, numSamples, numChannels);
+			convertToMono8((INT8*)input, output, numSamples, numChannels);
 			break;
 		case 16:
 			convertToMono16((INT16*)input, (INT16*)output, numSamples, numChannels);
@@ -163,7 +160,7 @@ namespace BansheeEngine
 		switch (inBitDepth)
 		{
 		case 8:
-			convert8To32Bits(input, srcBuffer, numSamples);
+			convert8To32Bits((INT8*)input, srcBuffer, numSamples);
 			break;
 		case 16:
 			convert16To32Bits((INT16*)input, srcBuffer, numSamples);
@@ -211,8 +208,8 @@ namespace BansheeEngine
 		{
 			for (UINT32 i = 0; i < numSamples; i++)
 			{
-				UINT8 sample = *input;
-				output[i] = sample / 255.0f;
+				INT8 sample = *(INT8*)input;
+				output[i] = sample / 127.0f;
 
 				input++;
 			}

+ 2 - 1
Source/BansheeFMOD/Source/BsFMODAudio.cpp

@@ -104,7 +104,8 @@ namespace BansheeEngine
 
 		mIsPaused = paused;
 
-		// TODO - Iterate over all sound sources, pause them
+		for (auto& source : mSources)
+			source->setGlobalPause(paused);
 	}
 
 	void FMODAudio::_update()

+ 55 - 1
Source/BansheeFMOD/Source/BsFMODAudioClip.cpp

@@ -78,9 +78,36 @@ namespace BansheeEngine
 			else
 				flags |= FMOD_CREATESAMPLE;
 
+			if(mDesc.format == AudioFormat::PCM)
+			{
+				switch(mDesc.bitDepth)
+				{
+				case 8:
+					exInfo.format = FMOD_SOUND_FORMAT_PCM8;
+					break;
+				case 16:
+					exInfo.format = FMOD_SOUND_FORMAT_PCM16;
+					break;
+				case 24:
+					exInfo.format = FMOD_SOUND_FORMAT_PCM24;
+					break;
+				case 32:
+					exInfo.format = FMOD_SOUND_FORMAT_PCM32;
+					break;
+				default:
+					assert(false);
+					break;
+				}
+
+				exInfo.numchannels = mDesc.numChannels;
+				exInfo.defaultfrequency = mDesc.frequency;
+
+				flags |= FMOD_OPENRAW;
+			}
+
 			if(fmod->createSound((const char*)sampleBuffer, flags, &exInfo, &mSound) != FMOD_OK)
 			{
-				LOGERR("Failed playing sound.");
+				LOGERR("Failed creating sound.");
 			}
 			else
 			{
@@ -129,6 +156,33 @@ namespace BansheeEngine
 		else
 			flags |= FMOD_2D;
 
+		if (mDesc.format == AudioFormat::PCM)
+		{
+			switch (mDesc.bitDepth)
+			{
+			case 8:
+				exInfo.format = FMOD_SOUND_FORMAT_PCM8;
+				break;
+			case 16:
+				exInfo.format = FMOD_SOUND_FORMAT_PCM16;
+				break;
+			case 24:
+				exInfo.format = FMOD_SOUND_FORMAT_PCM24;
+				break;
+			case 32:
+				exInfo.format = FMOD_SOUND_FORMAT_PCM32;
+				break;
+			default:
+				assert(false);
+				break;
+			}
+
+			exInfo.numchannels = mDesc.numChannels;
+			exInfo.defaultfrequency = mDesc.frequency;
+
+			flags |= FMOD_OPENRAW;
+		}
+
 		FMOD::Sound* sound = nullptr;
 		FMOD::System* fmod = gFMODAudio()._getFMOD();
 		if (fmod->createSound(pathStr.c_str(), flags, &exInfo, &sound) != FMOD_OK)

+ 4 - 2
Source/BansheeFMOD/Source/BsFMODAudioSource.cpp

@@ -66,7 +66,7 @@ namespace BansheeEngine
 		AudioSource::setPitch(pitch);
 
 		if (mChannel != nullptr)
-			mChannel->setPitch(mVolume);
+			mChannel->setPitch(mPitch);
 	}
 
 	void FMODAudioSource::setIsLooping(bool loop)
@@ -177,10 +177,12 @@ namespace BansheeEngine
 		
 		if(doPause)
 		{
-			mGlobalUnpauseState = getState();
+			AudioSourceState currentState = getState();
 
 			if (getState() == AudioSourceState::Playing)
 				pause();
+
+			mGlobalUnpauseState = currentState;
 		}
 		else
 		{

+ 1 - 1
Source/BansheeOpenAudio/Include/BsOAFileReader.h

@@ -42,7 +42,7 @@ namespace BansheeEngine
 		 * @return					Number of samples that were actually read (can be less than requested if the more data
 		 *							in the stream).
 		 *
-		 * @note 8-bit sample data is returned as unsigned values, while higher bit-depth all use signed values.
+		 * @note All values are returned as signed values.
 		 */
 		virtual UINT32 read(UINT8* samples, UINT32 numSamples) = 0;
 

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

@@ -54,8 +54,7 @@ namespace BansheeEngine
 		/** 
 		 * Helper method that allows you to quickly convert PCM to Ogg Vorbis data. 
 		 * 
-		 * @param[in]	samples		Buffer containing samples in PCM format. 8-bit samples should be unsigned, but higher
-		 *							bit depths signed.
+		 * @param[in]	samples		Buffer containing samples in PCM format. All samples should be in signed integer format.
 		 * @param[in]	info		Meta-data describing the provided samples.
 		 * @param[out]	size		Number of bytes written to the output buffer.
 		 * @return					Buffer containing the encoded samples, allocated using the general allocator.

+ 28 - 0
Source/BansheeOpenAudio/Source/BsOAAudio.cpp

@@ -384,6 +384,20 @@ namespace BansheeEngine
 					bs_stack_free(sampleBuffer16);
 				}
 			}
+			else if(info.bitDepth == 8) 
+			{
+				// OpenAL expects unsigned 8-bit data, but engine stores it as signed, so convert
+				UINT32 bufferSize = info.numSamples * (info.bitDepth / 8);
+				UINT8* sampleBuffer = (UINT8*)bs_stack_alloc(bufferSize);
+
+				for(UINT32 i = 0; i < info.numSamples; i++)
+					sampleBuffer[i] = ((INT8*)samples)[i] + 128;
+
+				ALenum format = _getOpenALBufferFormat(info.numChannels, 16);
+				alBufferData(bufferId, format, sampleBuffer, bufferSize, info.sampleRate);
+
+				bs_stack_free(sampleBuffer);
+			}
 			else
 			{
 				ALenum format = _getOpenALBufferFormat(info.numChannels, info.bitDepth);
@@ -406,6 +420,20 @@ namespace BansheeEngine
 
 				bs_stack_free(sampleBuffer32);
 			}
+			else if (info.bitDepth == 8)
+			{
+				// OpenAL expects unsigned 8-bit data, but engine stores it as signed, so convert
+				UINT32 bufferSize = info.numSamples * (info.bitDepth / 8);
+				UINT8* sampleBuffer = (UINT8*)bs_stack_alloc(bufferSize);
+
+				for (UINT32 i = 0; i < info.numSamples; i++)
+					sampleBuffer[i] = ((INT8*)samples)[i] + 128;
+
+				ALenum format = _getOpenALBufferFormat(info.numChannels, 16);
+				alBufferData(bufferId, format, sampleBuffer, bufferSize, info.sampleRate);
+
+				bs_stack_free(sampleBuffer);
+			}
 			else
 			{
 				ALenum format = _getOpenALBufferFormat(info.numChannels, info.bitDepth);

+ 1 - 7
Source/BansheeOpenAudio/Source/BsOAFLACReader.cpp

@@ -92,10 +92,7 @@ namespace BansheeEngine
 				{
 					memcpy(data->output, &buffer[j][i], bytesPerSample);
 					
-					if (bytesPerSample == 1) // Due to convention, convert 8-bit samples to unsigned
-						*data->output = (UINT8)(*(INT8*)data->output + 128);
-
-						data->output += bytesPerSample;
+					data->output += bytesPerSample;
 					data->samplesToRead--;
 				}
 				else
@@ -103,9 +100,6 @@ namespace BansheeEngine
 					UINT8 sample[4];
 					memcpy(sample, &buffer[j][i], bytesPerSample);
 
-					if (bytesPerSample == 1) // Due to convention, convert 8-bit samples to unsigned
-						sample[0] = (UINT8)(*(INT8*)&sample[0] + 128);
-
 					for(UINT32 k = 0; k < bytesPerSample; k++)
 						data->overflow.push_back(sample[k]);
 				}

+ 12 - 1
Source/BansheeOpenAudio/Source/BsOAWaveReader.cpp

@@ -48,7 +48,18 @@ namespace BansheeEngine
 
 	UINT32 OAWaveReader::read(UINT8* samples, UINT32 numSamples)
 	{
-		return (UINT32)mStream->read(samples, numSamples * mBytesPerSample);
+		UINT32 numRead = (UINT32)mStream->read(samples, numSamples * mBytesPerSample);
+
+		if(mBytesPerSample == 1) // 8-bit samples are stored as unsigned, but engine convention is to store all bit depths as signed
+		{
+			for(UINT32 i = 0; i < numRead; i++)
+			{
+				INT8 val = samples[i] - 128;
+				samples[i] = *((UINT8*)&val);
+			}
+		}
+
+		return numRead;
 	}
 
 	bool OAWaveReader::parseHeader(AudioDataInfo& info)

+ 2 - 2
Source/BansheeOpenAudio/Source/BsOggVorbisWriter.cpp

@@ -94,8 +94,8 @@ namespace BansheeEngine
 				{
 					for (UINT32 j = 0; j < mNumChannels; j++)
 					{
-						UINT8 sample = *(UINT8*)samples;
-						float encodedSample = sample / 255.0f;
+						INT8 sample = *(INT8*)samples;
+						float encodedSample = sample / 127.0f;
 						buffer[j][i] = encodedSample;
 
 						samples++;