/*----------------------------------------------------------------------
 *
 * Filename: wav.cpp
 *
 * Contents: 
 *
 * 
 *
 *
 * Copyright (c) 2003 SAMSUNG Electronics.
 *
 *----------------------------------------------------------------------
 */

#include <bsp.h>
#include "wav.h"
#include <string.h>

struct RIFF
{
	char scRiffID[4];
	DWORD  uRiffSIZE;
	char scRiffFORMAT[4];
} ;
	
struct FMT
{
	char scFmtID[4]; //4
	DWORD  uFmtSize; 
	
	unsigned short  usFormatTag; 
	unsigned short  usChannelType; 
	DWORD  uSampleRate;  
	DWORD  uAvgBytesPerSec; 
	unsigned short  usBlockAlign; 
	unsigned short  usBitsPerSample; 
};
	
struct DATA
{
	char scDataID[4]; 
	DWORD  uPcmSize;
};


void Copy1w(DWORD sa, DWORD da, DWORD words)
{
	for (DWORD i=0; i<words; i++)
		*(DWORD *)(da+i*4) = *(DWORD *)(sa+i*4);
}

WAV::WAV()
{
}

WAV::WAV(DWORD uWavFileAddr)
{
	m_uWavFileAddr = uWavFileAddr; 
	ParseHeader(uWavFileAddr, m_uPcmSize, m_uChannelType, m_uSampleRate, m_uBitsPerSample);
}

WAV::~WAV()
{
}
	
void WAV::ParseHeader(DWORD uWavFileAddr, 
	DWORD& uPcmSize, DWORD& uChannels, DWORD& uSampleRate, DWORD& uBitsPerSample)
{
	FMT *pFmt = (FMT*)(uWavFileAddr + sizeof(RIFF));
	uChannels = pFmt->usChannelType;	
	uSampleRate = pFmt->uSampleRate;
	uBitsPerSample = pFmt->usBitsPerSample;

	m_uPcmStAddr = uWavFileAddr + sizeof(RIFF) + pFmt->uFmtSize + 0x8;

	DATA *pData = (DATA*)m_uPcmStAddr;
	uPcmSize = pData->uPcmSize;

	m_uPcmStAddr+=sizeof(DATA);
}

void WAV::PutHeader(DWORD uWavFileAddr,DWORD uPcmSize,DWORD uChannels,DWORD uSampleRate,DWORD uBitsPerSample)
{
	RIFF *pRiff = (RIFF*)uWavFileAddr;
	strcpy(pRiff->scRiffID, "RIFF");
	pRiff->uRiffSIZE= uPcmSize+ sizeof(FMT) + sizeof(DATA) + 0x04;
	strcpy(pRiff->scRiffFORMAT,"WAVE");

	FMT *pFmt = (FMT*)(uWavFileAddr + sizeof(RIFF));

	strcpy(pFmt->scFmtID,"fmt ");
	pFmt->uFmtSize= sizeof(FMT) - 0x04 - 0x04;
    pFmt->usFormatTag = 0x01;
	pFmt->usChannelType = (unsigned short)uChannels;
	pFmt->uSampleRate = uSampleRate;
	pFmt->uAvgBytesPerSec = (uSampleRate*uChannels*uBitsPerSample)>>3;
	pFmt->usBlockAlign = (USHORT)(uBitsPerSample*(unsigned short)uChannels)>>3;
	pFmt->usBitsPerSample = (unsigned short)uBitsPerSample;

	DATA *pData = (DATA*)(uWavFileAddr + sizeof(RIFF) + sizeof(FMT));
	
	strcpy(pData->scDataID,"data");
	pData->uPcmSize = uPcmSize;

	m_uPcmStAddr = uWavFileAddr+WAVFILE_HEADER_SZ;

}

void WAV::SeparateCh(DWORD uWavFileAddr, DWORD uChIdx, DWORD uSaveAddr, DWORD& uSaveSize)
{
	DWORD uPcmSize, uChannelType, uSampleRate, uBitsPerSample;
	ParseHeader(uWavFileAddr, uPcmSize, uChannelType, uSampleRate, uBitsPerSample);
//	Assert(uChIdx < uChannelType);
//	Assert(uBitsPerSample==16);

	DWORD uWrPtr = uSaveAddr+WAVFILE_HEADER_SZ;
	DWORD uRdPtr = uWavFileAddr+WAVFILE_HEADER_SZ+uChIdx*2;
	while(1)
	{
		*(volatile unsigned short*)uWrPtr = *(volatile unsigned short*)uRdPtr;
		uWrPtr += 2;
		uRdPtr += uChannelType*2;
		if( uRdPtr >= (uWavFileAddr+WAVFILE_HEADER_SZ+uPcmSize) )
			break;
	}
	PutHeader(uSaveAddr, uWrPtr-(uSaveAddr+WAVFILE_HEADER_SZ),1, uSampleRate, uBitsPerSample);
	uSaveSize = uWrPtr-uSaveAddr;
}

void WAV::ExtendPcm(DWORD uWavFileAddr, DWORD uLimitSize)
{
	uLimitSize = (uLimitSize==-1) ? 0x10000000 : uLimitSize;
	DWORD uPcmSize, uChannelType, uSampleRate, uBitsPerSample;
	ParseHeader(uWavFileAddr, uPcmSize, uChannelType, uSampleRate, uBitsPerSample);

	DWORD uPcmStAddr;
	GetPcmStAddr(uPcmStAddr);
	if (uBitsPerSample==24)
	{
		DWORD uNewPcmSize = uPcmSize/3*4;
		PutHeader(uWavFileAddr, uNewPcmSize, uChannelType, uSampleRate, uBitsPerSample);
//		Assert(uNewPcmSize+0x300<uLimitSize+WAVFILE_HEADER_SZ);
		DWORD uTempAddr = uWavFileAddr+WAVFILE_HEADER_SZ+uNewPcmSize;
		Copy1w(uPcmStAddr, uTempAddr, 0x300);

		unsigned char* pSrcPcmPtr = (unsigned char*)(uPcmStAddr+uPcmSize-3);
		DWORD* pDstPcmPtr = (DWORD*)(uWavFileAddr+WAVFILE_HEADER_SZ+uNewPcmSize-4);

		while (uPcmSize>0x300)
		{
			*pDstPcmPtr = (pSrcPcmPtr[2]<<16)|(pSrcPcmPtr[1]<<8)|pSrcPcmPtr[0];
			pDstPcmPtr--;
			pSrcPcmPtr-=3;
			uPcmSize-=3;
		}
		pSrcPcmPtr = (unsigned char*)(uTempAddr+0x300-3);
		while (uPcmSize>0)
		{
			*pDstPcmPtr = (pSrcPcmPtr[2]<<16)|(pSrcPcmPtr[1]<<8)|pSrcPcmPtr[0];
			pDstPcmPtr--;
			pSrcPcmPtr-=3;
			uPcmSize-=3;
		}	
	}
	else if (uBitsPerSample == 8)
	{
		DWORD uNewPcmSize = uPcmSize*2;
		PutHeader(uWavFileAddr, uNewPcmSize, uChannelType, uSampleRate, uBitsPerSample);
//		Assert(uNewPcmSize+0x300<uLimitSize+WAVFILE_HEADER_SZ);
		DWORD uTempAddr = uWavFileAddr+WAVFILE_HEADER_SZ+uNewPcmSize;
		Copy1w(uPcmStAddr, uTempAddr, 0x300);

		unsigned char* pSrcPcmPtr = (unsigned char*)(uPcmStAddr+uPcmSize-1);
		signed short* pDstPcmPtr = (signed   short*)(uWavFileAddr+WAVFILE_HEADER_SZ+uNewPcmSize-2);

		while (uPcmSize>0x300)
		{
			*pDstPcmPtr = (pSrcPcmPtr[0]);
//			*pDstPcmPtr = (pSrcPcmPtr[0]-0x80);
			pDstPcmPtr--;
			pSrcPcmPtr-=1;
			uPcmSize-=1;
		}
		pSrcPcmPtr = (unsigned char*)(uTempAddr+0x300-1);
		while (uPcmSize>0)
		{
			*pDstPcmPtr = (pSrcPcmPtr[0]);
//			*pDstPcmPtr = (pSrcPcmPtr[0]-0x80);
			pDstPcmPtr--;
			pSrcPcmPtr-=1;
			uPcmSize-=1;
		}			
	}
	//else
	
//		Assert(0);
	ParseHeader(uWavFileAddr, m_uPcmSize, m_uChannelType, m_uSampleRate, m_uBitsPerSample);	
}

