/*------------------------------------------------------------------------------*
 * File Name: exportWAV.c	 													*
 * Creation: Sim 04-29-2007														*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Hong 09/17/07 QA80-10381 SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED				*
 *	Hong 09/24/07 QA80-10381 v8.0707 REMOVE_VOLUMN_FACTOR						*
 *	Hong 10/10/07 v8.0721c FIX_EXPORT_FAIL_IF_ONLY_ONE_COL						*
 *	Hong 12/13/07 QA80-10820 v8.0768 FIX_GARBAGE_FILE_CONVERT_BITS				*
 *	Sim 12-13-2007 IMPROVE_CONVERT_SAMPLE_BITS									*	
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// Including the system header file Origin.h should be sufficient for most Origin
// applications and is recommended. Origin.h includes many of the most common system
// header files and is automatically pre-compiled when Origin runs the first time.
// Programs including Origin.h subsequently compile much more quickly as long as
// the size and number of other included header files is minimized. All NAG header
// files are now included in Origin.h and no longer need be separately included.
//
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h>
////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////
// Include your own header files here.
#include "exportWAV.h"
#include <..\Originlab\file_utils.h>
#include <..\Originlab\fu_utils.h>

////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.

exportWAVFile::exportWAVFile()
{
	m_strWks.Empty();
	
	m_nC1 = -1;
	m_nC2 = -1;
	//m_nCX = -1;
	
	m_Setting.Channels = 2;
	m_Setting.SamplesPerSecond = SAMPLES_44KHZ;
	m_Setting.BitsPerSample = BITS_16;
	
	m_dFactor = 1;
}
	
exportWAVFile::~exportWAVFile()
{
	if ( IsOpen() )
		Close();
}
	
////////////////////////////
// public member function
////////////////////////////
int exportWAVFile::SetBitsPerSample(WORD wBitsPerSample)// = BITS_16)
{
	switch ( wBitsPerSample )
	{
	case BITS_8: 
	case BITS_16:
	case BITS_32:
		m_Setting.BitsPerSample = wBitsPerSample;
		break;
	default:
		return INVALID_SETTING;
	}
	return SUCCEED;
}

//int exportWAVFile::SetRange(DataRange& dr)
//{
	//Worksheet wks;
//
	//int nC1,nC2;
//
	//WorksheetPage pgTarget;
	//if ( !GetRangeInfo(dr, wks, pgTarget, nC1, nC2) )
		//return INVALID_RANGE_INPUT;
	//
	//return SetRange(wks, nC1, nC2);
//}

/// Hong 09/17/07 QA80-10381 SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
/*
int exportWAVFile::SetRange(Worksheet wks, int nC1, int nC2, int nCX, int nR1, int nR2)// = -1, 0, -1
{
	// check range
	if ( !wks )
		return INVALID_RANGE_INPUT;
	
	int nNumCols = wks.GetNumCols();
	int nNumRows = wks.GetNumRows();
	
	if ( -1 == nC2 )
		nC2 = nNumCols - 1;
	if ( -1 == nR2 )
		nR2 = nNumRows - 1;
		
	bool bValidRange;
	bValidRange = ( nC1 < nNumCols && nC2 < nNumCols && nCX < nNumCols 
					&& nCX < nC1 && nC1 <= nC2 
					&& nR1 < nNumRows && nR2 < nNumRows && nR1 <= nR2 );
	if ( !bValidRange )
		return INVALID_RANGE_INPUT;	

	m_strWks = wks_get_book_sheet_name(wks);
		
	// get number of channels
	if ( nC2 - nC1 + 1 > 2 ) // not support more than 2 channels
		return INVALID_RANGE_INPUT;
	m_Setting.Channels = nC2 - nC1 + 1;

	// get number of samples
	int nMinRow = nNumRows, nMaxRow = 0;
	for (int ii = nC1; ii <= nC2; ii++)
	{
		Column col(wks,ii);
		int nRow;
		
		nRow = col.GetLowerBound();
		if ( nRow < nMinRow )
			nMinRow = nRow;
		
		nRow = col.GetUpperBound();
		if ( nRow > nMaxRow )
			nMaxRow = nRow;
	}
	if ( nMinRow > nR1 )
		nR1 = nMinRow;
	if ( nMaxRow < nR2 )
		nR2 = nMaxRow;	
	
	// get samle rate
	bool bHasValidSampleRate = false;
	//m_nCX = nCX;
	//double dX0, dInc;
	Column col;
	
	if ( nCX < 0 )
	{	// from column sample interval
		bool bNoneSampleRate = true;
		for (int ii = nC1; ii <= nC2; ii++)
		{
			double dTempX0, dTempInc;
			col = wks.Columns(ii);
			if ( col.IsEvenSampling(&dTempX0, &dTempInc) )
				bNoneSampleRate = false;
		}
		
		if ( !bNoneSampleRate ) // get sample rate from column sample interval
		{
			int nRet = GetSampleRate(wks, m_Setting.SamplesPerSecond, nC1, nC2);
			if ( nRet )
				return nRet;
			
			bHasValidSampleRate = true; // successs to load sample rate
		}
		else
		{	// not have sample interval in any column
			// auto detect x-axis column
			nCX = nC1 - 1;
			while ( nCX >= 0 )
			{
				col = wks.Columns(nCX);
				if ( OKDATAOBJ_DESIGNATION_X == col.GetType() )
					break;
				nCX--;
			}
			
			//if ( nCX < 0)
				//return INVALID_SAMPLE_RATE;
		}
	}

	if ( !bHasValidSampleRate ) 
	{	// from x-axis column
		if ( nCX >= 0 )
		{	
			col = wks.Columns(nCX);
			int nRet = GetSampleRate(col, m_Setting.SamplesPerSecond, nR1, nR2);
			if ( SUCCEED != nRet )
				return nRet;
		}
		else
			return INVALID_SAMPLE_RATE;
	}
	
	m_nC1 = nC1;
	m_nC2 = nC2;
	m_nR1 = nR1;
	m_nR2 = nR2;
	// need check row size to make sure tow column have the same length contain in DataRange
	//...
	
	return SUCCEED;
}
*/
static bool _get_sample_interval(Worksheet& wks, int nIndex, double& dX0, double& dInc)
{
	Column col(wks, nIndex);			
	if ( !col )
		return false;
	
	if ( !col.IsEvenSampling(&dX0, &dInc) )
	{
		///---Sim 12-11-2007 IMPROVE_GET_SAMPLING_INTERVAL_FROM_X_COL
		//Curve crv;
		//crv.Attach(col);	
		//
		//string strXCol;
		//if ( !crv.HasX(strXCol) )	
			//return false;			
		//
		//dX0 = 0.0;
		//Dataset ds(strXCol);		
		//int nErr = ocmath_sampling_resolution(ds.GetSize(), ds, &dInc);
		//if ( OE_NOERROR != nErr )
			//return false;	
		int nYCol = nIndex;
		int nXCol = wks.FindColIndex(nYCol , OKDATAOBJ_DESIGNATION_X);
		if ( nXCol < 0 )
			return false;
		
		Column colX(wks, nXCol);
		vectorbase& vb = colX.GetDataObject();
		if ( vb.GetSize() <= 0 )
			return false;
		
		vector vd = vb;
		dX0 = vd[0];
		int nErr = ocmath_sampling_resolution(vd.GetSize(), vd, &dInc);
		if ( OE_NOERROR != nErr )
			return false;
		///---END IMPROVE_GET_SAMPLING_INTERVAL_FROM_X_COL
	}				
	
	return true;
}

/// Hong 09/19/07 v8.0704 FIX_SAMPLE_RATE_NOT_SAVED
//static int _check_columns(Worksheet& wks, int nC1, int nC2, bool bStereo)
static int _check_columns(Worksheet& wks, int nC1, int nC2, bool bStereo, double& dIncrement)
/// end FIX_SAMPLE_RATE_NOT_SAVED
{
	if ( !wks )
		return CER_NO_WORKSHEET;
	
	double dX0, dInc;
	if ( !_get_sample_interval(wks, nC1, dX0, dInc) )
		return EXPERR_WAVE_NOT_SAMPLE_RATE;
	
	if (  dInc <= 0 )
		return EXPERR_WAV_INVALID_X_AXIS;
	
	if ( bStereo )
	{
		double dTempX0, dTempInc;
		if ( !_get_sample_interval(wks, nC2, dTempX0, dTempInc) )		
			return EXPERR_WAVE_NOT_SAMPLE_RATE;
			
		if ( dX0 != dTempX0 )
			return EXPERR_WAVE_SAMPLE_RATE_X0;
			
		if ( dInc > 0 && dTempInc != dInc )
			return EXPERR_WAVE_INCONSISTENT_SAMPLE_RATE;
	}
	
	///---Sim 12-10-2007 CHECK_SAMPLE_RATE_LIMIT
	if ( (1/dInc) < WAV_SAMPLE_RATE_MINIMUM_LIMIT )
		return EXPERR_WAV_INVALID_X_AXIS;
	///---END CHECK_SAMPLE_RATE_LIMIT
	
	dIncrement = dInc; /// Hong 09/19/07 v8.0704 FIX_SAMPLE_RATE_NOT_SAVED
	
	return CER_NO_ERROR;
}

int exportWAVFile::SetRange(Worksheet wks, int nC1, int nC2, int nR1, int nR2, BOOL bStereo)// = -1, 0, -1, FALSE
{		
	if ( !wks )
		return INVALID_RANGE_INPUT;
	
	int nNumCols = wks.GetNumCols();
	int nNumRows = wks.GetNumRows();
	
	if ( -1 == nR2 )
		nR2 = nNumRows - 1;
	
	bool bValidRange;
	/// Hong 10/10/07 v8.0721c FIX_EXPORT_FAIL_IF_ONLY_ONE_COL
	//bValidRange = ( nC1 < nNumCols && nC2 < nNumCols 
	//				&& nR1 < nNumRows && nR2 < nNumRows && nR1 <= nR2 );
	bValidRange = ( nC1 < nNumCols && nR1 < nNumRows && nR2 < nNumRows && nR1 <= nR2 );
	if ( bStereo )
		bValidRange &= (nC2 < nNumCols);
	/// end FIX_EXPORT_FAIL_IF_ONLY_ONE_COL
	if ( !bValidRange )
		return INVALID_RANGE_INPUT;			

	m_strWks = wks_get_book_sheet_name(wks);
	
	m_Setting.Channels = bStereo ? 2 : 1;
	
	Column c1(wks, nC1);
	int nMinRow = nNumRows, nMaxRow = 0, nRow;	
	nRow = c1.GetLowerBound();
	if ( nRow < nMinRow )
		nMinRow = nRow;		
	nRow = c1.GetUpperBound();
	if ( nRow > nMaxRow )
		nMaxRow = nRow;

	if ( bStereo )
	{
		Column c2(wks, nC2);

		nRow = c2.GetLowerBound();
		if ( nRow < nMinRow )
			nMinRow = nRow;		
		nRow = c2.GetUpperBound();
		if ( nRow > nMaxRow )
			nMaxRow = nRow;
	}
	
	if ( nMinRow > nR1 )
		nR1 = nMinRow;
	if ( nMaxRow < nR2 )
		nR2 = nMaxRow;
	
	int nRet = SUCCEED;
	/// Hong 09/19/07 v8.0704 FIX_SAMPLE_RATE_NOT_SAVED
	//if ( nRet = _check_columns(wks, nC1, nC2, bStereo) )
	double dInc;
	if ( nRet = _check_columns(wks, nC1, nC2, bStereo, dInc) )
	/// end FIX_SAMPLE_RATE_NOT_SAVED
		return nRet;
		
	m_Setting.SamplesPerSecond = 1 / dInc;
	
	m_nC1 = nC1;
	m_nC2 = nC2;
	m_nR1 = nR1;
	m_nR2 = nR2;
	
	return SUCCEED;
}
/// end SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED

int exportWAVFile::SetFactor(double dFactor)
{
	if ( dFactor > 1 )
		return INVALID_SETTING;
	m_dFactor = dFactor;
	return SUCCEED;
}


#define _SAFE_RETURN(_nRet) { Close(); return _nRet; }

int exportWAVFile::WriteFile(LPCSTR lpcszFileName)
{	
	if ( !CheckSetting() )
		return INVALID_SETTING;
	
	if ( !Open( lpcszFileName, file::modeCreate | file::modeWrite ) )
		return FAIL_CREATE_WAV_FILE;
	
	int nRet;
	
	if ( nRet = WriteHeader() )
		_SAFE_RETURN(nRet);
	
	if ( nRet = WriteChunks() )
		_SAFE_RETURN(nRet);
	
	_SAFE_RETURN(SUCCEED) ;		
}

////////////////////////////
// private member function
////////////////////////////
int exportWAVFile::WriteHeader()
{
	RIFFHDR rh = {RIFF_ID, 0};
	
	Write(&rh, sizeof(RIFFHDR));
	
	WAVEHDR wh = {WAVE_ID};
	
	Write(&wh, sizeof(WAVEHDR));
	
	return SUCCEED;
}
	
int exportWAVFile::WriteChunks()
{
	// write fmt
	CHUNKHDR chFmt = {RIFFCHUNK_FMT};
	chFmt.len = sizeof(FMTWAVEFORMAT);
	Write(&chFmt, sizeof(CHUNKHDR));

	int nBytePerSample = m_Setting.BitsPerSample / 8;
	
	FMTWAVEFORMAT fmt = {0};
	fmt.wFormatTag = WAVE_FORMAT_PCM;
	fmt.wChannels = m_Setting.Channels;
	fmt.dwSamplesPerSec = m_Setting.SamplesPerSecond;
	fmt.wBitsPerSample = m_Setting.BitsPerSample;
	fmt.dwAvgBytesPerSec = m_Setting.Channels * m_Setting.SamplesPerSecond * nBytePerSample;
	fmt.wBlockAlign = fmt.wChannels * nBytePerSample;
	Write(&fmt, sizeof(FMTWAVEFORMAT));
	
	// write data
	CHUNKHDR chData = {RIFFCHUNK_DATA};
	chData.len = fmt.wChannels * nBytePerSample * ( m_nR2 - m_nR1 + 1);
	Write(&chData, sizeof(CHUNKHDR));
	/// Hong 09/24/07 QA80-10381 v8.0707 REMOVE_VOLUMN_FACTOR
	//Worksheet wks(m_strWks);
	//GetMaxVolumeSource(m_dMaxVolume, wks, m_nC1, m_nC2, m_nR1, m_nR2);
	/// end REMOVE_VOLUMN_FACTOR
	
	//matrix<short> matData(m_nR2 - m_nR1 + 1, fmt.wChannels);
//
	//matData.CopyFromWks(wks, m_nC1, m_nC2, m_nR1, m_nR2);
	//
	//short* lpbyData = matData;
	//Write(lpbyData, (m_nR2 - m_nR1 + 1) * fmt.wChannels * sizeof(short) );
	switch ( nBytePerSample )
	{
	case 1:
		///---Sim 12-13-2007 IMPROVE_CONVERT_SAMPLE_BITS
		//matrix<char> matData;
		matrix<byte> matData;
		///---END IMPROVE_CONVERT_SAMPLE_BITS
		WriteSamples(matData);
		break;
	case 2:
		matrix<short> matData;
		WriteSamples(matData);
		break;
	case 4:
		// 32 bits
		matrix<int> matData;
		WriteSamples(matData);
		break;
	default:
		error_report("Unknow Sample Bits");
		break;
	}
	
	SeekToBegin();
	DWORD dwLength = GetLength();
	RIFFHDR rh = {RIFF_ID, 0};
	rh.len = dwLength - 8;
	Write(&rh, sizeof(RIFFHDR));
	
	return SUCCEED;
}

///---Sim 12-13-2007 IMPROVE_CONVERT_SAMPLE_BITS
/*
/// Hong 09/24/07 QA80-10381 v8.0707 REMOVE_VOLUMN_FACTOR
bool exportWAVFile::GetMaxVolumnByType(int nType, int& nMaxVolumn, int* pnBytesSample) // = NULL,
{
	int nBytesSample;
	switch ( nType )
	{
	///---Sim 12-13-2007 IMPROVE_CONVERT_SAMPLE_BITS
	//case FSI_CHAR: nBytesSample = 1; break;
	case FSI_BYTE: nBytesSample = 1; break;
	///---END IMPROVE_CONVERT_SAMPLE_BITS
	case FSI_SHORT: nBytesSample = 2; break;
	case FSI_LONG: nBytesSample = 4; break;
	default:
		return false;
	}
	
	nMaxVolumn = ( 1 << (8*nBytesSample - 1) ) - 1;
	
	if ( pnBytesSample )
		*pnBytesSample = nBytesSample;
	
	return true;
}
/// end REMOVE_VOLUMN_FACTOR

bool exportWAVFile::WriteSamples(matrixbase& mb)
{
	mb.SetSize(m_nR2 - m_nR1 + 1, m_Setting.Channels);
	
	Worksheet wks(m_strWks);
	matrix mat;	
	mat.SetSize(m_nR2 - m_nR1 + 1, m_Setting.Channels);	
	/// Hong 09/17/07 QA80-10381 SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	/// Hong 09/24/07 QA80-9160 v8.0707 FIX_FAIL_EXPORT_STEREO_DATA
	//mat.CopyFromWks(wks, m_nC1, m_nC2, m_nR1, m_nR2);
	mat.CopyFromWks(wks, m_nC1, m_nC1, m_nR1, m_nR2);
	/// end FIX_FAIL_EXPORT_STEREO_DATA
	//mat.CopyFromWks(wks, m_nC1, m_nC1); /// Hong 09/19/07 v8.0704 FIX_ROW_INDEX_NOT_CORRECT_FOR_MONO
	mat.SetSize(m_nR2 - m_nR1 + 1, m_Setting.Channels, TRUE);	
	if ( 2 == m_Setting.Channels )
	{
		Column col(wks, m_nC2);
		if ( !col )
			return false;
		
		vectorbase& vb = col.GetDataObject();
		vector vSub;
		vb.GetSubVector(vSub, m_nR1, m_nR2);
		mat.SetColumn(vSub, 1);
	}
	/// end SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	mat.Replace(get_missing_value(), 0);

	int nBytesSample; 
	int nType = mb.GetInternalDataType();
	/// Hong 09/24/07 QA80-10381 v8.0707 REMOVE_VOLUMN_FACTOR
	/#
	switch ( nType )
	{
	case FSI_CHAR: nBytesSample = 1; break;
	case FSI_SHORT: nBytesSample = 2; break;
	case FSI_LONG: nBytesSample = 4; break;
	default:
		return error_report(_L("Unsupported Sample Bits!"));
	}
	
	int nMaxVolumeTarget;
	nMaxVolumeTarget = ( 1 << (8*nBytesSample - 1) ) - 1;
	
	mat *= (nMaxVolumeTarget/m_dMaxVolume) * m_dFactor;
	#/
	int nMaxVolumeTarget;
	if ( !GetMaxVolumnByType(nType, nMaxVolumeTarget, &nBytesSample) )		
		return error_report(_L("Unsupported Sample Bits!"));

	int nDataType, nMaxVolumnSrc = nMaxVolumeTarget;
	vector vSub;
	/// Hong 12/13/07 QA80-10820 v8.0768 FIX_GARBAGE_FILE_CONVERT_BITS
	//nDataType = wks.Columns(m_nC1).GetInternalDataType();
	nType = wks.Columns(m_nC1).GetInternalDataType();
	/// end FIX_GARBAGE_FILE_CONVERT_BITS
	GetMaxVolumnByType(nType, nMaxVolumnSrc);
	
	mat.GetColumn(vSub, 0);
	vSub *= (nMaxVolumeTarget/(double)nMaxVolumnSrc) * m_dFactor;
	mat.SetColumn(vSub, 0);
	
	if ( WAV_CHANNEL_STEREO == m_Setting.Channels )
	{
		nType = wks.Columns(m_nC2).GetInternalDataType();
		GetMaxVolumnByType(nType, nMaxVolumnSrc);
		
		mat.GetColumn(vSub, 1);
		vSub *= (nMaxVolumeTarget/(double)nMaxVolumnSrc) * m_dFactor;
		mat.SetColumn(vSub, 1);
	}
	
	mat.ReplaceGreaterThan(nMaxVolumeTarget, nMaxVolumeTarget);
	mat.ReplaceLessThan(-nMaxVolumeTarget - 1,  -nMaxVolumeTarget - 1);
	
	// if take back m_dFactor, need recaculate m_dMaxVolume here
	/// end REMOVE_VOLUMN_FACTOR	
	mb = mat;
	
	void* lpbyData = mb;
	Write(lpbyData, (m_nR2 - m_nR1 + 1) * m_Setting.Channels * nBytesSample );
	
	return true;	
}
*/
bool exportWAVFile::GetMaxMinSample(int nDataType, int& nMax, int& nMin)
{
	if ( FSI_BYTE == nDataType )
	{
		nMax = 255;
		nMin = 0;
	}
	else
	{
		int nBytesSample = GetBytesSample(nDataType);
		if ( nBytesSample <= 0 )
			return false;
		
		nMax = ( (int)1 << (8*nBytesSample - 1) ) - 1;
		nMin = -nMax - 1;
	}
	return true;
}

int exportWAVFile::GetBytesSample(int nDataType)
{
	switch ( nDataType )
	{
	case FSI_BYTE: 
		return 1;
	case FSI_SHORT:
		return 2;
	case FSI_LONG:
		return 4;
	}
	
	return 0;
}

bool exportWAVFile::GenerateTargetChannelData(vector& vChannel, int nTargetDataType, const Column& col)
{
	if ( !col || !vChannel )
		return false;
	
	int nSrcDataType = col.GetInternalDataType();
	vectorbase& vb = col.GetDataObject();
	vb.GetSubVector(vChannel, m_nR1, m_nR2);
	
	if ( FSI_BYTE == nSrcDataType ) // 8 bits is unsigned, data 0-255 to -128-127
	{
		int nMax, nMin;
		GetMaxMinSample(nSrcDataType, nMax, nMin);
		vChannel -= (nMax+1)/2; 
	}
	
	double dFactor = pow(256, GetBytesSample(nTargetDataType) - GetBytesSample(nSrcDataType));
	vChannel *= dFactor;	
	
	if ( FSI_BYTE == nTargetDataType ) // 8 bits is unsigned, -128-127 to 0-255
	{
		int nMax, nMin;
		GetMaxMinSample(nTargetDataType, nMax, nMin);
		vChannel += (nMax+1)/2; 
	}
	
	return true;
}

bool exportWAVFile::WriteSamples(matrixbase& mb)
{
	int nTargetDataType = mb.GetInternalDataType();
	mb.SetSize(m_nR2 - m_nR1 + 1, m_Setting.Channels);
	
	matrix mat;	
	mat.SetSize(m_nR2 - m_nR1 + 1, m_Setting.Channels);	
	
	Worksheet wks(m_strWks);
	Column col;
	vector vChannel;
	
	col = wks.Columns(m_nC1);
	if ( !GenerateTargetChannelData(vChannel, nTargetDataType, col) )
		return false;
	mat.SetColumn(vChannel, 0);

	if ( 2 == m_Setting.Channels )
	{
		col = wks.Columns(m_nC2);
		if ( !GenerateTargetChannelData(vChannel, nTargetDataType, col) )
			return false;
		mat.SetColumn(vChannel, 1);
	}
	
	mat.Replace(get_missing_value(), 0);
	int nMaxVolumeTarget, nMinVolumeTarget;
	if ( GetMaxMinSample(nTargetDataType, nMaxVolumeTarget, nMinVolumeTarget) )
	{
		mat.ReplaceGreaterThan(nMaxVolumeTarget, nMaxVolumeTarget);
		mat.ReplaceLessThan(nMinVolumeTarget,  nMinVolumeTarget);
	}
	
	mb = mat;
	void* lpbyData = mb;
	Write(lpbyData, (m_nR2 - m_nR1 + 1) * m_Setting.Channels * GetBytesSample(nTargetDataType));
	
	return true;	
}
///---END IMPROVE_CONVERT_SAMPLE_BITS

bool exportWAVFile::CheckSetting()
{
	if ( m_strWks.IsEmpty() )
		return false;
	
	Worksheet wks(m_strWks);
	if ( !wks )
		return false;
	
	int nNumCols = wks.GetNumCols();
	int nNumRows = wks.GetNumRows();
	/// Hong 09/17/07 QA80-10381 SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	//if ( -1 == m_nC2 )
		//m_nC2 = nNumCols - 1;
	/// end SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	if ( -1 == m_nR2 )
		m_nR2 = nNumRows - 1;
		
	bool bValidRange;
	//bValidRange = ( m_nC1 < nNumCols && m_nC2 < nNumCols && m_nCX < nNumCols 
					//&& m_nCX < m_nC1 && m_nC1 <= m_nC2
					//&& m_nR1 < nNumRows && m_nR2 < nNumRows && m_nR1 <= m_nR2 );
	/// Hong 09/17/07 QA80-10381 SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	//bValidRange = ( m_nC1 < nNumCols && m_nC2 < nNumCols && m_nC1 <= m_nC2
	//				&& m_nR1 < nNumRows && m_nR2 < nNumRows && m_nR1 <= m_nR2 );
	/// Hong 10/10/07 v8.0721c FIX_EXPORT_FAIL_IF_ONLY_ONE_COL
	//bValidRange = ( m_nC1 < nNumCols && m_nC2 < nNumCols
	//				&& m_nR1 < nNumRows && m_nR2 < nNumRows && m_nR1 <= m_nR2 );
	bValidRange = ( m_nC1 < nNumCols && m_nR1 < nNumRows && m_nR2 < nNumRows && m_nR1 <= m_nR2 );
	if ( WAV_CHANNEL_STEREO == m_Setting.Channels )
		bValidRange &= (m_nC2 < nNumCols);
	/// end FIX_EXPORT_FAIL_IF_ONLY_ONE_COL
	/// end SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	if ( !bValidRange )
		return false;	
	
	return true;
}

#define MAX_DOUBLE ((double)1.7E307)

/// Hong 09/17/07 QA80-10381 SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
static void _get_min_max(Worksheet& wks, int nIndex, int nR1, int nR2, double& dMinest, double& dMaxest)
{
	double dMin, dMax;
	
	Column col(wks, nIndex);
	vectorbase& vb = col.GetDataObject();
	vector vv;
	vv = vb;
	if ( nR2 < vv.GetSize() - 1 )
		vv.RemoveAt(nR2+1, vv.GetSize() - 1 - nR2);
	if ( nR1 > 1 )
		vv.RemoveAt(0, nR1);
	
	vv.GetMinMax(dMin, dMax);
	if ( dMin < dMinest )
		dMinest = dMin;
	if ( dMax > dMaxest )
		dMaxest = dMax;
}
/// end SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED

void exportWAVFile::GetMaxVolumeSource(double& dMaxVolume, Worksheet& wks, int nC1, int nC2, int nR1, int nR2) // = 0, -1
{
	double dMinest = MAX_DOUBLE; // initialize
	double dMaxest = MAX_DOUBLE * -1; // initialize
	/// Hong 09/17/07 QA80-10381 SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	/*
	double dMin, dMax;
	// not handle nR1, nR2	
	for (int ii = nC1; ii <= nC2; ii++ )
	{
		Column col(wks, ii);
		vectorbase& vb = col.GetDataObject();
		vector vv;
		vv = vb;
		if ( nR2 < vv.GetSize() - 1 )
			vv.RemoveAt(nR2+1, vv.GetSize() - 1 - nR2);
		if ( nR1 > 1 )
			vv.RemoveAt(0, nR1);
		
		vv.GetMinMax(dMin, dMax);
		if ( dMin < dMinest )
			dMinest = dMin;
		if ( dMax > dMaxest )
			dMaxest = dMax;
	}
	*/
	_get_min_max(wks, nC1, nR1, nR2, dMinest, dMaxest);
	if ( 2 == m_Setting.Channels ) /// Hong 09/19/07 v8.0704 FIX_RUNTIME_IF_MONO
		_get_min_max(wks, nC2, nR1, nR2, dMinest, dMaxest);
	/// end SIMPLIFY_GUI_HIDDEN_OPTION_IF_NO_NEED
	dMaxVolume = (fabs(dMaxest) > fabs(dMinest)) ? fabs(dMaxest) : fabs(dMinest);
}

//void exportWAVFile::ClearMissingValueToZero(Worksheet& wks, int nC1, int nC2, int nR1, int nR2) // = 0, -1
//{
	//for (int ii = nC1; ii <= nC2; ii++ )
	//{
		//Column col(wks, ii);
		//vectorbase& vb = col.GetDataObject();
		//vb.Replace(get_missing_value(), 0);
	//}
//}

int exportWAVFile::GetSampleRate(Column& colX, DWORD& dwSampleRate, int nR1, int nR2) // = 0, -1;
{
	if ( -1 == nR2 )
		nR2 = colX.GetNumRows() - 1;
	
	vectorbase& vb = colX.GetDataObject();
	vector vX;
	vX = vb;
	if ( nR2 < vX.GetSize() - 1 )
		vX.RemoveAt(nR2+1, vX.GetSize() - 1 - nR2);
	if ( nR1 > 1 )
		vX.RemoveAt(0, nR1);
	
	double dInterval;
	int nErr;
	nErr = ocmath_sampling_resolution(vX.GetSize(), vX, &dInterval);
	if ( OE_NOERROR != nErr )
		return INVALID_X_AXIS;
	
	if ( dInterval < 0 )
		return INVALID_X_AXIS;
	
	if ( (1/dInterval) < WAV_SAMPLE_RATE_MINIMUM_LIMIT )
		return INVALID_X_AXIS;
	
	dwSampleRate = (1/dInterval);
	return SUCCEED;	
}

int exportWAVFile::GetSampleRate(Worksheet& wks, DWORD& dwSampleRate, int nC1, int nC2)
{
	double dX0, dInc;
	
	Column col;
	col = wks.Columns(nC1);
	if ( !col.IsEvenSampling(&dX0, &dInc) )
		return INVALID_SAMPLE_RATE;
	
	double dTempX0, dTempInc;
	for (int ii = nC1 + 1; ii <= nC2; ii++)
	{
		col = wks.Columns(ii);
		if ( !col.IsEvenSampling(&dTempX0, &dTempInc) )
			return INVALID_SAMPLE_RATE;
		
		if ( !(dX0 == dTempX0 && dInc == dTempInc) )
			return INVALID_SAMPLE_RATE;
	}
	
	m_Setting.SamplesPerSecond = 1 / dInc;
	if ( m_Setting.SamplesPerSecond < WAV_SAMPLE_RATE_MINIMUM_LIMIT )
		return INVALID_SAMPLE_RATE;
}
