// WaveOutFile.cpp: implementation of the CWaveOutFile class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "WaveOutFile.h"

#include "audiotap.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CWaveOutFile::CWaveOutFile()
{
   m_wfxWaveFormat.wFormatTag       = WAVE_FORMAT_PCM;               /* format type */
   m_wfxWaveFormat.nChannels        = 1;                             /* number of channels (i.e. mono, stereo...) */
   m_wfxWaveFormat.nSamplesPerSec   = AUDIOTAP_RATEOUT;              /* sample rate */
   m_wfxWaveFormat.nAvgBytesPerSec  = 16000;                         /* for buffer estimation */
   m_wfxWaveFormat.nBlockAlign      = 2;                             /* block size of data */
   m_wfxWaveFormat.wBitsPerSample   = 16;                            /* Number of bits per sample of mono data */
   m_wfxWaveFormat.cbSize           = 0;                             /* The count in bytes of the size of
                                                                        extra information (after cbSize) */
   m_strPath = _T("");
   m_hMMIO = NULL;

   ZeroMemory(&m_mmckiWave, sizeof(m_mmckiWave));
   ZeroMemory(&m_mmckiData, sizeof(m_mmckiData));
}

CWaveOutFile::~CWaveOutFile()
{
   Close();
}

BOOL CWaveOutFile::Open(CString const & strPath, BOOL const fStereo /*=FALSE*/)
{
   BOOL fSuccess = FALSE;

   ASSERT(!strPath.IsEmpty());

   if (m_hMMIO != NULL) Close();

   if (fStereo)
   {
      m_wfxWaveFormat.nChannels        = 2;
      m_wfxWaveFormat.wBitsPerSample   = 8;
   }
   else
   {
      m_wfxWaveFormat.nChannels        = 1;
      m_wfxWaveFormat.wBitsPerSample   = 16;
   }

   m_strPath = strPath;

	m_hMMIO = mmioOpen((PTSTR)(LPCTSTR)m_strPath, NULL, MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF);
   ASSERT(m_hMMIO != NULL);
   if (m_hMMIO != NULL)
   {
	   // create wave RIFF chunk...
	   m_mmckiWave.fccType = mmioFOURCC('W','A','V','E');
	   m_mmckiWave.cksize = 0;		 	// let the function determine the size
	   MMRESULT mmResult = mmioCreateChunk(m_hMMIO, &m_mmckiWave, MMIO_CREATERIFF);
      ASSERT(mmResult == MMSYSERR_NOERROR);
      if (mmResult == MMSYSERR_NOERROR)
      {
         MMCKINFO mmckiFMT = {0};

	      // create the format chunk and write the wave format...
	      mmckiFMT.ckid = mmioFOURCC('f','m','t',' ');
	      mmckiFMT.cksize = sizeof(m_wfxWaveFormat);
	      mmResult = mmioCreateChunk(m_hMMIO, &mmckiFMT, 0);
         ASSERT(mmResult == MMSYSERR_NOERROR);
         if (mmResult == MMSYSERR_NOERROR)
         {
	         LONG cbWritten = mmioWrite(m_hMMIO, (PCSTR)&m_wfxWaveFormat, sizeof(m_wfxWaveFormat));
            ASSERT(cbWritten == sizeof(m_wfxWaveFormat));
            if (cbWritten == sizeof(m_wfxWaveFormat))
            {
	            // back out of format chunk...
	            mmioAscend(m_hMMIO, &mmckiFMT, 0);

	            // now create the wave data chunk...
	            m_mmckiData.ckid = mmioFOURCC('d','a','t','a');
	            m_mmckiData.cksize = 0;	 	// let the function determine the size
	            mmResult = mmioCreateChunk(m_hMMIO, &m_mmckiData, 0);
               ASSERT(mmResult == MMSYSERR_NOERROR);
               fSuccess = (mmResult == MMSYSERR_NOERROR);
            }
         }
      }
   }

   return fSuccess;
}

void CWaveOutFile::Close()
{
   if (m_hMMIO != NULL)
   {
      mmioAscend(m_hMMIO, &m_mmckiData, 0);
      ZeroMemory(&m_mmckiData, sizeof(m_mmckiData));

      mmioAscend(m_hMMIO, &m_mmckiWave, 0);
      ZeroMemory(&m_mmckiWave, sizeof(m_mmckiWave));

      mmioClose(m_hMMIO, 0);
      m_hMMIO = NULL;
   }
}

BOOL CWaveOutFile::Write(BYTE const * const pbData, DWORD const cbData)
{
   BOOL fSuccess = FALSE;

   ASSERT(m_hMMIO != NULL);
   if (m_hMMIO != NULL)
   {
	   DWORD cbWritten = (DWORD)mmioWrite(m_hMMIO, (PCSTR)pbData, cbData);
      ASSERT(cbWritten == cbData);
      fSuccess = (cbWritten == cbData);
   }

   return fSuccess;
}
