/*
 *  MSample.h
 *  MSE
 *
 *  Created by Hawk on 10/16/09.
 *  Copyright 2009 Maizesoft. All rights reserved.
 *
 */
#pragma once
#include "MSoundFile.h"

//memory sample and disk streaming sample

struct MSE_SampleProperty
{
	int rootNote;
	MSE_Rect range;
	MSE_SampleLoopType loopType;
	//must call UpdateSampleRange() after changing the following
	//these 8 byte frames must be aligned
	MSE_Frame startSample, endSample;
	MSE_Frame startLoop, endLoop;
	//must call UpdateProperty() after changing following
	float gain;			//dB
	float pan;			// -1 - 0 - 1
	//ADSR
	float attack;		//time in ms
	float decay;		//time in ms
	float sustain;		//dB <0
	float release;		//time in ms
	//pitch
	float tune;			//cents
	//because of different structure padding of different compiler, we should not use bool
	//sizeof(bool) = 1 but sizeof a struct must be multiple of 4, different compiler pad differently
	int staticpitch;
	int staticvelocity;
	//choke cluster, 0 means no choke
	int choke;

	int reserved[128];
};

class MInstrument;	//forward declearation
class MGroup;

class MSE_API MSample
{
public:
	MSample(MInstrument* owner, std::string& filename, FILE* compactfile = NULL, MSE_Size offset = 0);
	~MSample();
	
	//get and set
	bool IsReady();
	MSoundFile* GetSoundFile();
	
	//audio fetch
	void GetFrame(MSE_Frame pos, float* left, float* right);
	
	//property structure for fast reading and writing
	MSE_SampleProperty f_Property;
	
	//used by MSample and MDSVoice to fill the buffer with loop taking into consideration, return current file pos
	MSE_Frame FillDSBuffer(MSE_Frame start, MSE_Frame length, void* buffer);

	//calculate parameters value based on property value
	void UpdateProperty();
	//reload the head buffer if the sample start/end or loop start/end is changed
	void UpdateSampleRange();
	//used for garbage collection
	double GetLastActivityTime();

	//public parameters for voice
	float m_Acoff, m_Dcoff, m_Rcoff, m_Scoff, m_LeftPanCoff, m_RightPanCoff, m_GainCoff;
	
	//owner, must be assigned upon sample creation
	MInstrument* m_pInstrument;
	MGroup* m_pGroup;
	
protected:
	bool m_SampleReady;
	double m_LastActivityTime;
	
	MSoundFile* m_pSoundFile;
	
	//cached property for speed
	bool m_SampleIsMono;
	bool m_DiskStreaming;
	bool m_FixedPoint;
	int m_BufferSize;
	
	float* m_FloatBuffer;
	short* m_FixedBuffer;
	
	void FillMemoryBuffer();	//fill head buffer or memory buffer
	void FillHeadBuffer();
	
	MSE_Frame ReadFramesHelper(void* buffer, MSE_Frame frames, MSE_Frame offset = 0);	//helper function
};

