/*
 *  FMODaudio.cpp
 *  fmod_rocks2010
 *
 *	Music and Code by Peter "pdx" Drescher.
 *  Copyright 2010 twittering machine. All rights reserved.
 *
 *  Uses the FMOD Ex API to simultaneoulsy play 8 .ogg file loops
 *  containing the 8 tracks from the Rocks2010 remix ProTools session.
 *	The sounds are loaded into channels, which are then muted/unmuted
 *	according to the level mixes from the original Sidekick game.
 *
 */

#include "FMODaudio.h"

void FMODaudio::ERRCHECK(FMOD_RESULT result)
{
    if (result != FMOD_OK)
    {
        printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
        exit(-1);
    }
}

void FMODaudio::init()
{
//	Create a System object and initialize.
	result = FMOD::System_Create(&system);
    ERRCHECK(result);
	
    result = system->getVersion(&version);
    ERRCHECK(result);
	
    if (version < FMOD_VERSION)
    {
        printf("Error!  You are using an old version of FMOD %08x.  This program requires %08x\n", version, FMOD_VERSION);
    }
	
    result = system->init(32, FMOD_INIT_NORMAL, 0);
    ERRCHECK(result);
	
//  get the sounds from the resource bundle
	char		audioFileName[PATH_MAX];
	CFURLRef	urlRef;
	CFBundleRef mainBundle = CFBundleGetMainBundle();

	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("bass"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName,  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[BASS]);
    ERRCHECK(result);

	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("drums"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[DRUMS]);
    ERRCHECK(result);

	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("sweep"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[SWEEP]);
    ERRCHECK(result);

	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("ost1"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[OST1]);
    ERRCHECK(result);

	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("ost2"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[OST2]);
    ERRCHECK(result);	

	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("ost3"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[OST3]);
    ERRCHECK(result);
	
	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("gtr"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[GTR]);
    ERRCHECK(result);
	
	urlRef = CFBundleCopyResourceURL(mainBundle, CFSTR("ding"), CFSTR("ogg"), NULL);
	CFURLGetFileSystemRepresentation(urlRef, TRUE, (UInt8 *)audioFileName, PATH_MAX);
    result = system->createSound(audioFileName, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &sound[DING]);
    ERRCHECK(result);
		
//	load sounds into channels
    for (count = 0; count < 8; count++)
    {
        result = system->playSound(FMOD_CHANNEL_FREE, sound[count], true, &channel[count]);
        ERRCHECK(result);
        result = channel[count]->setPaused(false);
        ERRCHECK(result);
	}
	
//	pan settings
	channel[BASS]->setPan  (0.0f);
	channel[DRUMS]->setPan (0.3f);
	channel[SWEEP]->setPan (-0.3f);
	channel[OST1]->setPan  (-0.6f);
	channel[OST2]->setPan  (0.0f);
	channel[OST3]->setPan  (0.6f);
	channel[GTR]->setPan   (-0.8f);
	channel[DING]->setPan  (0.8f);
	
//	start with just bass (level 1)
	channel[BASS]->setMute  (false);
	channel[DRUMS]->setMute (true);
	channel[SWEEP]->setMute (true);
	channel[OST1]->setMute  (true);
	channel[OST2]->setMute  (true);
	channel[OST3]->setMute  (true);
	channel[GTR]->setMute   (true);
	channel[DING]->setMute  (true);	

}

void FMODaudio::setLevelMix(int levelNumber)
{
	switch (levelNumber)
	{
		case 1: //bass
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (true);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (true);
			break;
		}
		case 2: //bass, drums
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (true);
			break;
		}
		case 3: //bass, drums, sweep, gtr
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (false);
			channel[DING]->setMute  (true);
			break;
		}
		case 4: //bass, drums, sweep, ost2
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (false);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (true);
			break;
		}
		case 5: //bass, sweep, ost1, ost2, ding
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (true);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (false);
			channel[OST2]->setMute  (false);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (false);
			break;
		}
		case 6: //bass, sweep, ost1, ost2, ost3, ding
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (true);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (false);
			channel[OST2]->setMute  (false);
			channel[OST3]->setMute  (false);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (false);
			break;
		}
		case 7: //drums, ost1, ost2, ost3, ding
		{
			channel[BASS]->setMute  (true);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (false);
			channel[OST2]->setMute  (false);
			channel[OST3]->setMute  (false);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (false);
			break;
		}
		case 8: //drums, ost1, ost2, ost3
		{
			channel[BASS]->setMute  (true);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (false);
			channel[OST2]->setMute  (false);
			channel[OST3]->setMute  (false);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (true);
			break;
		}
		case 9: //drums, sweep, ost3, ding
		{
			channel[BASS]->setMute  (true);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (false);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (false);
			break;
		}
		case 10: //bass, drums, ost3, ding
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (false);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (false);
			break;
		}
		case 11: //bass, drums, ost1, ost3, 
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (false);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (false);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (true);
			break;
		}
		case 12: //bass, drums, gtr, ding
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (false);
			channel[DING]->setMute  (false);
			break;
		}
		case 13: //bass, drums, sweep, gtr, ding
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (false);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (false);
			channel[DING]->setMute  (false);
			break;
		}
		case 14: //bass, sweep, gtr
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (true);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (false);
			channel[DING]->setMute  (true);
			break;
		}
		case 15: //bass, sweep
		{
			channel[BASS]->setMute  (false);
			channel[DRUMS]->setMute (true);
			channel[SWEEP]->setMute (false);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (true);
			break;
		}
		default:	//all off (should never happen)
		{
			channel[BASS]->setMute  (true);
			channel[DRUMS]->setMute (true);
			channel[SWEEP]->setMute (true);
			channel[OST1]->setMute  (true);
			channel[OST2]->setMute  (true);
			channel[OST3]->setMute  (true);
			channel[GTR]->setMute   (true);
			channel[DING]->setMute  (true);
			break;
		}
	}	
}

void FMODaudio::muteChannel(int channelNumber)
{
	channel[channelNumber]->setMute(true);
}

void FMODaudio::unmuteChannel(int channelNumber)
{
	channel[channelNumber]->setMute(false);
}

FMODaudio::~FMODaudio()
{
	for (count = 0; count < 8; count++)
	{
		result = sound[count]->release();
		ERRCHECK(result);
	}

	result = system->close();
	ERRCHECK(result);
	result = system->release();
	ERRCHECK(result);
}

