//------------------------------------------------------------------------------
// 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
 */

#include "LampBasic.h"
#include "Sound/System/Sound.h"
#include "Core/Utility/StringTokenizer.h"

namespace Lamp{

//------------------------------------------------------------------------------
// 生成、破棄
//------------------------------------------------------------------------------
// コンストラクタ
Sound::Sound(){
}
//------------------------------------------------------------------------------
// デストラクタ
Sound::~Sound(){
}
//------------------------------------------------------------------------------
// リセット
void Sound::reset(Reset flags){
	if((flags & resetName) != 0){ setName(""); }
	if((flags & resetCursor) != 0){ stop(); }
	if((flags & resetPriority) != 0){ setPriority(priorityDefault); }
	if((flags & resetLoop) != 0){ setLoop(false); }
	if((flags & resetLoopCursor) != 0){ setLoopCursor(0); }
	if((flags & resetVolume) != 0){ setVolume(1.f); }
	if((flags & resetFrequency) != 0){ setOriginalFrequency(); }
	if((flags & resetFade) != 0){ stopFade(); }
}
//------------------------------------------------------------------------------
// コメントオプションの適用
void Sound::applyCommentOption(){
	StringTokenizer tokenizer(getComment());
	while(tokenizer.hasMoreTokens()){
		String token = tokenizer.getNextToken();
		if(token == "-loop"){
			setLoop(true);
		}else if(token == "-loopCursor"){
			if(!tokenizer.hasMoreTokens()){ break; }
			String subToken = tokenizer.getNextToken();
			u_int cursor;
			if(!subToken.parseUInt(&cursor)){ continue; }
			setLoopCursor(cursor * getOneSampleBytes());
		}else if(token == "-loopTime"){
			if(!tokenizer.hasMoreTokens()){ break; }
			String subToken = tokenizer.getNextToken();
			float time;
			if(!subToken.parseFloat(&time)){ continue; }
			setLoopTime(time);
		}
	}
}
//------------------------------------------------------------------------------
// 文字列への変換
String Sound::toString() const{
	String result, temp;
	if(!getName().isEmpty()){ result += getName() + "  "; }

	State state = getState();
	if(state == statePlay){ result += "Play     "; }
	else if(state == stateSuspend){ result += "Suspend  "; }
	else if(state == stateStop){ result += "Stop     "; }
	else if(state == stateLost){ result += "Lost     "; }

	temp.format("Size(%7dbyte)\nLength(%6.2f/%6.2fsec)  ",
		getSize(), getCurrentTime(), getTimeLength());
	result += temp;

	temp.format("Sample(%2d)  Channel(%1d)  Bit(%2d)\n",
		getSample(), getChannel(), getBit());
	result += temp;

	if(isLoop()){
		temp.format("Loop(%6.2fsec)", getLoopTime());
		result += temp;
	}else{ result += "Once"; }

	temp.format("  Priority(%d)", getPriority());
	result += temp;

	Focus focus = getFocus();
	if(focus == focusNormal){
		result += "  Focus(Normal)\n";
	}else if(focus == focusSticky){
		result += "  Focus(Sticky)\n";
	}else if(focus == focusGlobal){
		result += "  Focus(Global)\n";
	}

	temp.format("Volume(%4.2f)  Frequency(%7dHz)\n",
		getVolume(), getFrequency());
	result += temp;
	if(!getComment().isEmpty()){ result += "Comment " + getComment() + "\n"; }
	return result;
}
//------------------------------------------------------------------------------
// ボリュームデシベル変換
int Sound::volumeToDecibel(float volume){
	Assert(volume >= 0.f);
	Assert(volume <= 1.f);
	if(volume <= 0.002f){// 0.002f以下はdbが0になる
		return DSBVOLUME_MIN;
	}
	// 10dbで人の耳に聞こえる音量が半分になるとする(エネルギーを半分にするなら6db)
	// 33.22 = -10db / log10(0.5f)、100.fはDirectSoundが1db = 100.fなので
	int db = (int)(33.22f * 100.f * Math::log10(volume));
	Assert(db <= DSBVOLUME_MAX);
	Assert(db >= DSBVOLUME_MIN);
	return db;
}
//------------------------------------------------------------------------------
// デシベルボリューム変換
float Sound::decibelToVolume(int decibel){
	Assert(decibel <= DSBVOLUME_MAX);
	Assert(decibel >= DSBVOLUME_MIN);
	if(decibel == DSBVOLUME_MIN){ return 0.f; }
	// 10dbで人の耳に聞こえる音量が半分になるとする(エネルギーを半分にするなら6db)
	// 33.22 = -10db / log10(0.5f)、100.fはDirectSoundが1db = 100.fなので
	float volume = Math::pow(10, (decibel / 33.22f / 100.f));
	return volume;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
