#include "CBeatAnalyzer.h"
#include "Debug.h"

CBeatAnalyzer::CBeatAnalyzer(int nSoundID, double difficultyModifier)
{
	m_nSoundID = nSoundID;
	m_dDifficultyModifier = difficultyModifier;
	m_vHistoryBuffer.clear();
	memset(m_fvLeftChannel, 0, 1024*sizeof(float));
	memset(m_fvRightChannel, 0, 1024*sizeof(float));
}

CBeatAnalyzer::~CBeatAnalyzer(void)
{
}

bool CBeatAnalyzer::IsBeat(void)
{
	CSGD_FModManager* pFM = CSGD_FModManager::GetInstance();
	

	Channel* pChannel;
	float instantEnergy = 0.0f;
	float averageEnergy = 0.0f;
	float variance = 0.0f;
	float historyMaxNum = 1/43.0f;
	float sensitivityConstant = 0;

	//CONSOLEMSG << "Retrieving channel:\n";
	pChannel = pFM->GetChannel(m_nSoundID);
	//CONSOLEMSG << "Channel retrieved:\n";
	
	//*  Compute the instant sound energy 'e' on the 1024 new samples taken in (an) and (bn) using the following formula (R1).
	bool playing;
	pChannel->getPaused( &playing );
	if(!playing)
	{
		pChannel->getSpectrum(m_fvLeftChannel, 1024, 0, FMOD_DSP_FFT_WINDOW_BLACKMAN);
		pChannel->getSpectrum(m_fvRightChannel, 1024, 1, FMOD_DSP_FFT_WINDOW_BLACKMAN);
	}
	else
	{
		memset(m_fvLeftChannel, 0, 1024*sizeof(float));
		memset(m_fvRightChannel, 0, 1024*sizeof(float));
	}
	
	//CONSOLEMSG << "Calculating the instant energy:\n";
	for(unsigned i=0; i<1024; ++i)
		instantEnergy += (m_fvLeftChannel[i] * m_fvLeftChannel[i]) + (m_fvRightChannel[i] * m_fvRightChannel[i]);
	//CONSOLEMSG << "Instant energy:  " << instantEnergy << "\n\n";

	//* Compute the average local energy <E> with (E) sound energy history buffer using formula (R3).
	//CONSOLEMSG << "Calculating the average energy:\n";
	for(std::list<float>::iterator pIter = m_vHistoryBuffer.begin(); pIter != m_vHistoryBuffer.end(); ++pIter)
		averageEnergy += *pIter * *pIter;
	averageEnergy *= historyMaxNum;
	//CONSOLEMSG << "Average energy:  " << averageEnergy << "\n\n";
	
	//* Compute the variance 'V' of the energies in (E) using the following formula:
	//CONSOLEMSG << "Calculating the variance:\n";
	for(std::list<float>::iterator pIter = m_vHistoryBuffer.begin(); pIter != m_vHistoryBuffer.end(); ++pIter)
		variance += (*pIter - averageEnergy) * (*pIter - averageEnergy);
	variance *= historyMaxNum;
	//CONSOLEMSG << "Variance:  " << variance << "\n\n";

	//  (R4)
	//* Compute the 'C' constant using a linear degression of 'C' with 'V', using a linear regression with values (R5):
	//CONSOLEMSG << "Calculating the sensitivity constant:\n";
	sensitivityConstant = (float)(((double)-0.0025714 * (double)variance) + (double)(m_dDifficultyModifier));
	//CONSOLEMSG << "Sensitiviy constant:  " << sensitivityConstant << "\n\n";
	//1.5142857 - original second paramater of the above equation - second number was 150.8142857
	//  (R6)
	//* Shift the sound energy history buffer (E) of 1 index to the right. We make room for the new energy value and flush the oldest.
    //* Pile in the new energy value 'e' at E[0].
	if(m_vHistoryBuffer.size() == 43)
	{
		m_vHistoryBuffer.push_front(instantEnergy);
		m_vHistoryBuffer.pop_back();
	}
	else
		m_vHistoryBuffer.push_front(instantEnergy);
	
	
   
	////////////////////////////////////////////////////////////////////////
	// If there's not enough samples to find an accurate beat, return
	if(m_vHistoryBuffer.size() < 43)
		return false;

	//* Compare 'e' to 'C*<E>', if superior we have a beat!
	if(instantEnergy > (sensitivityConstant * averageEnergy))
	{
		CONSOLEMSG << "We found a Beat!:\n";
		return true;
	}

	return false;
}