//	StreamingSound.h - Class which streams a sound file from disk.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#ifndef STREAMINGSOUND_H_
#define STREAMINGSOUND_H_

#include "c0xHeaders.h"

#include <stdint.h>

class SoundFileLoader;

typedef StdSharedPtr<SoundFileLoader>::type SoundFileLoaderPtr;

///	Class which streams a sound file from disk.
/*!
	Internally, the class has two separate ways of generating sound: it can
	stream a sound file from disk via a SoundFileLoader, or (if the sound
	file is short enough) it can stream the contents of a pre-loaded buffer
	held in memory.

	If streaming, you'll need to call the threadUpdate() method regularly from
	a thread separate from the audio thread to actually stream the data from
	disk.
 */
class StreamingSound
{
  public:
	///	Constructor.
	StreamingSound();
	///	Destructor.
	~StreamingSound();

	///	Writes the sound's audio to the passed-in buffer.
	void getAudio(float *buffer, int numSamples);

	///	Returns true if the sound is currently playing.
	bool getActive() const {return (fadeVal > 0.0f);};

	///	Starts the sound streaming from disk using a SoundFileLoader.
	/*!
		Note: to ensure sounds can start playing without delay, StreamingSound
		makes use of SoundFileLoader's getInitialBuffers() method. If you have
		not filled out the initial buffers, you will hit an assert when you call
		this method.

		Also note: StreamingSound assumes the buffers are stereo interleaved; if
		you only fill them with mono data you can expect things to mess up
		(i.e.: the sound will play twice as fast due to its having been read
		into two interleaved buffers).
	 */
	void startPlaying(SoundFileLoaderPtr loader);
	///	Starts the sound playing from a pre-loaded buffer.
	/*!
		\sa The other startPlaying regarding the buffer.
	 */
	void startPlaying(float *buffer, int32_t size);

	///	Stops the sound playing.
	void stopPlaying();

	///	Tells the sound to fade in (startPlaying) and out (stopPlaying), or not.
	void setFade(bool val);
	///	Sets the sound's level.
	/*!
		This will ramp to the new level to avoid clicks.
	 */
	void setLevel(float val);
	///	Sets how the sound should be panned (0->1).
	void setPan(float val);
	///	Tells the sound to loop, or not.
	void setLoop(bool val);

	///	Used to stream the audio data from disk when using a SoundFileLoader.
	/*!
		Note: You must call this regularly if you're using a SoundFileLoader.
	 */
	void threadUpdate();

	///	The size of the buffers we use for streaming.
	enum
	{
		BufferSize = 11025,
		NumBuffers = 3
	};
  private:
	///	The SoundFileLoader used to fill streamingBuffers.
	SoundFileLoaderPtr soundFileLoader;
	///	The streaming buffers (stereo interleaved).
	float streamingBuffers[NumBuffers][BufferSize * 2];
	///	Which streaming buffer we're currently reading from.
	int currentBuffer;
	///	Our position within the current buffer.
	int streamingPos;
	///	Which streaming buffers need re-loaded.
	bool clearedBuffers[NumBuffers];

	///	The pre-loaded buffer (if we're not using a SoundFileLoader).
	float *preLoadedBuffer;
	///	The size of the pre-loaded buffer.
	int32_t preLoadedSize;

	///	Our position within the file (in samples, doesn't account for the stereo nature of the buffers).
	/*!
		This is used by threadUpdate(). Don't touch it in getAudio().
	 */
	int64_t position;
	///	Our sample position in the file (getAudio()'s version).
	int64_t readPos;
	///	Whether we're looping.
	bool loop;

	///	The sound's level.
	float level;
	///	The sound's intended level (so we can ramp when the level changes).
	float newLevel;
	///	How the sound is panned.
	float pan;

	///	If we fade in and out on sound start/stop.
	bool fade;
	///	For fading in/out.
	float fadeVal;
	///	If we're fading in (false) or fading out (true).
	bool fadeDir;
};

#endif
