Browse Source

FMOD AudioSource implemented

BearishSun 9 years ago
parent
commit
5905d66869

+ 6 - 7
Source/BansheeCore/Include/BsAudioSource.h

@@ -72,7 +72,7 @@ namespace BansheeEngine
 		 * might get disabled. By setting a higher priority the audio source is guaranteed to be disabled after sources
 		 * with lower priority.
 		 */
-		virtual void setPriority(UINT32 priority);
+		virtual void setPriority(INT32 priority);
 
 		/**
 		 * Gets the priority of the audio source. 
@@ -107,13 +107,13 @@ namespace BansheeEngine
 		float getAttenuation() const { return mAttenuation; }
 
 		/** Starts playing the currently assigned audio clip. */
-		virtual void play();
+		virtual void play() = 0;
 
 		/** Pauses the audio playback. */
-		virtual void pause();
+		virtual void pause() = 0;
 
 		/** Stops audio playback, rewinding it to the start. */
-		virtual void stop();
+		virtual void stop() = 0;
 
 		/**
 		 * Sets the time at which playback will begin.
@@ -130,7 +130,7 @@ namespace BansheeEngine
 		virtual float getTime() const = 0;
 
 		/** Returns the current state of the audio playback (playing/paused/stopped). */
-		AudioSourceState getState() const { return mState; }
+		virtual AudioSourceState getState() const = 0;
 
 		/** Creates a new audio source. */
 		static SPtr<AudioSource> create();
@@ -144,10 +144,9 @@ namespace BansheeEngine
 		float mVolume;
 		float mPitch;
 		bool mLoop;
-		UINT32 mPriority;
+		INT32 mPriority;
 		float mMinDistance;
 		float mAttenuation;
-		AudioSourceState mState;
 	};
 
 	/** @} */

+ 3 - 18
Source/BansheeCore/Source/BsAudioSource.cpp

@@ -2,12 +2,12 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsAudioSource.h"
 #include "BsAudio.h"
+#include "BsMath.h"
 
 namespace BansheeEngine
 {
 	AudioSource::AudioSource()
 		: mVolume(1.0f), mPitch(1.0f), mLoop(false), mPriority(0), mMinDistance(1.0f), mAttenuation(1.0f)
-		, mState(AudioSourceState::Stopped)
 	{
 
 	}
@@ -29,7 +29,7 @@ namespace BansheeEngine
 
 	void AudioSource::setVolume(float volume)
 	{
-		mVolume = volume;
+		mVolume = Math::clamp01(volume);
 	}
 
 	void AudioSource::setPitch(float pitch)
@@ -42,7 +42,7 @@ namespace BansheeEngine
 		mLoop = loop;
 	}
 
-	void AudioSource::setPriority(UINT32 priority)
+	void AudioSource::setPriority(INT32 priority)
 	{
 		mPriority = priority;
 	}
@@ -57,21 +57,6 @@ namespace BansheeEngine
 		mAttenuation = attenuation;
 	}
 
-	void AudioSource::play()
-	{
-		mState = AudioSourceState::Playing;
-	}
-
-	void AudioSource::pause()
-	{
-		mState = AudioSourceState::Paused;
-	}
-
-	void AudioSource::stop()
-	{
-		mState = AudioSourceState::Stopped;
-	}
-
 	SPtr<AudioSource> AudioSource::create()
 	{
 		return gAudio().createSource();

+ 3 - 0
Source/BansheeFMOD/Include/BsFMODAudioClip.h

@@ -25,6 +25,9 @@ namespace BansheeEngine
 		 */
 		FMOD::Sound* createStreamingSound() const;
 
+		/** Returns FMOD sound representing this clip. Only valid for non-streaming clips. */
+		FMOD::Sound* getSound() const { return mSound; }
+
 	protected:
 		/** @copydoc Resource::initialize */
 		void initialize() override;

+ 18 - 7
Source/BansheeFMOD/Include/BsFMODAudioSource.h

@@ -4,6 +4,7 @@
 
 #include "BsFMODPrerequisites.h"
 #include "BsAudioSource.h"
+#include "BsFMODAudio.h"
 
 namespace BansheeEngine
 {
@@ -37,13 +38,7 @@ namespace BansheeEngine
 		void setIsLooping(bool loop) override;
 
 		/** @copydoc AudioSource::setPriority */
-		void setPriority(UINT32 priority) override;
-
-		/** @copydoc AudioSource::setMinDistance */
-		void setMinDistance(float distance) override;
-
-		/** @copydoc AudioSource::setAttenuation */
-		void setAttenuation(float attenuation) override;
+		void setPriority(INT32 priority) override;
 
 		/** @copydoc AudioSource::setTime */
 		void setTime(float setTime) override;
@@ -59,6 +54,22 @@ namespace BansheeEngine
 
 		/** @copydoc AudioSource::stop */
 		void stop() override;
+
+		/** @copydoc AudioSource::getState */
+		AudioSourceState getState() const override;
+
+	private:
+		friend class FMODAudio;
+
+		/** Pauses or resumes audio playback due to the global pause setting. */
+		void setGlobalPause(bool pause);
+
+		FMOD::Channel* mChannel;
+		FMOD::Sound* mStreamingSound;
+
+		float mTime;
+		bool mGloballyPaused;
+		AudioSourceState mGlobalUnpauseState;
 	};
 
 	/** @} */

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

@@ -28,9 +28,12 @@ namespace BansheeEngine
 	float F_CALLBACK FMOD3DRolloff(FMOD_CHANNELCONTROL* channelControl, float distance)
 	{
 		FMODAudioSource* source = nullptr;
-		FMOD::Channel* channel = (FMOD::Channel*)channelControl;
+		FMOD::ChannelControl* channel = (FMOD::ChannelControl*)channelControl;
 		channel->getUserData((void**)&source);
 
+		if (source == nullptr)
+			return 1.0f;
+
 		// Calculate standard inverse rolloff, but use different attenuation per source (also ignore max distance)
 		float minDistance = source->getMinDistance();
 		float attenuation = source->getAttenuation();

+ 9 - 6
Source/BansheeFMOD/Source/BsFMODAudioClip.cpp

@@ -44,8 +44,10 @@ namespace BansheeEngine
 		else
 			flags |= FMOD_2D;
 
-		// Load decompressed data into a sound buffer
-		if(mDesc.readMode == AudioReadMode::LoadDecompressed || mDesc.readMode == AudioReadMode::LoadCompressed)
+		// Load data into a sound buffer
+		// TODO - Vorbis cannot be decompressed from memory by FMOD. Instead we force AudioReadMode::Stream for it.
+		if(mDesc.readMode == AudioReadMode::LoadDecompressed || 
+			(mDesc.readMode == AudioReadMode::LoadCompressed && mDesc.format != AudioFormat::VORBIS))
 		{
 			// Read all data into memory
 			SPtr<DataStream> stream;
@@ -69,9 +71,7 @@ namespace BansheeEngine
 			exInfo.cbsize = sizeof(exInfo);
 			exInfo.length = bufferSize;
 
-			// TODO - Vorbis cannot be decompressed from memory by FMOD. Instead we force AudioReadMode::Stream for it.
-			bool loadCompressed =
-				mDesc.readMode == AudioReadMode::LoadCompressed && mDesc.format != AudioFormat::VORBIS;
+			bool loadCompressed = mDesc.readMode == AudioReadMode::LoadCompressed && mDesc.format != AudioFormat::PCM;
 
 			if (loadCompressed)
 				flags |= FMOD_CREATECOMPRESSEDSAMPLE;
@@ -119,6 +119,9 @@ namespace BansheeEngine
 		String pathStr;
 		if(mStreamData->isFile())
 		{
+			exInfo.length = mStreamSize;
+			exInfo.fileoffset = mStreamOffset;
+
 			SPtr<FileDataStream> fileStream = std::static_pointer_cast<FileDataStream>(mStreamData);
 			pathStr = fileStream->getPath().toString();
 
@@ -129,7 +132,7 @@ namespace BansheeEngine
 			SPtr<MemoryDataStream> memStream = std::static_pointer_cast<MemoryDataStream>(mStreamData);
 
 			flags |= FMOD_OPENMEMORY_POINT;
-			exInfo.length = (UINT32)memStream->size();
+			exInfo.length = mStreamSize;
 
 			memStream->seek(mStreamOffset);
 			streamData = (const char*)memStream->getCurrentPtr();

+ 144 - 29
Source/BansheeFMOD/Source/BsFMODAudioSource.cpp

@@ -7,109 +7,224 @@
 namespace BansheeEngine
 {
 	FMODAudioSource::FMODAudioSource()
+		: mChannel(nullptr), mStreamingSound(nullptr), mTime(0.0f), mGloballyPaused(false)
+		, mGlobalUnpauseState(AudioSourceState::Stopped)
 	{
 		gFMODAudio()._registerSource(this);
-		// TODO
 	}
 
 	FMODAudioSource::~FMODAudioSource()
 	{
 		gFMODAudio()._unregisterSource(this);
-		// TODO
+
+		if (mStreamingSound != nullptr)
+			mStreamingSound->release();
+
+		if (mChannel != nullptr)
+			mChannel->stop();
 	}
 
 	void FMODAudioSource::setClip(const HAudioClip& clip)
 	{
-		AudioSource::setClip(clip);
+		stop();
 
-		// TODO
+		AudioSource::setClip(clip);
 	}
 
 	void FMODAudioSource::setPosition(const Vector3& position)
 	{
 		AudioSource::setPosition(position);
 
-		// TODO
+		if (mChannel != nullptr)
+		{
+			FMOD_VECTOR fmodPosition = { position.x, position.y, position.z };
+			mChannel->set3DAttributes(&fmodPosition, nullptr);
+		}
 	}
 
 	void FMODAudioSource::setVelocity(const Vector3& velocity)
 	{
 		AudioSource::setVelocity(velocity);
 
-		// TODO
+		if (mChannel != nullptr)
+		{
+			FMOD_VECTOR fmodVelocity = { velocity.x, velocity.y, velocity.z };
+			mChannel->set3DAttributes(nullptr, &fmodVelocity);
+		}
 	}
 
 	void FMODAudioSource::setVolume(float volume)
 	{
 		AudioSource::setVolume(volume);
 
-		// TODO
+		if (mChannel != nullptr)
+			mChannel->setVolume(mVolume);
 	}
 
 	void FMODAudioSource::setPitch(float pitch)
 	{
 		AudioSource::setPitch(pitch);
 
-		// TODO
+		if (mChannel != nullptr)
+			mChannel->setPitch(mVolume);
 	}
 
 	void FMODAudioSource::setIsLooping(bool loop)
 	{
 		AudioSource::setIsLooping(loop);
 
-		// TODO
+		if (mChannel != nullptr)
+			mChannel->setMode(loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
 	}
 
-	void FMODAudioSource::setPriority(UINT32 priority)
+	void FMODAudioSource::setPriority(INT32 priority)
 	{
 		AudioSource::setPriority(priority);
 
-		// TODO
+		if (mChannel != nullptr)
+			mChannel->setPriority(priority);
 	}
 
-	void FMODAudioSource::setMinDistance(float distance)
+	void FMODAudioSource::play()
 	{
-		AudioSource::setMinDistance(distance);
-
-		// TODO
+		mGlobalUnpauseState = AudioSourceState::Playing;
+
+		if (mGloballyPaused)
+			return;
+
+		if (!mAudioClip.isLoaded())
+			return;
+
+		if (mChannel == nullptr)
+		{
+			assert(mStreamingSound == nullptr);
+
+			FMOD::System* fmod = gFMODAudio()._getFMOD();
+			
+			FMODAudioClip* fmodClip = static_cast<FMODAudioClip*>(mAudioClip.get());
+			FMOD::Sound* sound;
+			if(mAudioClip->getReadMode() == AudioReadMode::Stream)
+			{
+				mStreamingSound = fmodClip->createStreamingSound();
+				sound = mStreamingSound;
+			}
+			else
+			{
+				sound = fmodClip->getSound();
+			}
+			
+			if(fmod->playSound(sound, nullptr, true, &mChannel) != FMOD_OK)
+			{
+				LOGERR("Failed playing sound.");
+
+				if (mStreamingSound != nullptr)
+				{
+					mStreamingSound->release();
+					mStreamingSound = nullptr;
+				}
+
+				return;
+			}
+
+			mChannel->setUserData(this);
+			mChannel->setVolume(mVolume);
+			mChannel->setPitch(mVolume);
+			mChannel->setMode(mLoop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
+			mChannel->setPriority(mPriority);
+			mChannel->setPosition((UINT32)(mTime * 1000.0f), FMOD_TIMEUNIT_MS);
+
+			FMOD_VECTOR fmodPosition = { mPosition.x, mPosition.y, mPosition.z };
+			FMOD_VECTOR fmodVelocity = { mVelocity.x, mVelocity.y, mVelocity.z };
+			mChannel->set3DAttributes(&fmodPosition, &fmodVelocity);
+		}
+			
+		mChannel->setPaused(false);
 	}
 
-	void FMODAudioSource::setAttenuation(float attenuation)
+	void FMODAudioSource::pause()
 	{
-		AudioSource::setAttenuation(attenuation);
+		mGlobalUnpauseState = AudioSourceState::Paused;
 
-		// TODO
+		if (mChannel != nullptr)
+			mChannel->setPaused(true);
 	}
 
-	void FMODAudioSource::play()
+	void FMODAudioSource::stop()
 	{
-		AudioSource::play();
+		mGlobalUnpauseState = AudioSourceState::Stopped;
 
-		// TODO
+		if (mChannel != nullptr)
+		{
+			mChannel->stop();
+			mChannel = nullptr;
+		}
+
+		if(mStreamingSound != nullptr)
+		{
+			mStreamingSound->release();
+			mStreamingSound = nullptr;
+		}
+
+		mTime = 0.0f;
 	}
 
-	void FMODAudioSource::pause()
+	void FMODAudioSource::setGlobalPause(bool doPause)
 	{
-		AudioSource::pause();
+		if (mGloballyPaused == doPause)
+			return;
 
-		// TODO
+		mGloballyPaused = doPause;
+		
+		if(doPause)
+		{
+			mGlobalUnpauseState = getState();
+
+			if (getState() == AudioSourceState::Playing)
+				pause();
+		}
+		else
+		{
+			if (mGlobalUnpauseState == AudioSourceState::Playing)
+				play();
+		}
 	}
 
-	void FMODAudioSource::stop()
+	AudioSourceState FMODAudioSource::getState() const
 	{
-		AudioSource::stop();
+		if(mChannel == nullptr)
+			return AudioSourceState::Stopped;
 
-		// TODO
+		bool isPlaying = false;
+		mChannel->isPlaying(&isPlaying);
+
+		if (isPlaying)
+			return AudioSourceState::Playing;
+
+		bool isPaused = false;
+		mChannel->getPaused(&isPaused);
+		if (isPaused)
+			return AudioSourceState::Paused;
+
+		return AudioSourceState::Stopped;
 	}
 
 	void FMODAudioSource::setTime(float time)
 	{
-		// TODO
+		if (mChannel != nullptr)
+			mChannel->setPosition((UINT32)(time * 1000.0f), FMOD_TIMEUNIT_MS);
+		else
+			mTime = time;
 	}
 
 	float FMODAudioSource::getTime() const
 	{
-		// TODO
+		if(mChannel != nullptr)
+		{
+			UINT32 position = 0;
+			mChannel->getPosition(&position, FMOD_TIMEUNIT_MS);
+
+			return position / 1000.0f;
+		}
 
 		return 0.0f;
 	}

+ 5 - 1
Source/BansheeOpenAudio/Include/BsOAAudioSource.h

@@ -37,7 +37,7 @@ namespace BansheeEngine
 		void setIsLooping(bool loop) override;
 
 		/** @copydoc AudioSource::setPriority */
-		void setPriority(UINT32 priority) override;
+		void setPriority(INT32 priority) override;
 
 		/** @copydoc AudioSource::setMinDistance */
 		void setMinDistance(float distance) override;
@@ -60,6 +60,9 @@ namespace BansheeEngine
 		/** @copydoc AudioSource::stop */
 		void stop() override;
 
+		/** @copydoc AudioSource::getState */
+		AudioSourceState getState() const override { return mState; }
+
 	private:
 		friend class OAAudio;
 
@@ -98,6 +101,7 @@ namespace BansheeEngine
 
 		Vector<UINT32> mSourceIDs;
 		float mSavedTime;
+		AudioSourceState mState;
 		bool mGloballyPaused;
 
 		static const UINT32 StreamBufferCount = 3;

+ 7 - 7
Source/BansheeOpenAudio/Source/BsOAAudioSource.cpp

@@ -8,8 +8,8 @@
 namespace BansheeEngine
 {
 	OAAudioSource::OAAudioSource()
-		: mSavedTime(0.0f), mGloballyPaused(false), mStreamBuffers(), mBusyBuffers(), mStreamProcessedPosition(0)
-		, mStreamQueuedPosition(0), mIsStreaming(false)
+		: mSavedTime(0.0f), mState(AudioSourceState::Stopped), mGloballyPaused(false), mStreamBuffers(), mBusyBuffers()
+		, mStreamProcessedPosition(0), mStreamQueuedPosition(0), mIsStreaming(false)
 	{
 		gOAAudio()._registerSource(this);
 		rebuild();
@@ -101,7 +101,7 @@ namespace BansheeEngine
 			if (contexts.size() > 1) // If only one context is available it is guaranteed it is always active, so we can avoid setting it
 				alcMakeContextCurrent(contexts[i]);
 
-			alSourcef(mSourceIDs[i], AL_GAIN, volume);
+			alSourcef(mSourceIDs[i], AL_GAIN, mVolume);
 		}
 	}
 
@@ -139,7 +139,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void OAAudioSource::setPriority(UINT32 priority)
+	void OAAudioSource::setPriority(INT32 priority)
 	{
 		AudioSource::setPriority(priority);
 
@@ -178,7 +178,7 @@ namespace BansheeEngine
 
 	void OAAudioSource::play()
 	{
-		AudioSource::play();
+		mState = AudioSourceState::Playing;
 
 		if (mGloballyPaused)
 			return;
@@ -207,7 +207,7 @@ namespace BansheeEngine
 
 	void OAAudioSource::pause()
 	{
-		AudioSource::pause();
+		mState = AudioSourceState::Paused;
 
 		auto& contexts = gOAAudio()._getContexts();
 		UINT32 numContexts = (UINT32)contexts.size();
@@ -222,7 +222,7 @@ namespace BansheeEngine
 
 	void OAAudioSource::stop()
 	{
-		AudioSource::stop();
+		mState = AudioSourceState::Stopped;
 
 		auto& contexts = gOAAudio()._getContexts();
 		UINT32 numContexts = (UINT32)contexts.size();