#include "ofSoundPlayer.h"		



// these are global functions, that affect every sound / channel:
// ------------------------------------------------------------		
// ------------------------------------------------------------		

bool bUseSpectrum = false;
float fftValues[512];	// max # bands is 512

//--------------------
void ofSoundStopAll(){
	FSOUND_StopSound(FSOUND_ALL);
}

//--------------------
void ofSoundSetVolume(float vol){
	FSOUND_SetVolume(FSOUND_ALL, (int)(vol*255.0f));
}

//--------------------
void ofSoundSetUseSpectrum(bool use){
	bUseSpectrum = use;
	FSOUND_DSP_SetActive( FSOUND_DSP_GetFFTUnit( ), bUseSpectrum);
}	

//--------------------
float * ofSoundGetSpectrum(int nBands){
	
	// ------------------------------------
	// [note] this code snippet comes from:
	// http://qepsilon.org/doc/snd__main_8cpp-source.html
	// via gamedev.net forum
	// ------------------------------------
	
	if (nBands > 512){
		printf("error in ofSoundGetSpectrum, the maximum number of bands is 512 - you asked for %i\nwe will return 512\n", nBands);
		nBands = 512;
	}

	// now, get the spectrum and 
	// place it into fftValues array with the nBands requested
	// for returning:
	
	float *spectrum = FSOUND_DSP_GetSpectrum( );
    int ctr = 0;
    int FreqPerBand =  448 / nBands;
    for (int i = 0; i < nBands; i++){
        fftValues[i] = 0.0f;
        for (int j = 0; j < FreqPerBand; j++){
            fftValues[i] += spectrum[ctr++];
        }
        fftValues[i] = fftValues[i] / 1.5f;
        if (fftValues[i] > 1.0f){
            fftValues[i] = 1.0f;
        }
    }
    
    return fftValues;
    
}



// ------------------------------------------------------------		
// ------------------------------------------------------------		


// now, the individual sound player:
//------------------------------------------------------------		
ofSoundPlayer::ofSoundPlayer(){
	bLoop 			= false;
	bLoadedOk 		= false;
	channel 		= -1;				
	pan 			= 0.5f;					
	volume 			= 1.0f;
	internalFreq 	= 44100;  	
	speed 			= 1;
	bPaused 		= false;
}

//------------------------------------------------------------
void ofSoundPlayer::loadSound(char * fileName){
	
	// fmod uses IO posix internally, might have trouble
	// with unicode paths...
	// says this code:
	// http://66.102.9.104/search?q=cache:LM47mq8hytwJ:www.cleeker.com/doxygen/audioengine__fmod_8cpp-source.html+FSOUND_Sample_Load+cpp&hl=en&ct=clnk&cd=18&client=firefox-a
	// for now we use FMODs way, but we could switch if
	// there are problems:
	
	bMultiPlay = false;
	
	// [1] init fmod, if necessary
	
	initializeFmod();	
	
	// [2] try to unload any previously loaded sounds
	// & prevent user-created memory leaks
	// if they call "loadSound" repeatedly, for example
	
	unloadSound();
	
	// [3] load sound
	
	samp 	= FSOUND_Sample_Load(FSOUND_UNMANAGED, fileName, FSOUND_NORMAL, 0, 0);
	if (!samp){
		bLoadedOk = false;
	} else {
		bLoadedOk = true;
		length 	= FSOUND_Sample_GetLength(samp);
	}
}

//------------------------------------------------------------
void ofSoundPlayer::unloadSound(){
	if (bLoadedOk){
		stop();						// try to stop the sound
		FSOUND_Sample_Free(samp);  	// & free the sample
	}
}

//------------------------------------------------------------
bool ofSoundPlayer::getIsPlaying(){
	if (channel == -1 || !bLoadedOk) return false;
	return FSOUND_IsPlaying(channel);
}

//------------------------------------------------------------
float ofSoundPlayer::getSpeed(){
	return speed;
}

//------------------------------------------------------------
float ofSoundPlayer::getPan(){
	return pan;
}

//------------------------------------------------------------
void ofSoundPlayer::setVolume(float vol){
	if (getIsPlaying() == true){
		FSOUND_SetVolume(channel, (int)(vol*255.0f));
		volume = vol;
	}
}

//------------------------------------------------------------
void ofSoundPlayer::setPosition(float pct){
	if (getIsPlaying() == true){
		int sampleToBeAt = (int)(length * pct);
		FSOUND_SetCurrentPosition(channel, sampleToBeAt);
	}
}

//------------------------------------------------------------
float ofSoundPlayer::getPosition(){
	if (getIsPlaying() == true){
		int sampleImAt;
		sampleImAt = (int)FSOUND_GetCurrentPosition(channel);
		float pct = 0.0f;
		if (length > 0){
			pct = sampleImAt / (float)length;
		}
		return pct;
	} else {
		return 0;
	}
}

//------------------------------------------------------------
void ofSoundPlayer::setPan(float p){
	if (getIsPlaying() == true){
		FSOUND_SetPan(channel, (int)(p*255.0f));
		pan = p;
	}
}


//------------------------------------------------------------
void ofSoundPlayer::setPaused(bool bP){
	if (getIsPlaying() == true){
		FSOUND_SetPaused(channel, bP);
		bPaused = bP;
	}
}


//------------------------------------------------------------
void ofSoundPlayer::setSpeed(float spd){
	FSOUND_SetFrequency(channel, (int)(internalFreq * spd));
	speed = spd;
}


//------------------------------------------------------------
void ofSoundPlayer::setLoop(bool bLp){
	FSOUND_SetLoopMode(channel, (bLp == true) ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF);
	bLoop = bLp;
}

// ---------------------------------------------------------------------------- 
void ofSoundPlayer::setMultiPlay(bool bMp){
	bMultiPlay = bMp;		// be careful with this...
}
		
// ---------------------------------------------------------------------------- 
void ofSoundPlayer::play(){
	
	// if it's a looping sound, we should try to kill it, no?
	// or else people will have orphan channels that are looping
	if (bLoop == true){
		FSOUND_StopSound(channel);
	}
	
	// if the sound is not set to multiplay, then stop the current,
	// before we start another
	if (!bMultiPlay){
		FSOUND_StopSound(channel);
	}
	
	channel = FSOUND_PlaySound(FSOUND_FREE, samp);	
	internalFreq = FSOUND_GetFrequency(channel);
	FSOUND_SetVolume(channel, (int)(volume*255.0f));
	FSOUND_SetPan(channel, (int)(pan*255.0f));
	FSOUND_SetPaused(channel, bPaused);
	FSOUND_SetFrequency(channel, (int)(internalFreq * speed));
	FSOUND_SetLoopMode(channel, (bLoop == true) ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF);
	
}

// ---------------------------------------------------------------------------- 
void ofSoundPlayer::stop(){
	FSOUND_StopSound(channel);
}
