//------------------------------------------------------------------------------
// 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_H_
#define SOUND_H_

namespace Lamp{

class SoundBuffer;
class StereoSound;
class Sound3D;
class StaticSound;
class StreamSound;
class StaticSound3D;
class StreamSound3D;

//------------------------------------------------------------------------------
/**
 * サウンド
 *
 * 状態の移り変わり。<br>
 * play()<br>
 *  statePlay　　そのまま再生<br>
 *  stateStop　　先頭に戻って再生<br>
 *  stateSuspend 一時停止した場所から再生<br>
 *  stateLost　　そのまま再生を試みる<br>
 * stop()<br>
 *  statePlay　　停止<br>
 *  stateStop　　そのまま停止<br>
 *  stateSuspend 停止<br>
 *  stateLost　　停止<br>
 * suspend()<br>
 *  statePlay　　一時停止<br>
 *  stateStop　　そのまま停止<br>
 *  stateSuspend そのまま一時停止<br>
 *  stateLost　　一時停止を試みる<br>
 * resume()<br>
 *  statePlay　　そのまま再生を試みる<br>
 *  stateStop　　そのまま停止<br>
 *  stateSuspend 再生再開<br>
 *  stateLost　　再生再開を試みる<br>
 */
class Sound{
friend class SoundManager;
friend class SoundCache;
public:
	//--------------------------------------------------------------------------
	// 優先度
	//--------------------------------------------------------------------------
	/// デフォルト優先度
	static const int priorityDefault = 0;

	/// 最高優先度
	static const int priorityMax = Limit::shortMax;

	/// 最低優先度
	static const int priorityMin = Limit::shortMin;

	//--------------------------------------------------------------------------
	// ステート
	//--------------------------------------------------------------------------
	/// ステート
	enum State{
		/// 再生中
		statePlay,
		/// 一時停止中
		stateSuspend,
		/// 停止中
		stateStop,
		/// ロスト中
		stateLost,
	};

	//--------------------------------------------------------------------------
	// フォーカス
	//--------------------------------------------------------------------------
	/// フォーカス
	enum Focus{
		/// 通常フォーカス
		focusNormal = 0,
		/// スティっキーフォーカス
		focusSticky,
		/// グローバルフォーカス
		focusGlobal,
	};

	//--------------------------------------------------------------------------
	// リセット
	//--------------------------------------------------------------------------
	/// リセットフラグ
	enum Reset{
		// Sound
		resetName				= (1),
		resetCursor				= (resetName << 1),
		resetPriority			= (resetCursor << 1),
		resetLoop				= (resetPriority << 1),
		resetLoopCursor			= (resetLoop << 1),
		resetVolume				= (resetLoopCursor << 1),
		resetFrequency			= (resetVolume << 1),
		resetFade				= (resetFrequency << 1),
		// StereoSound
		resetPan				= (resetFade << 1),
		// Sound3D
		resetPosition			= (resetPan << 1),
		resetVelocity			= (resetPosition << 1),
		resetDistance			= (resetVelocity << 1),
		resetConeDirection		= (resetDistance << 1),
		resetConeAngle			= (resetConeDirection << 1),
		resetConeOutsideVolume	= (resetConeAngle << 1),
		reset3DEnabled			= (resetConeOutsideVolume << 1),
		// Custom
		resetNone				= (0),
		resetAll				= (0xffffffff),
		resetRuntime			=
			(resetCursor | resetVolume | resetFrequency | resetFade |
			resetPan | resetPosition | resetVelocity | resetConeDirection |
			resetConeAngle | resetConeOutsideVolume | reset3DEnabled),
	};

	//--------------------------------------------------------------------------
	// 基本データ取得
	//--------------------------------------------------------------------------
	/**
	 * 名前の設定
	 * @param name 名前
	 */
	virtual void setName(const String& name) = 0;

	/**
	 * 名前の取得
	 * @return 名前
	 */
	virtual const String& getName() const = 0;

	//--------------------------------------------------------------------------
	/**
	 * サイズの取得
	 * @return サイズ
	 */
	virtual u_int getSize() const = 0;

	/**
	 * 時間の長さの取得
	 * @return 秒単位の時間の長さ
	 */
	virtual float getTimeLength() const{ return byteToTime(getSize()); }

	/**
	 * サンプル数の取得
	 * @return サンプル数
	 */
	virtual int getSample() const = 0;

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

	/**
	 * ビット数の取得
	 * @return ビット数
	 */
	virtual int getBit() const = 0;

	/**
	 * フォーカスの取得
	 * @return フォーカス
	 */
	virtual Focus getFocus() const = 0;

	/**
	 * 1サンプルのバイト数取得
	 * @return 1サンプルのバイト数
	 */
	virtual u_int getOneSampleBytes() const{
		return (getChannel() * getBit() / 8);
	}

	/**
	 * 1秒のバイト数取得
	 * @return 1秒のバイト数
	 */
	virtual u_int getOneSecondBytes() const{
		return (getSample() * getOneSampleBytes());
	}

	/**
	 * バイト数から時間への変換
	 * @param byte バイト数
	 * @return 秒単位の時間
	 */
	virtual float byteToTime(u_int byte) const{
		Assert(byte <= getSize());
		return (float)byte / (float)getOneSecondBytes();
	}

	/**
	 * 時間からバイト数への変換
	 * @return time 秒単位の時間
	 * @return バイト数
	 */
	virtual u_int timeToByte(float time) const{
		Assert((time >= 0.f) && (time < getTimeLength()));
		return (u_int)(time * getOneSecondBytes());
	}

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

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

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

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

	/**
	 * リセット
	 * @param flags リセットフラグ
	 */
	virtual void reset(Reset flags);

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

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

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

	//--------------------------------------------------------------------------
	/**
	 * 再生時間設定
	 * @param timeCursor 再生時間の秒数
	 */
	virtual void setCurrentTime(float timeCursor){
		setCursor(timeToByte(timeCursor));
	}

	/**
	 * 現在の再生時間取得
	 * @return 現在の再生時間の秒数
	 */
	virtual float getCurrentTime() const{ return byteToTime(getCursor()); }

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

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

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

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

	//--------------------------------------------------------------------------
	/**
	 * ループ位置の設定
	 * @param loopCursor ループ位置をバイト数で指定
	 */
	virtual void setLoopCursor(u_int loopCursor){
		if(loopCursor == 0){ return; }
		Assert(false);
	}

	/**
	 * ループ位置の取得
	 * @return ループ位置のバイト数
	 */
	virtual u_int getLoopCursor() const{ return 0; }

	//--------------------------------------------------------------------------
	/**
	 * ループ時間の設定
	 * @param loopTimeCursor ループ時間を秒数で指定
	 */
	virtual void setLoopTime(float loopTimeCursor){
		setLoopCursor(timeToByte(loopTimeCursor));
	}

	/**
	 * ループ時間の取得
	 * @return ループ時間の秒数
	 */
	virtual float getLoopTime() const{ return byteToTime(getLoopCursor()); }

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

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

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

	/**
	 * 周波数の取得
	 * @return 周波数
	 */
	virtual int getFrequency() const = 0;

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

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

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

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

	/**
	 * フェードの中止
	 */
	virtual void stopFade(){ fade(0.f, 0.f, 0.f); }

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

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

	/**
	 * コメントの取得
	 * @return コメント
	 */
	virtual const String& getComment() const = 0;

	/**
	 * コメントオプションの適用
	 */
	virtual void applyCommentOption();

	//--------------------------------------------------------------------------
	// その他
	//--------------------------------------------------------------------------
	/**
	 * 複製
	 * ストリームは複製できない。
	 * @return 複製されたサウンド。失敗したらNULLを返す
	 */
	virtual Sound* clone(){ return NULL; }

	/**
	 * 所有権の取得
	 * @return 所有権。falseなら誰かに所有されている
	 */
	virtual bool hasOwnership() const = 0;

	/**
	 * 文字列への変換
	 * @return 文字列
	 */
	virtual String toString() const;

	//--------------------------------------------------------------------------
	// RTTI
	//--------------------------------------------------------------------------
	/**
	 * ストリームを使用しているか
	 * @return ストリームを使用しているtrue
	 */
	virtual bool useStream() const{ return false; }

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

	/**
	 * サウンドバッファへのキャスト
	 * @return サウンドバッファ。型が違えばNULLを返す。
	 */
	virtual SoundBuffer* castSoundBuffer() const{
		if(isSoundBuffer()){ return (SoundBuffer*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * ステレオサウンドかどうか
	 * @return ステレオサウンドならtrue
	 */
	virtual bool isStereoSound() const{ return false; }

	/**
	 * ステレオサウンドへのキャスト
	 * @return ステレオサウンド。型が違えばNULLを返す。
	 */
	virtual StereoSound* castStereoSound() const{
		if(isStereoSound()){ return (StereoSound*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * 3Dサウンドかどうか
	 * @return 3Dサウンドならtrue
	 */
	virtual bool isSound3D() const{ return false; }

	/**
	 * 3Dサウンドへのキャスト
	 * @return 3Dサウンド。型が違えばNULLを返す。
	 */
	virtual Sound3D* castSound3D() const{
		if(isSound3D()){ return (Sound3D*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * 静的サウンドかどうか
	 * @return 静的サウンドならtrue
	 */
	virtual bool isStaticSound() const{ return false; }

	/**
	 * 静的サウンドへのキャスト
	 * @return 静的サウンド。型が違えばNULLを返す。
	 */
	virtual StaticSound* castStaticSound() const{
		if(isStaticSound()){ return (StaticSound*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * ストリームサウンドかどうか
	 * @return ストリームサウンドならtrue
	 */
	virtual bool isStreamSound() const{ return false; }

	/**
	 * ストリームサウンドへのキャスト
	 * @return ストリームサウンド。型が違えばNULLを返す。
	 */
	virtual StreamSound* castStreamSound() const{
		if(isStreamSound()){ return (StreamSound*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * 静的3Dサウンドかどうか
	 * @return 静的3Dサウンドならtrue
	 */
	virtual bool isStaticSound3D() const{ return false; }

	/**
	 * 静的3Dサウンドへのキャスト
	 * @return 静的3Dサウンド。型が違えばNULLを返す。
	 */
	virtual StaticSound3D* castStaticSound3D() const{
		if(isStaticSound3D()){ return (StaticSound3D*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * ストリーム3Dサウンドかどうか
	 * @return ストリーム3Dサウンドならtrue
	 */
	virtual bool isStreamSound3D() const{ return false; }

	/**
	 * ストリーム3Dサウンドへのキャスト
	 * @return ストリーム3Dサウンド。型が違えばNULLを返す。
	 */
	virtual StreamSound3D* castStreamSound3D() const{
		if(isStreamSound3D()){ return (StreamSound3D*)this; }
		return NULL;
	}

	//--------------------------------------------------------------------------
	/**
	 * ボリュームデシベル変換
	 * @param volume ボリューム
	 * @return デシベル
	 */
	static int volumeToDecibel(float volume);

	/**
	 * デシベルボリューム変換
	 * @param decibel デシベル
	 * @return ボリューム
	 */
	static float decibelToVolume(int decibel);

protected:
	//--------------------------------------------------------------------------
	// 生成、破棄
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 */
	Sound();

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

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

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

private:
	//--------------------------------------------------------------------------
	// コピーコンストラクタの隠蔽
	Sound(const Sound& copy);

	// 代入コピーの隠蔽
	void operator =(const Sound& copy);

};

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