//	TonesSounder.h - The game's Sounder.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	This program 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.
//
//	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 General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#ifndef TONESSOUNDER_H_
#define TONESSOUNDER_H_

#include "sound/Sounder.h"

#include <vector>

///	The game's Sounder.
class TonesSounder : public Sounder
{
  public:
	///	Constructor.
	TonesSounder();
	///	Destructor.
	~TonesSounder();

	///	Called for every audio block.
	void getAudio(float *input, float *output, int numSamples);

	///	Called for each sound file resource by LoadingScreen.
	/*!
		We don't use this.
	 */
	void loadSoundFileResource(SoundFileLoaderPtr soundFileLoader) {};

	///	Triggers a note on event, returning an index to the synth voice.
	/*!
		\param rail The rail that the triggering dot is on. This is used to
		determine what frequency the note will play at.
		\param octave Which octave the note should be (1 = 1*pitch, 0.5 =
		0.5*pitch, etc.).
		\return The index of the voice assigned to this note. It can be used
		to change the voice's pitch, and issue it with a note off message.
	 */
	int noteOn(int rail, float octave);
	///	Alternative note on trigger, letting you set the frequency directly.
	int noteOn(float freq);
	///	Triggers a note off event for the indexed voice.
	/*!
		\param index The index of the voice to cancel.
		\param pitchDrop Whether to drop the voice's pitch when it's cancelled.
	 */
	void noteOff(int index, bool pitchDrop);
	///	Triggers a pitch change for the indexed voice.
	/*!
		\param index The index of the voice whose pitch needs changed.
		\param newRail The rail the calling dot is moving to. This is used to
		calculate which pitch to glissando to.
	 */
	void changePitch(int index, int newRail, float octave);
	///	Triggers a change in amplitude for the indexed voice.
	void changeAmplitude(int index, float val);

	///	Used to trigger a note at the same pitch as the indexed note.
	int createCopyNote(int index);

	///	Sets the pitches available for this synth.
	void setPitches(const std::vector<float>& p);
	///	Returns the number of pitches available.
	int getNumPitches() const {return pitches.size();};
	///	Instructs all tones to play an octave lower.
	/*!
		This is a persistent change, in addition to the temporary one
		instigated by setGlobalPitch().
	 */
	void setLowMode(bool val);

	///	Used to temporarily reduce the pitches of all Synths by an octave.
	void setGlobalPitch(float val);
  private:
	///	Struct representing a single synth voice.
	struct Synth
	{
		///	Whether this synth is currently active or not.
		bool active;

		///	The synth's frequency.
		float frequency;
		///	Which of the pitches this synth refers to.
		int pitchIndex;
		///	Which octave this synth is at.
		float octave;

		///	For the sine generation.
		float x0;
		///	For the sine generation.
		float x1;
		///	For the sine generation.
		float coeff;

		///	Used to glissando between pitches (only happens if this != coeff).
		float newCoeff;
		///	Used to glissando between pitches.
		float glissando;

		///	The sine's current amplitude.
		float amplitude;
		///	Whether it's time to fade out yet.
		bool fadeOut;
	};

	///	The maximum number of voices which may be active at any one time.
	enum
	{
		NumVoices = 128
	};

	///	The voices.
	Synth voices[NumVoices];

	///	The available pitches.
	std::vector<float> pitches;
	///	Used to temporarily reduce the pitches of all Synths by an octave.
	float globalPitch;
	///	Used to make all Synths play an octave lower.
	float lowMode;
};

#endif
