/*
 *  MVoice.h
 *  MSE
 *
 *  Created by Hawk on 10/23/09.
 *  Copyright 2009 Maizesoft. All rights reserved.
 *
 */

#pragma once
#include "MSample.h"

class MSE_API MVoice
{
public:
	MVoice();
	virtual ~MVoice();

	virtual bool Init(MSample* pSample, MSE_Byte note, MSE_Byte velocity, MSE_Byte ch = 0);
	
	//called by instrument processing
	virtual bool GetNextFrame(float* left, float* right);
	
	//get and set
	virtual MSample* GetSample();
	virtual bool IsLive() { return m_Live; }
	virtual bool IsReleasing() { return m_Releasing; }
	virtual void Release();
    virtual void FastRelease();
	virtual void Kill();
	virtual void Zombie();
	virtual void ClearZombie();
	virtual MSE_Byte GetNote();
	virtual MSE_Byte GetChannel();
	virtual double GetTimeStamp();
	virtual void SetTimeStamp(double ms);
	virtual bool GetNoteOffSent();
	virtual void SetNoteOffSent(bool noteoffsent);
	virtual bool IsZombie(MSE_Byte note, MSE_Byte ch);
		
protected:
	MSample* m_pSample;
	
	//cached property for speed
	bool m_SampleIsMono;
	bool m_DiskStreaming;
	bool m_FixedPoint;
	int m_BufferSize;
	MSE_ResampleQuality m_ResampleQuality;
	
	//Status
	bool m_Live;
	bool m_Releasing;
	bool m_Rising;
	bool m_NoteOffSent;		//used with sustain pedal
	double m_TimeStamp;
	bool m_Zombie;		//zombie voice will release in 1ms and then send the pending note
    bool m_FastRelease;     //release in 1ms

	//pending voice init parameters, used with zombie
	MSample* m_pPendingSample;
	MSE_Byte m_pendingNote;
	MSE_Byte m_pendingVelocity;
	MSE_Byte m_pendingCh;	//1 based ch number, 0 means omni channel

	//positions, have to use double instead of float here, otherwise pitch will drift
	double m_Increment;
	double m_StepSize;
	double m_VoicePos;
	MSE_Byte m_Note;
	MSE_Byte m_RealNote;	//the note before any glide change the note
	MSE_Byte m_Channel;		//1 based ch number, 0 means omni channel

	//ADSR
	virtual void UpdateEnvelope();
	float m_Envelope;
	float m_Velocity;
	
	//glide pitch factor
	float m_Glide, m_GlideTarget, m_GlideRamp, m_GlideTime;
	void UpdateIncrement();	//based on m_StepSize, with pitch modulation taken care
	
	//interpolate based on m_VoicePos
	virtual void Resample(double pos, float* left, float* right);
	
	//fetch sample from file or DS buffer
	virtual void GetFrameHelper(MSE_Frame pos, float* left, float* right, bool nextbuffer = false);

	float _overflowSamples[2];
};