//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * サウンドバッファヘッダ
 * @author Junpee
 */

#ifndef SOUND_BUFFER_H_
#define SOUND_BUFFER_H_

#include <Sound/System/Sound.h>
#include <Core/Utility/Timer.h>

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * サウンドバッファ
 */
class SoundBuffer : public Sound{
friend class StreamPlayer;
public:
	//--------------------------------------------------------------------------
	// 基本データ取得
	//--------------------------------------------------------------------------
	/**
	 * 名前の設定
	 * @param name 名前
	 */
	virtual void setName(const String& name){ name_ = name; }

	/**
	 * 名前の取得
	 * @return 名前
	 */
	virtual const String& getName() const{ return name_; }

	//--------------------------------------------------------------------------
	/**
	 * サイズの取得
	 * @return サイズ
	 */
	virtual u_int getSize() const{ return size_; }

	/**
	 * サンプル数の取得
	 * @return サンプル数
	 */
	virtual int getSample() const{ return sample_; }

	/**
	 * チャンネル数の取得
	 * @return チャンネル数
	 */
	virtual int getChannel() const{ return channel_; }

	/**
	 * ビット数の取得
	 * @return ビット数
	 */
	virtual int getBit() const{ return bit_; }

	/**
	 * フォーカスの取得
	 * @return フォーカス
	 */
	virtual Focus getFocus() const{ return focus_; }

	/**
	 * バッファサイズの取得
	 * @return バッファサイズ
	 */
	virtual u_int getBufferSize() const{ return size_; }

	//--------------------------------------------------------------------------
	// 再生
	//--------------------------------------------------------------------------
	/**
	 * 再生
	 * @return 正常に再生されればtrue
	 */
	virtual bool play();

	/**
	 * 停止
	 */
	virtual void stop();

	/**
	 * 再生の一時停止
	 */
	virtual void suspend();

	/**
	 * 再生再開
	 * @return 正常に再生が再開されればtrue
	 */
	virtual bool resume();

	/**
	 * 状態の取得
	 */
	virtual State getState() const;

	//--------------------------------------------------------------------------
	// 再生位置
	//--------------------------------------------------------------------------
	/**
	 * 再生位置設定
	 * @param cursor 再生位置のバイト数
	 */
	virtual void setCursor(u_int cursor);

	/**
	 * 再生位置取得
	 * @return 再生位置のバイト数
	 */
	virtual u_int getCursor() const;

	//--------------------------------------------------------------------------
	// 優先度
	//--------------------------------------------------------------------------
	/**
	 * 優先度の設定
	 *
	 * 優先度は次回再生時に適用される
	 * @param priority 優先度を32767〜-32768の間で指定
	 */
	virtual void setPriority(int priority){
		Assert(priority <= priorityMax);
		Assert(priority >= priorityMin);
		priority_ = priority;
	}

	/**
	 * 優先度の取得
	 * @return 32767〜-32768の間の値を持つ優先度
	 */
	virtual int getPriority() const{ return priority_; }

	//--------------------------------------------------------------------------
	// ループ
	//--------------------------------------------------------------------------
	/**
	 * ループの設定
	 *
	 * ループは次回再生時に適用される
	 * @param loop ループするならtrue
	 */
	virtual void setLoop(bool loop){ loop_ = loop; }

	/**
	 * ループしているか
	 * @return ループしているならtrue
	 */
	virtual bool isLoop() const{ return loop_; }

	//--------------------------------------------------------------------------
	// ボリューム
	//--------------------------------------------------------------------------
	/**
	 * ボリュームの設定
	 * @param volume ボリュームを1.fから0.fで設定する
	 */
	virtual void setVolume(float volume);

	/**
	 * ボリュームの取得
	 * @return ボリュームを1.fから0.fで返す
	 */
	virtual float getVolume() const{ return volume_; }

	//--------------------------------------------------------------------------
	// 周波数
	//--------------------------------------------------------------------------
	/**
	 * 周波数の設定
	 * @param frequency 周波数
	 */
	virtual void setFrequency(int frequency);

	/**
	 * 周波数の取得
	 * @return 周波数
	 */
	virtual int getFrequency() const{ return frequency_; }

	/**
	 * オリジナル周波数の設定
	 */
	virtual void setOriginalFrequency();

	//--------------------------------------------------------------------------
	// フェード
	//--------------------------------------------------------------------------
	/**
	 * フェードイン
	 * @param millisecond フェードインにかかる時間。0を指定するとフェード中止。
	 */
	virtual void fadeIn(float millisecond){
		fade(millisecond, 0.f, 1.f);
	}

	/**
	 * フェードアウト
	 * @param millisecond フェードアウトにかかる時間。0を指定するとフェード中止。
	 */
	virtual void fadeOut(float millisecond){
		fade(millisecond, getVolume(), 0.f);
	}

	/**
	 * フェード
	 * @param millisecond フェードアウトにかかる時間。0を指定するとフェード中止。
	 * @param startVolume 開始ボリューム
	 * @param endVolume 終了ボリューム
	 */
	virtual void fade(float millisecond, float startVolume, float endVolume);

	/**
	 * フェード中かどうか
	 * @return フェード中ならtrue
	 */
	virtual bool isFading() const{ return isFading_; }

	//--------------------------------------------------------------------------
	// コメント
	//--------------------------------------------------------------------------
	/**
	 * コメントの設定
	 * @param comment コメント
	 */
	virtual void setComment(const String& comment){ comment_ = comment; }

	/**
	 * コメントの取得
	 * @return コメント
	 */
	virtual const String& getComment() const{ return comment_; }

	//--------------------------------------------------------------------------
	// その他
	//--------------------------------------------------------------------------
	/**
	 * 所有権があるか
	 * @return 所有権。falseならすでに誰かに所有されている
	 */
	virtual bool hasOwnership() const{ return ownership_; }

	//--------------------------------------------------------------------------
	// ロック
	//--------------------------------------------------------------------------
	/// ロック
	class Lock{
	friend class SoundBuffer;
	public:
		/**
		 * アドレス0の取得
		 * @return アドレス0
		 */
		void* getAddress0() const{ return address0_; }

		/**
		 * サイズ0の取得
		 * @return サイズ0
		 */
		u_int getSize0() const{ return (u_int)size0_; }

		/**
		 * アドレス1の取得
		 * @return アドレス1
		 */
		void* getAddress1() const{ return address1_; }

		/**
		 * サイズ1の取得
		 * @return サイズ1
		 */
		u_int getSize1() const{ return (u_int)size1_; }

		/**
		 * データが有効か
		 * @return データが有効ならtrueを返す
		 */
		bool isValid() const{ return (size0_ != 0); }

	private:
		/// コンストラクタ
		Lock(){ clear(); }

		/// クリア
		void clear(){
			address0_ = address1_ = NULL;
			size0_ = size1_ = 0;
		}

		// アドレス0
		void* address0_;
		// サイズ0
		u_long size0_;
		// アドレス1
		void* address1_;
		// サイズ1
		u_long size1_;
	};

	//--------------------------------------------------------------------------
	/**
	 * ロック
	 *
	 * バッファ全体をロックします。失敗した場合、Lock::isValid()がfalseを返します。
	 * @return ロックデータ
	 */
	virtual Lock& lock();

	/**
	 * ロック
	 *
	 * 失敗した場合、Lock::isValid()がfalseを返します。
	 * @param offset オフセットをバイト数で指定する
	 * @param bytes ロックするバイト数
	 * @return ロックデータ
	 */
	virtual Lock& lock(u_int offset, u_int bytes);

	/**
	 * アンロック
	 */
	virtual void unlock();

	//--------------------------------------------------------------------------
	// RTTI
	//--------------------------------------------------------------------------
	/**
	 * サウンドバッファかどうか
	 * @return サウンドバッファならtrue
	 */
	virtual bool isSoundBuffer() const{ return true; }

protected:
	//--------------------------------------------------------------------------
	// 生成、破棄
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 * @param soundBuffer サウンドバッファ
	 */
	SoundBuffer(DirectSoundBuffer* soundBuffer);

	/**
	 * デストラクタ
	 */
	virtual ~SoundBuffer();

	/**
	 * 初期化
	 * @param size サイズ
	 * @param sample サンプル数
	 * @param channel チャンネル数
	 * @param bit ビット数
	 * @param focus フォーカス
	 */
	virtual void initialize(
		u_int size, int sample, int channel, int bit, Focus focus);

	/**
	 * サウンドバッファデータのコピー
	 * @param destination コピー先サウンドバッファ
	 */
	virtual void copySoundBufferData(SoundBuffer* destination);

	//--------------------------------------------------------------------------
	/**
	 * アップデート
	 * @return アップデートが必要な処理が終了したらtrueを返す
	 */
	virtual bool update();

	//--------------------------------------------------------------------------
	// 基本データ取得
	//--------------------------------------------------------------------------
	/**
	 * サウンドバッファの取得
	 * @return サウンドバッファ
	 */
	DirectSoundBuffer* getSoundBuffer(){ return soundBuffer_; }

	//--------------------------------------------------------------------------
	/**
	 * 所有権の設定
	 * @param ownership 所有権。falseなら誰かに所有されている
	 */
	virtual void setOwnership(bool ownership){ ownership_ = ownership; }

	//--------------------------------------------------------------------------
	// 再生
	//--------------------------------------------------------------------------
	/**
	 * バッファの再生
	 * @return 成功すればtrue
	 */
	virtual bool playBuffer();

	/**
	 * バッファの停止
	 */
	virtual void stopBuffer();

	/**
	 * 再生フラグの取得
	 * @return 再生フラグ
	 */
	virtual u_int getPlayFlag() = 0;

	//--------------------------------------------------------------------------
	// 周波数
	//--------------------------------------------------------------------------
	/**
	 * バッファ周波数の取得
	 * @return バッファ周波数
	 */
	virtual int getBufferFrequency() const;

private:
	// サウンドバッファ
	DirectSoundBuffer* soundBuffer_;
	// ロック
	Lock lock_;
	// 名前
	String name_;
	// コメント
	String comment_;
	// サイズ
	u_int size_;
	// サンプル数
	int sample_;
	// チャンネル数
	int channel_;
	// ビット数
	int bit_;
	// フォーカス
	Focus focus_;
	// ボリューム
	float volume_;
	// 周波数
	int frequency_;
	// フェード開始時間
	Timer::Tick fadeStartTime_;
	// フェード期間
	float fadePeriod_;
	// フェード開始ボリューム
	float fadeStartVolume_;
	// フェード終了ボリューム
	float fadeEndVolume_;
	// 優先度
	int priority_;
	// 所有フラグ
	bool ownership_;
	// フェード中か
	bool isFading_;
	// ループ
	volatile bool loop_;
	// 一時停止
	volatile bool isSuspended_;

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of SOUND_BUFFER_H_
//------------------------------------------------------------------------------
