//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "GlobalUnit.h"
#include "AudioTrack.h"
#include "Undo.h"
#include "Project.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

/***************************************************************************************/
// 全局变量
/***************************************************************************************/

TAudio 				g_Audio;
TAudioTrackList&  	g_aAudioTracks = g_Audio.AudioTracks();  //全曲音频轨道（最大4组）
int 				g_iSelAudio = 0; 	   // 当前处理的音频轨

 /***************************************************************************************/
// TAudio类函数
/***************************************************************************************/

void TAudio::CopyTrackList( int iStartBar, int nCopyBars, TAudioTrackList* lstAudio, bool bFx )
{
	int iTrkStart = 1,
		iTrkEnd = m_lstTracks.size();

	if( g_iPreStage==0/*iTrkEnd==iTrkStart*/ )
		iTrkStart = 0;

	for( int i=iTrkStart; i<iTrkEnd; i++ ){
		if( !m_lstTracks[i]->lstBars.empty() )
			lstAudio->push_back( CopyTrack( i, iStartBar, nCopyBars, bFx ) );
	}
}

TAudioTrack* TAudio::CopyTrack( int iTrack, int iStartBar, int nCopyBars, bool bFx, TAudioTrack* pDest )
{
	TAudioTrack* pSrcTrack = m_lstTracks[iTrack],
			*pDestTrack = pDest ? pDest : new TAudioTrack();

	pDestTrack->state = pSrcTrack->state;
	pDestTrack->volume = pSrcTrack->volume;
	pDestTrack->pan = pSrcTrack->pan;
	pDestTrack->gain = pSrcTrack->gain;

	for( int i=0; i<nCopyBars; i++ ){
		pDestTrack->lstBars.push_back( new TWaveBar( pSrcTrack->lstBars[iStartBar+i] ) );
	}

	if( bFx ){
		for( int i=0; i<pSrcTrack->lstFxs.size(); i++ )
			pDestTrack->lstFxs.push_back( new TAudioFx( pSrcTrack->lstFxs[i]) );
	}

	return pDestTrack;
}

void TAudio::ResetTracks( TAudioTrackList* lstAudio )
{
	//处理音频
	while( m_lstTracks.size()>1 ){
		delete m_lstTracks.back();
		m_lstTracks.pop_back();
	}

	for( int i=0; i<lstAudio->size(); i++ ){
		//替换AudioTrack
		TAudioTrack* pNewTrack = DuplicateAudioTrack( (*lstAudio)[i] );
		m_lstTracks.push_back( pNewTrack );

		AudioEffectsSet( i+1 );
	}

/*	if( m_lstTracks.size()>1 ){
		m_lstTracks[0]->bHide = true;
	}
*/
}

void TAudio::RestoreAudio( TOpusStageList* lstStages, TAudioTrackList* lstAudio, bool bUndo )
{
	int iOrigStage = 0, iVarBar = 0;

	TOpusStageList::iterator iterDest = lstStages->begin(),
							iterSrc = g_lstOpusStages.begin();
	int iDestBar(0), iSrcBar(0);//, iDVB(0), iSVB(0);
	while( iterDest!=lstStages->end() && iterSrc!=g_lstOpusStages.end() ){
		TOpusStage *pSrcStage = *iterSrc,
				*pDestStage = *iterDest;

		if( pSrcStage->iSegType<SEGTYPE_INTRO && pDestStage->iSegType<SEGTYPE_INTRO ){
			int nBar = min( pSrcStage->aBars.size(), pDestStage->aBars.size() );

			if( nBar==pSrcStage->aBars.size() ){
				iterSrc++;
			}

			if( nBar==pDestStage->aBars.size() ){
				iterDest++;
			}

			iDestBar += nBar;
			iSrcBar += nBar;
		}
		else if( pSrcStage->iSegType<SEGTYPE_INTRO && pDestStage->iSegType>=SEGTYPE_INTRO ){ //undo情况
			int nBar = pDestStage->aBars.size();

			iDestBar += nBar;
			iSrcBar += nBar;
			iterDest++;
		}
		else if( pSrcStage->iSegType>=SEGTYPE_INTRO && pDestStage->iSegType<SEGTYPE_INTRO ){ //redo情况
			//删掉音频
			int nBar = pSrcStage->aBars.size();
			for( int i=1; i<g_aAudioTracks.size(); i++ ){
				RemoveWaveBars( i, iSrcBar, nBar );
			}

			iterSrc++;
		}
		else if( pSrcStage->iSegType==SEGTYPE_INTRO && pDestStage->iSegType==SEGTYPE_ENDING ){//redo情况
			//删掉音频
			int nBar = pSrcStage->aBars.size();
			for( int i=1; i<g_aAudioTracks.size(); i++ ){
				RemoveWaveBars( i,iSrcBar , nBar );
			}

			iterSrc++;
		}
		else if( pSrcStage->iSegType==SEGTYPE_ENDING && pDestStage->iSegType==SEGTYPE_INTRO ){//undo情况
			int nBar = pDestStage->aBars.size();

			iDestBar += nBar;
			iSrcBar += nBar;
			iterDest++;
		}
		else{ //前尾奏类型相同
			//redo比较长度并插入空白或删除
			if( !bUndo ){
				if( pDestStage->aBars.size() > pSrcStage->aBars.size() ){
					int nBar = pDestStage->aBars.size() - pSrcStage->aBars.size(),
						iInsBar = iSrcBar + pSrcStage->aBars.size();

					for( int i=1; i<g_aAudioTracks.size(); i++ ){
						InsertAudioTrack( i, iInsBar, nBar, NULL );
					}

					iSrcBar += nBar;
				}
				else if( pDestStage->aBars.size() < pSrcStage->aBars.size() ){
					int nBar = pSrcStage->aBars.size() - pDestStage->aBars.size(),
						iDelBar = iSrcBar + pDestStage->aBars.size();

					for( int i=1; i<g_aAudioTracks.size(); i++ ){
						RemoveWaveBars( i, iDelBar, nBar );
					}

					iSrcBar -= nBar;
				}
			}

			iSrcBar += pSrcStage->aBars.size();
			iDestBar += pDestStage->aBars.size();
			iterSrc++;
			iterDest++;
		}
	}

	while( iterDest!=lstStages->end() ){ //undo情况
		int nBar = (*iterDest)->aBars.size();

		iDestBar += nBar;
		iterDest++;
	}

	//处理音频
	if( lstAudio ){
		for( int i=1; i<g_aAudioTracks.size(); i++ ){
			if( bUndo ){ //替换WaveBars
				TAudioTrack *pAT = g_aAudioTracks[i],
						*pSrc = (*lstAudio)[i-1];

				RemoveWaveBars( i, 0, pAT->lstBars.size() );

				if( pSrc ){
					for( int i=0; i<pSrc->lstBars.size(); i++ ){
						TWaveBar* pWvBar = new TWaveBar;
						memcpy( pWvBar->aVols, pSrc->lstBars[i], sizeof(DWORD)*POINTS_PER_BAR );
						pAT->lstBars.push_back( pWvBar );
					}
				}
			}
		}
	}
}

void TAudio::WriteProj( FILE* pFile )
{
	int num = m_lstTracks.size();
	fwrite( &num, sizeof(int), 1, pFile );

	for( int i=0; i<num; i++ ){
		TAudioTrack* pAT = m_lstTracks[i];

		int nBars = pAT->lstBars.size();
		fwrite( &nBars, sizeof(int), 1, pFile );

//		fwrite( &bHide, sizeof(BYTE), 1, pFile );
//		fwrite( &bMute, sizeof(BYTE), 1, pFile );
		fwrite( &pAT->state, sizeof(BYTE), 1, pFile );
		fwrite( &pAT->volume, sizeof(BYTE), 1, pFile );
		fwrite( &pAT->pan, sizeof(char), 1, pFile );
		fwrite( &pAT->gain, sizeof(char), 1, pFile );
//		fwrite( &iShow, sizeof(BYTE), 1, pFile );

		int count = pAT->lstFxs.size();
		fwrite( &count, sizeof(int), 1, pFile );

		for( int j=0; j<count; j++ ){
			TAudioFx* pFx = pAT->lstFxs[j];
			fwrite( &pFx->iFx, sizeof(int), 1, pFile );
			fwrite( &pFx->iPreset, sizeof(int), 1, pFile );
			fwrite( &pFx->bBypass, sizeof(WORD), 1, pFile );
			fwrite( &pFx->nParamSize, sizeof(WORD), 1, pFile );
			if( pFx->nParamSize>0 )
				fwrite( pFx->pParam, sizeof(float), pFx->nParamSize, pFile );

			if( pFx->iFx >= FX_VST ){
				VSTINFO* pVST = g_lstVSTFx[pFx->iFx-FX_VST];
				DWORD uniqueID = pVST->uniqueID;
				fwrite( &uniqueID, sizeof(DWORD), 1, pFile );

				if( pFx->iPreset>=0 ){
					uniqueID = pVST->aPlugins[pFx->iPreset]->id;
					fwrite( &uniqueID, sizeof(DWORD), 1, pFile );
				}
			}
		}
	}
}

int TAudio::ReadProj( FILE* pFile, DWORD dwVersion )
{
	WORD wMajVersion = HIWORD( dwVersion ),
		wMinVersion = LOWORD( dwVersion );
	int iError = E_PROJ_NOERROR;

	int num;
	fread( &num, sizeof(int), 1, pFile );

	for( int i=0; i<num; i++ ){
		int nBars;
		fread( &nBars, sizeof(int), 1, pFile );

		TAudioTrack* pAT = NULL;
		if( i==0 ){
			pAT = m_lstTracks[0];
		}
		else{
			pAT = new TAudioTrack;
			m_lstTracks.push_back( pAT );
		}

		for( int j=0; j<nBars; j++ ){
			TWaveBar* pWvBar = new TWaveBar;
			pAT->lstBars.push_back( pWvBar );
		}

		if( wMajVersion==5 && wMinVersion>=6 ){
			fread( &pAT->state, sizeof(BYTE), 1, pFile );
			fread( &pAT->volume, sizeof(BYTE), 1, pFile );
			fread( &pAT->pan, sizeof(char), 1, pFile );
			fread( &pAT->gain, sizeof(char), 1, pFile );

			int count = 0;
			fread( &count, sizeof(int), 1, pFile );

			for( int j=0; j<count; j++ ){
				int iFx, iPreset;
				WORD bBypass, nParamSize;
				float* pParam = NULL;
				bool bAdd = true;

				fread( &iFx, sizeof(int), 1, pFile );
				fread( &iPreset, sizeof(int), 1, pFile );
				fread( &bBypass, sizeof(WORD), 1, pFile );
				fread( &nParamSize, sizeof(WORD), 1, pFile );
				if( nParamSize>0 ){
					pParam = new float[nParamSize];
					fread( pParam, sizeof(float), nParamSize, pFile );
				}

				if( iFx >= FX_VST ){
					DWORD uniqueID = 0, pluginID = 0;
					fread( &uniqueID, sizeof(DWORD), 1, pFile );

					if( iPreset>=0 )
						fread( &pluginID, sizeof(int), 1, pFile );

					bAdd = false;
					for( int k=0; k<g_lstVSTFx.size(); k++ ){
						if( uniqueID==g_lstVSTFx[k]->uniqueID ){
							iFx = FX_VST + k;

							if( iPreset<0 ){
								bAdd = true;
							}
							else{
								for( int p=0; p<g_lstVSTFx[k]->aPlugins.size(); p++ ){
									if( g_lstVSTFx[k]->aPlugins[p]->id==pluginID ){
										iPreset = p;
										bAdd = true;

										break;
									}
								}
							}

							break;
						}
					}
				}

				if( bAdd ){
					TAudioFx* pFx = new TAudioFx( iFx, iPreset, pParam, nParamSize, bBypass );
					pAT->lstFxs.push_back( pFx );
				}
				else{
					iError |= E_PROJ_INVALIDFX;
                }
			}
		}
		else{
			BYTE bHide, bMute, iShow;
			fread( &bHide, sizeof(BYTE), 1, pFile );
			fread( &bMute, sizeof(BYTE), 1, pFile );
			fread( &pAT->volume, sizeof(BYTE), 1, pFile );
			fread( &iShow, sizeof(BYTE), 1, pFile );

			if( bHide )
				pAT->Hide();
			if( bMute )
				pAT->Mute();

			for( int k=0; k<MAX_FX_NUM; k++ ){
				int count;
				fread(&count, sizeof(int), 1, pFile);

				for( int j=0; j<count; j++ ){
					TEffect pAE;
					fread( &pAE.iBarStart, sizeof(int), 1, pFile );
					fread( &pAE.iPointStart, sizeof(int), 1, pFile );
					fread( &pAE.iBarEnd, sizeof(int), 1, pFile );
					fread( &pAE.iPointEnd, sizeof(int), 1, pFile );
					fread( &pAE.iPreset, sizeof(int), 1, pFile );
					fread( &pAE.bOn, sizeof(bool), 1, pFile );
					if( pAE.bOn ){
						pAE.aParams = new float[6];
						fread( pAE.aParams, sizeof(float), 6, pFile );
					}

					if( pAE.iBarStart==0 && pAE.iBarEnd>=pAT->lstBars.size()-1 ){
						int iType = g_aAudioEffectTypes[k];

						if( iType!=FX_PITCH ){
							int nSize = GetFxParamNum( iType );
							float* pParams = new float[nSize];
							int iPreset = pAE.iPreset;

							int nPresetCount = GetFxPresetCount( iType );

							if( pAE.bOn )
								memcpy( pParams, pAE.aParams, sizeof(float)*nSize );
							else{
								if( iPreset>=nPresetCount )
									iPreset = 0;

								GetFxPreset( iType, iPreset, pParams );
							}

							TAudioFx* pFx = new TAudioFx( iType, iPreset, pParams, nSize, !pAE.bOn );
							pAT->lstFxs.push_back( pFx );
						}
					}
					else{
						iError |= E_PROJ_INVALIDFX;
                    }
				}
			}
		}
	}

	return iError;
}

/***************************************************************************************/
// 全局函数
/***************************************************************************************/

TAudioTrack* NewAudioTrack( int nBar, bool bAddUndo )
{
	TAudioTrack* pTrack = NULL;

	if( g_aAudioTracks.size()<MAX_AUDIOTRACK ){
		pTrack = new TAudioTrack;
		g_aAudioTracks.push_back( pTrack );

		if( g_aAudioTracks.size()>1 ){
			int iTrack = g_aAudioTracks.size()-1;

			for( int i=0; i<nBar; i++ ){
				TWaveBar* pBar = new TWaveBar;
				pTrack->lstBars.push_back( pBar );
			}

			if( bAddUndo ){
				f_MM_AudioNewTrack();

				g_Undo.AddUndo( UNDO_TRKAUD_ADD, iTrack, 0, 0, NULL, NULL );

				f_MM_AddUndoBefore( 0, NULL );
				f_MM_AddUndoAfter( 1, &iTrack );
			}

			g_aAudioTracks[0]->Hide();
		}

		PostMessage( Application->MainFormHandle, UM_ENABLERECORD, 0, 0 );
	}

	return pTrack;
}

void DeleteAudioTrack( int iTrack, bool bAddUndo )
{
	if( iTrack>0 && iTrack>=g_aAudioTracks.size() )
		return;

	int num = 1, iDelTrk = iTrack;
	TAudioTrackList* aTracks = NULL;
//	TAudioTrack* aTracks = NULL;

	if( iTrack<0 ){
		if( g_iPreStage==0 ){
			if( g_aAudioTracks[0]->lstBars.empty() )
				return;
			else
				iDelTrk = 0;
		}
		else if( g_aAudioTracks.size()<=1 )
			return;
	}

	if( iDelTrk<0 ){
		int nBars = g_Opus.BarCount();
		num = g_aAudioTracks.size()-1;

		if( bAddUndo ){
			aTracks = new TAudioTrackList;
//			aTracks = new TAudioTrack[num];
			int* aTrks = new int[num];

			for( int i=0; i<num; i++ )
				aTrks[i] = i+1;

			f_MM_AddUndoBefore( num, aTrks );

			delete[] aTrks;
		}

		for( int i=num; i>0; i-- ){
			if( bAddUndo )
//				g_Audio.CopyTrack( i, 0, nBars, true, &aTracks[i-1] );
				aTracks->insert( aTracks->begin(), DuplicateAudioTrack( g_aAudioTracks[i] ));

			f_MM_AudioDeleteTrack( i );
			delete g_aAudioTracks.back();
			g_aAudioTracks.pop_back();
		}
	}
	else{
		if( bAddUndo ){
			aTracks = new TAudioTrackList;

			aTracks->push_back( DuplicateAudioTrack( g_aAudioTracks[iDelTrk] ));
			f_MM_AddUndoBefore( 1, &iDelTrk );
		}

		f_MM_AudioDeleteTrack( iDelTrk );
		delete g_aAudioTracks[iDelTrk];

		if( iDelTrk==0 )
			g_aAudioTracks[0] = new TAudioTrack;
		else
			g_aAudioTracks.erase( g_aAudioTracks.begin() + iDelTrk );
	}

	if( bAddUndo ){
		int iUndoType = iTrack<0 ? UNDO_TRKAUD_DELALL : UNDO_TRKAUD_DEL;
		g_Undo.AddUndo( iUndoType, iDelTrk, -1, -1, (void*)aTracks, NULL );
	}

	PostMessage( Application->MainFormHandle, UM_ENABLERECORD, 0, 0 );
	//Application->MainForm->Perform( UM_ENABLERECORD, 0, 0 );
}

void DuplicateRawBars()
{
	if( g_aAudioTracks.size()>1 || g_aAudioTracks[0]->lstBars.empty() )
		return;

	TAudioTrack* pRaw = g_aAudioTracks[0];
	TAudioTrack* pAT = DuplicateAudioTrack( pRaw );

	g_aAudioTracks.push_back( pAT );

	pRaw->Hide();
	pAT->Hide(false);

	f_MM_AudioNewTrack();
	f_MM_SetStreamVolume( 0x10+1, pAT->IsMute() ? 0.0 : ( pAT->volume / 100.0) );
	MoveAudio( 0, 0, pRaw->lstBars.size(), 1, 0, MODE_INSERT | OPT_BARS );

	AudioEffectsSet( g_aAudioTracks.size()-1 );
}

TAudioTrack* DuplicateAudioTrack( TAudioTrack* pSrc )
{
	if( !pSrc )
		return NULL;

	TAudioTrack* pNew = new TAudioTrack( pSrc );

	//复制bars
	for( int i=0; i<pSrc->lstBars.size(); i++ ){
		TWaveBar* pWvBar = new TWaveBar;
		memcpy( pWvBar->aVols, pSrc->lstBars[i]->aVols,	sizeof(DWORD)*POINTS_PER_BAR );
		pNew->lstBars.push_back( pWvBar );
	}

	for( int i=0; i<pSrc->lstFxs.size(); i++ ){
		TAudioFx* pFx = new TAudioFx( pSrc->lstFxs[i] );
		pNew->lstFxs.push_back( pFx );
	}

	return pNew;
}

bool MoveAudio( int iSrcTrack, double dblStart, double dblEnd,
				int iDestTrack, double dblInsert, int iOption )
{
	bool bMoveBars = iOption & OPT_BARS,
		bCountDown = false;

	int iMode = iOption & 0x0F;
	int iStartBar = (int)dblStart,
		iEndBar = (int)dblEnd,
		iInsertBar = (int)dblInsert,
		iStartPoint = (int)( (dblStart-iStartBar) * POINTS_PER_BAR + 0.5 ),
		iEndPoint = (int)( (dblEnd-iEndBar) * POINTS_PER_BAR + 0.5 ),
		iInsertPoint = (int)( (dblInsert-iInsertBar) * POINTS_PER_BAR + 0.5 );

	TAudioTrack *pSrcTrack = iSrcTrack<0 ? NULL : g_aAudioTracks[iSrcTrack],
			*pDestTrack = iDestTrack<0 ? NULL : g_aAudioTracks[iDestTrack];

	if( bMoveBars ){ //小节操作
		int nBarCount = iEndBar - iStartBar,
			iDelBar = iStartBar;

		if( iMode==MODE_MOVE || iMode==MODE_COPY || iMode==MODE_INSERT ){
			TWaveBarList lstCopyBars;

			for( int i=iStartBar; i<iEndBar; i++ ){
				TWaveBar* pWvBar = new TWaveBar;
				if( pSrcTrack )
					memcpy( pWvBar->aVols, pSrcTrack->lstBars[i]->aVols,
											sizeof(DWORD)*POINTS_PER_BAR );

				lstCopyBars.push_back( pWvBar );
			}

			InsertWaveBars( iDestTrack, iInsertBar, lstCopyBars );

			if( iMode==MODE_MOVE && iInsertBar<iStartBar )
				iDelBar += nBarCount;

			f_MM_AudioMove( iDestTrack, dblInsert, iSrcTrack, dblStart, dblEnd, MODE_INSERT );
		}

		if( iMode == MODE_DELETE || iMode == MODE_MOVE ){
			RemoveWaveBars( iSrcTrack, iDelBar, nBarCount );

			f_MM_AudioMove( -1, 0, iSrcTrack, iDelBar, iDelBar+nBarCount, MODE_DELETE );
		}
	}
	else{ //音频操作
		if( iSrcTrack==iDestTrack && iStartBar==iInsertBar && iStartPoint==iInsertPoint ) //无需移动
			return false;

		int nPoints = (int)( (dblEnd-dblStart) * POINTS_PER_BAR + 0.5 );
		double dblDelStart = dblStart,	dblDelEnd = dblEnd;
		DWORD* aWave = iMode==MODE_ERASE ? NULL : new DWORD[nPoints];

		if( pSrcTrack ){
			int iPoint = 0;

			for( int i=iStartBar; i<=iEndBar; i++ ){
				int iSP = 0, iEP = POINTS_PER_BAR;
				if( i==iStartBar )
					iSP = iStartPoint;
				if( i==iEndBar )
					iEP = iEndPoint;

				if( iEP>iSP ){
					int lenP = iEP - iSP;
					if( iMode==MODE_MOVE || iMode==MODE_COPY )
						memcpy( aWave + iPoint, pSrcTrack->lstBars[i]->aVols + iSP,
															sizeof(DWORD) * lenP );

					if( iMode==MODE_MOVE || iMode==MODE_ERASE )
						memset( pSrcTrack->lstBars[i]->aVols + iSP, 0,
															sizeof(DWORD) * lenP );

					iPoint += lenP;
				}
				else{
					break;
				}
			}
		}

		if( iMode==MODE_MOVE || iMode==MODE_COPY ){
			if( iDestTrack==0 ){ //处理增加长度
				double dblMinLen = dblInsert + dblEnd - dblStart;
				if( dblMinLen > pDestTrack->lstBars.size() ){
					int nBars = (int)dblMinLen;
					if( dblMinLen - nBars > 0 )
						nBars++;

					for( int i=pDestTrack->lstBars.size(); i<nBars; i++ ){
						TWaveBar* pWvBar = new TWaveBar;
						pDestTrack->lstBars.push_back( pWvBar );
					}
				}
			}

			int iPoint = 0;
			while( iPoint<nPoints ){
				int iSP = 0, iEP = POINTS_PER_BAR;

				if( iInsertPoint>0 ){
					iSP = iInsertPoint;

					if( iSP + nPoints - iPoint < POINTS_PER_BAR )
						iEP = iSP + nPoints - iPoint;
				}
				else if( nPoints-iPoint < POINTS_PER_BAR ){
					iEP = nPoints - iPoint;
				}

				if( iEP > iSP ){
					int lenP = iEP - iSP;
					memcpy( pDestTrack->lstBars[iInsertBar]->aVols + iInsertPoint,
								aWave + iPoint, sizeof(DWORD) * lenP );

					iInsertPoint = 0;
					iInsertBar++;
					iPoint += lenP;
				}
				else{
					break;
				}
			}

			delete[] aWave;
		}

		f_MM_AudioMove( iDestTrack, dblInsert, iSrcTrack, dblStart, dblEnd, iMode );

		if( g_iSelAudio==0 )
			PostMessage( Application->MainForm->Handle, UM_AUTORECOGNITION, iMode, 0 );
	}

	return bCountDown;
}

int CopyWave( int iTrack, int iStartBar, int iStartPoint,
								int iEndBar, int iEndPoint,	DWORD** aWave )
{
	bool bT2A = *aWave==NULL;
	int nSelPoints = ( iEndBar - iStartBar - 1) * POINTS_PER_BAR
						 + (POINTS_PER_BAR - iStartPoint) + iEndPoint;

	if( bT2A ){
		*aWave = new DWORD[nSelPoints];
	}

	TAudioTrack* pTrack = g_aAudioTracks[iTrack];
	int iPoint = 0;

	for( int i=iStartBar; i<=iEndBar; i++ ){
		int iSP = 0, iEP = POINTS_PER_BAR;
		if( i==iStartBar )
			iSP = iStartPoint;
		if( i==iEndBar )
			iEP = iEndPoint;

		if( iEP>iSP ){
			char *pSrc = (char*)( bT2A ? pTrack->lstBars[i]->aVols+iSP : (*aWave)+iPoint ),
				*pDest = (char*)( bT2A ? (*aWave)+iPoint : pTrack->lstBars[i]->aVols+iSP );

			memcpy( pDest, pSrc, sizeof(DWORD) * ( iEP - iSP ));

			iPoint += iEP - iSP;
		}
		else{
			break;
		}
	}

	return nSelPoints;
}

void RemoveWaveBars( int iTrack, int iStartBar, int nDelBars )
{
	TAudioTrack* pTrack = g_aAudioTracks[iTrack];

	for( int i=0; i<nDelBars; i++ ){
		delete pTrack->lstBars[iStartBar];
		pTrack->lstBars.erase( pTrack->lstBars.begin()+iStartBar );
	}
}

void InsertWaveBars( int iTrack, int iInsertBar, TWaveBarList lstBars )
{
	TAudioTrack* pTrack = g_aAudioTracks[iTrack];

	if( pTrack->lstBars.size()>0 && iInsertBar < pTrack->lstBars.size() ){
		for( int i=lstBars.size()-1; i>=0; i-- ){
			pTrack->lstBars.insert( pTrack->lstBars.begin()+iInsertBar, lstBars[i] );
		}
	}
	else{
		for( int i=0; i<lstBars.size(); i++ ){
			pTrack->lstBars.push_back( lstBars[i] );
		}
	}
}

void RestoreWaveBars( int iInsBar, int nBars, DWORD* aWave )
{
	int nPoints = nBars * POINTS_PER_BAR;

	for( int i=1; i<g_aAudioTracks.size(); i++ ){
		DWORD* pW = aWave ? aWave + nPoints * ( i - 1 ) : NULL;
		TWaveBarList lstWaveBars;

		for( int j=0; j<nBars; j++ ){
			TWaveBar* pWvBar = new TWaveBar;

			if( pW )
				memcpy( pWvBar->aVols, pW + j * POINTS_PER_BAR,
											sizeof(DWORD)*POINTS_PER_BAR );

			lstWaveBars.push_back( pWvBar );
		}

		InsertWaveBars( i, iInsBar, lstWaveBars );
	}
}

TAudioTrack* CopyAudioTrack( int iTrack, int iStartBar, int nCopyBars )
{
	TAudioTrack* pSrcTrack = g_aAudioTracks[iTrack],
			*pDestTrack = new TAudioTrack(pSrcTrack);

	for( int i=0; i<nCopyBars; i++ ){
		TWaveBar* pWvBar = new TWaveBar;
		memcpy( pWvBar->aVols, pSrcTrack->lstBars[iStartBar+i],
												sizeof(DWORD)*POINTS_PER_BAR );
		pDestTrack->lstBars.push_back( pWvBar );
	}

	return pDestTrack;
}

void InsertAudioTrack( int iTrack, int iInsertBar, int nBars, TAudioTrack* pSrcTrack, int iStartBar )
{
	TAudioTrack* pDestTrack = g_aAudioTracks[iTrack];

	if( pDestTrack->lstBars.size()>0 && iInsertBar < pDestTrack->lstBars.size() ){
		for( int i=nBars-1; i>=0; i-- ){
			TWaveBar* pWvBar = new TWaveBar;

			if( pSrcTrack )
				memcpy( pWvBar->aVols, pSrcTrack->lstBars[iStartBar+i], sizeof(DWORD)*POINTS_PER_BAR );

			pDestTrack->lstBars.insert( pDestTrack->lstBars.begin()+iInsertBar, pWvBar );
		}
	}
	else{
		for( int i=0; i<nBars; i++ ){
			TWaveBar* pWvBar = new TWaveBar;

			if( pSrcTrack )
				memcpy( pWvBar->aVols, pSrcTrack->lstBars[iStartBar+i], sizeof(DWORD)*POINTS_PER_BAR );

			pDestTrack->lstBars.push_back( pWvBar );
		}
	}
}
