/*
 *  tracker/PlayerMaster.h
 *
 *  Copyright 2009 Peter Barth
 *
 *  This file is part of Milkytracker.
 *
 *  Milkytracker is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Milkytracker 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*
 *  PlayerMaster.h
 *  MilkyTracker
 *
 *  Created by Peter Barth on 18.12.07.
 *
 */

#ifndef __PLAYERMASTER_H__
#define __PLAYERMASTER_H__

#include "BasicTypes.h"
#include "TrackerConfig.h"

struct TMixerSettings
{
	// Negative values means ignore 
	pp_int32 mixFreq;
	// Negative values means ignore 
	pp_int32 bufferSize;
	// Negative values means ignore 
	pp_int32 mixerVolume;
	// Negative values means ignore 
	pp_int32 mixerShift;
	// 0 = false, 1 = true, negative values means ignore 
	pp_int32 powerOfTwoCompensation;
	// 0 = none, 1 = linear, 2 = lagrange, negative values means ignore 
	pp_int32 resampler;
	// 0 = false, 1 = true, negative values means ignore 
	pp_int32 ramping;
	// NULL means ignore
	char* audioDriverName;
	// 0 means disable virtual channels, negative value means ignore
	pp_int32 numVirtualChannels;

	TMixerSettings() :
		mixFreq(-1),
		bufferSize(-1),
		mixerVolume(-1),
		mixerShift(-1),
		powerOfTwoCompensation(-1),
		resampler(-1),
		ramping(-1),
		audioDriverName(NULL),
		numVirtualChannels(-1)
	{
	}

	~TMixerSettings()
	{
		delete[] audioDriverName; 
	}

	void setAudioDriverName(const char* name)
	{
		delete[] audioDriverName; 
		if (name)
		{
			audioDriverName = new char[strlen(name)+1];
			strcpy(audioDriverName, name);
		}
		else 
			audioDriverName = NULL;
	}

	bool operator==(const TMixerSettings& source)
	{
		if (mixFreq != source.mixFreq)
			return false;

		if (bufferSize != source.bufferSize)
			return false;

		if (mixerVolume != source.mixerVolume)
			return false;

		if (mixerShift != source.mixerShift)
			return false;

		if (powerOfTwoCompensation != source.powerOfTwoCompensation)
			return false;

		if (resampler != source.resampler)
			return false;

		if (ramping != source.ramping)
			return false;

		if (numVirtualChannels != source.numVirtualChannels)
			return false;

		return strcmp(audioDriverName, source.audioDriverName) == 0;
	}
	
	bool operator!=(const TMixerSettings& source)
	{
		return !(*this == source);
	}

};

template<class Type>
class PPSimpleVector;
class PlayerController;

class PlayerMaster
{
private:
	enum 
	{
		DefaultMaxDevices = 32,
	};

	class MasterMixer* mixer;
	class MasterMixerNotificationListener* listener;
	PPSimpleVector<PlayerController>* playerControllers;
	
	TMixerSettings currentSettings;
	
	pp_uint32 oldBufferSize;
	bool forcePowerOfTwoBufferSize;

	pp_uint8 panning[TrackerConfig::MAXCHANNELS];

	bool multiChannelKeyJazz;
	bool multiChannelRecord;
	
	void adjustSettings();
	void applySettingsToPlayerController(PlayerController& playerController, const TMixerSettings& settings);
	
public:
	PlayerMaster(pp_uint32 numDevices = DefaultMaxDevices);
	~PlayerMaster();
	
	static const char* getPreferredAudioDriverID();
	static pp_uint32 getPreferredSampleRate();
	static pp_uint32 getPreferredBufferSize();
	static pp_int32 roundToNearestPowerOfTwo(pp_int32 v);	
	static float convertBufferSizeToMillis(pp_uint32 sampleRate, pp_uint32 bufferSize);

	PlayerController* createPlayerController(bool fakeScopes);
	bool destroyPlayerController(PlayerController* playerController);	
	
	pp_int32 getNumPlayerControllers() const;
	PlayerController* getPlayerController(pp_int32 index);
	
	// Delegating some player functionality
	bool applyNewMixerSettings(const TMixerSettings& settings, bool allowMixerRestart);
	
	// Delegating some audio driver enumeration code
	const char* getFirstDriverName() const;
	const char* getNextDriverName() const;
	const char* getCurrentDriverName() const;
	bool setCurrentDriverByName(const char* name);
	
	// this will be delegated to all playercontrollers
	void reallocateChannels(pp_int32 moduleChannels = 32, pp_int32 virtualChannels = 0);
	void setUseVirtualChannels(bool useVirtualChannels);

	// see above
	void setMultiChannelKeyJazz(bool b);
	void setMultiChannelRecord(bool b);
	
	bool start();
	bool stop(bool detachPlayers);
	
	void getCurrentSamplePeak(pp_int32& left, pp_int32& right);
	
	void resetQueuedPositions();
	
	friend class MasterMixerNotificationListener;
};

#endif
