// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010  Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.


/*
 * This sample shows how to initialize the audio mixer (UAudioMixer),
 * how to create a source (USource), and how to move the listener
 * (UListener).
 */


#include "nel/misc/debug.h"
#include "nel/misc/time_nl.h"
#include "nel/misc/path.h"
#include "nel/misc/vector.h"
using namespace NLMISC;

#include "nel/sound/u_audio_mixer.h"
#include "nel/sound/u_listener.h"
using namespace NLSOUND;

#include <stdio.h>

#ifndef NL_SOUND_DATA
#define NL_SOUND_DATA "."
#endif // NL_SOUND_DATA

// Pointer to the audio mixer object
UAudioMixer	*AudioMixer = NULL;


/*
 * Initialization
 */
void Init()
{
	try
	{

		CPath::addSearchPath(NL_SOUND_DATA"/data", true, false);

		/*
		 * 1. Create the audio mixer object and init it.
		 * If the sound driver cannot be loaded, an exception is thrown.
		 */
		AudioMixer = UAudioMixer::createAudioMixer();

		// Set the sample path before init, this allow the mixer to build the sample banks
		AudioMixer->setSamplePath("data/samplebank");
		// Packed sheet option, this mean we want packed sheet generated in 'data' folder
		AudioMixer->setPackedSheetOption("data", true);

		printf("Select NLSOUND Driver:\n");
		printf(" [1] FMod\n");
		printf(" [2] OpenAl\n");
		printf(" [3] DSound\n");
		printf(" [4] XAudio2\n");
		printf("> ");
		int selection = getchar();
		printf("\n");

		// init with 32 tracks, EAX enabled, no ADPCM, and activate automatic sample bank loading
		AudioMixer->init(32, true, false, NULL, true, (UAudioMixer::TDriver)(selection - '0')/*UAudioMixer::DriverFMod*/);

		/*
		 * 2. Initialize listener's position and orientation (in NeL coordinate system).
		 */
		CVector initpos ( 0.0f, 0.0f, 0.0f );
		CVector frontvec( 0.0f, 1.0f, 0.0f );
		CVector upvec( 0.0f, 0.0f, 1.0f );
		AudioMixer->getListener()->setPos( initpos );
		AudioMixer->getListener()->setOrientation( frontvec, upvec );

	}
	catch( Exception& e )
	{
		nlerror( "Error: %s", e.what() );
	}
}


/*
 * Adding a source
 */
USource *OnAddSource( const char *name, float x, float y, float z )
{
	/*
	 * Create a source with sound 'name', and set some of its initial properties, if successful
	 */
	USource *source = AudioMixer->createSource( CStringMapper::map(name) );
	if ( source != NULL )
	{
		source->setPos( CVector(x,y,z) );

		/* The initial gain, pitch and looping state are stored
		 * in the "source sounds file".
		 */
		source->setLooping(true);
		source->play(); // start playing immediately
	}
	else
	{
		nlwarning( "Sound '%s' not found", name );
	}
	return source;
}


/*
 * When moving the listener, wait for a short delay
 */
void OnMove( const CVector& listenerpos )
{
	// Move forward
	AudioMixer->getListener()->setPos( listenerpos );

	// Wait 20 ms
	TTime time = CTime::getLocalTime();
	while ( CTime::getLocalTime() < time+20 );

	/* If we used spawned sources or "envsounds" or if we had
	 * a large number of sources, we should call:
	 * AudioMixer->update();
	 */
}

/*
 * main
 *
 * Note: The NeL vector coordinate system is described as follows:
 * \verbatim
 *     (top)
 *       z
 *       |  y (front)
 *       | /
 *       -----x (right)
 * \endverbatim
 */
int main()
{
	CApplicationContext *appContext = new CApplicationContext(); // crash at end if on stack ...

	// Initialization
	Init();

	// First step: we create two sources
	printf( "Press ENTER to start playing the two sources\n" );
	printf( "One is 20 meters ahead, on the right\n" );
	printf( "The other is 5 meters ahead, on the left\n" );
	getchar();
	USource *src1 = OnAddSource( "beep", 1.0f, 20.0f, 0.0f );  // Beep on the right, 20 meters ahead
	USource *src2 = OnAddSource( "tuut", -2.0f, 5.0f, 0.0f ); // Tuut on the left, 5 meters ahead

	// Second step: we will move the listener ahead
	printf( "Press ENTER again to start moving the listener\n" );
	getchar();

	// Listener orientation is constant in this example (see initialization)

	// Move forward, then backward, twice
	CVector listenervel;
	CVector listenerpos ( 0.0f, 0.0f, 0.0f );
	for ( uint i=0; i!=2; i++ )
	{
		printf( "%u of 2\n", i+1 );

		// Forward velocity
		listenervel.set( 0.0f, 0.5f, 0.0f );
		AudioMixer->getListener()->setVelocity( listenervel );

		// Move forward: set position every frame
		printf( "Moving forward, going past the sources...\n" );
		for ( listenerpos.y=0.0f; listenerpos.y<30.0f; listenerpos.y+=0.1f )
		{
			OnMove( listenerpos );
			AudioMixer->update();
		}

		// Backward velocity
		listenervel.set( 0.0f, -0.5f, 0.0f );
		AudioMixer->getListener()->setVelocity( listenervel );

		// Move backward: set position every frame
		printf( "Moving backward, going back to the start position...\n" );
		for ( listenerpos.y=30.0f; listenerpos.y>0.0f; listenerpos.y-=0.1f )
		{
			OnMove( listenerpos );
			AudioMixer->update();
		}
	}

	// Finalization
	printf( "Press ENTER again to exit\n" );
	getchar();

	delete src1; delete src2;
	delete AudioMixer;

	delete appContext;

	return 0;
}