📄 twave.cpp
字号:
// TWave.cpp: CtWave class implementation
//
#include "stdafx.h"
#include <assert.h>
#include "tWave.h"
//****************************************************************************
// Debug tracing functions.
#define DIM(rg) (sizeof(rg)/sizeof(*rg))
#ifdef _DEBUG
static
void WOTRACE(
MMRESULT mr,
LPCTSTR pszFunc)
{
if( mr )
{
TCHAR szErr[128];
waveOutGetErrorText(mr, szErr, DIM(szErr));
OutputDebugString(pszFunc);
OutputDebugString("() -- ");
OutputDebugString(szErr);
OutputDebugString("\n");
}
}
static
void WITRACE(
MMRESULT mr,
LPCTSTR pszFunc)
{
if( mr )
{
TCHAR szErr[128];
waveInGetErrorText(mr, szErr, DIM(szErr));
OutputDebugString(pszFunc);
OutputDebugString("() -- ");
OutputDebugString(szErr);
OutputDebugString("\n");
}
}
#else
inline void WOTRACE(MMRESULT, LPCSTR) {}
#define WOTRACE 1 ? 0 : WOTRACE
inline void WITRACE(MMRESULT, LPCSTR) {}
#define WITRACE 1 ? 0 : WITRACE
#endif
//*********************************************************************
// CtWave Constuctor.
// CTWaveSink is a CWnd and CtWaveSink derived class which acts as
// a message handler for the Wave Driver communications.
CtWave::CtWave(CtWaveSink* pSink):
m_pSink(pSink),
m_pDataIn1(0),
m_pDataIn2(0),
m_pDataOut1(0),
m_hWaveOut(0),
m_hWaveIn(0),
m_pWaveInHdr1(0),
m_pWaveInHdr2(0),
m_bWaveInHdr1InUse(true),
m_pWaveOutHdr1(0),
m_nRecordedSize(0),
m_pFormat(0),
m_nFormatSize(0),
m_bStopping(false),
m_bOwnData(false)
{
m_nTotalRecording = 0;
}
//*********************************************************************
CtWave::~CtWave()
{
// Ensure all activity is aborted.
Close();
}
//*********************************************************************
// Loads a WAV file by name.
bool CtWave::Load(LPCTSTR pszFileName)
{
// Make sure we're not open
Close();
// assert(!m_pFormat);
// assert(!m_nFormatSize);
// assert(!m_pDataOut1); //***
// assert(!m_nRecordedSize);
// Open the given file for reading using buffered I/O
HMMIO hmmio;
hmmio = mmioOpen(const_cast<TCHAR*>(pszFileName), 0, MMIO_READ | MMIO_ALLOCBUF);
if( !hmmio )
{
OutputDebugString("mmioOpen() -- Failed to open file: ");
OutputDebugString(pszFileName);
OutputDebugString("\n");
return false;
}
bool bSuccess = Load(hmmio);
// We're done with the file, close it
mmioClose(hmmio, 0);
return bSuccess;
}
//*********************************************************************
// Loads WAV data from the application resource by numerical ID
bool CtWave::Load(HMODULE hm, UINT nID)
{
return Load(hm, MAKEINTRESOURCE(nID));
}
//*********************************************************************
// Loads WAV data from the application resource by name
bool CtWave::Load(HMODULE hm, LPCTSTR pszID)
{
// Make sure we're not open
Close();
assert(!m_pFormat);
assert(!m_nFormatSize);
assert(!m_pDataOut1); //***
assert(!m_nRecordedSize);
// Load the resource
HRSRC hrsrc = FindResource(hm, pszID, __TEXT("wave"));
if( !hrsrc )
{
OutputDebugString("Failed to find 'wave' resource ");
OutputDebugString(pszID);
OutputDebugString("\n");
return false;
}
assert(SizeofResource(hm, hrsrc));
HGLOBAL hg = LoadResource(hm, hrsrc);
if( !hg )
{
OutputDebugString("Failed to load 'wave' resource ");
OutputDebugString(pszID);
OutputDebugString("\n");
return false;
}
// Open the given resource for reading
MMIOINFO mii = { 0 };
mii.pchBuffer = (HPSTR)hg;
mii.fccIOProc = FOURCC_MEM;
mii.cchBuffer = SizeofResource(hm, hrsrc);
HMMIO hmmio;
hmmio = mmioOpen(0, &mii, MMIO_READ | MMIO_ALLOCBUF);
if( !hmmio )
{
OutputDebugString("mmioOpen() -- Failed to open 'wave' resource ");
OutputDebugString(pszID);
OutputDebugString("\n");
return false;
}
bool bSuccess = Load(hmmio);
// We're done with the file, close it
mmioClose(hmmio, 0);
return bSuccess;
}
//*********************************************************************
// Loads the WAV data from multiple sources
bool CtWave::Load(HMMIO hmmio)
{
MMRESULT mr;
MMCKINFO mmckinfoParent;
MMCKINFO mmckinfoSubchunk;
// Locate a 'RIFF' chunk with a 'WAVE' form type to make sure it's a WAVE file
mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
mr = mmioDescend(hmmio, &mmckinfoParent, 0, MMIO_FINDRIFF);
if( mr )
{
WOTRACE(mr, __TEXT("mmioDescend"));
mmioClose(hmmio, 0);
return false;
}
// Now, find the format chunk (form type 'fmt '). It should be
// a subchunk of the 'RIFF' parent chunk.
mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
mr = mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK);
if( mr )
{
WOTRACE(mr, __TEXT("mmioDescend"));
mmioClose(hmmio, 0);
return false;
}
// Get the size of the format chunk and allocate memory for it
DWORD nFormatSize = mmckinfoSubchunk.cksize;
WAVEFORMATEX* pFormat = (WAVEFORMATEX*)(new BYTE[nFormatSize]);
if( !pFormat )
{
OutputDebugString("new[] -- Out of memory\n");
mmioClose(hmmio, 0);
return false;
}
// Read the format chunk
if( mmioRead(hmmio, (HPSTR)pFormat, nFormatSize) != (LONG)nFormatSize )
{
OutputDebugString("mmioRead() -- Failed to read FMT chunk\n");
delete[] pFormat;
mmioClose(hmmio, 0);
return false;
}
/*
TRACE1("wFormatTag = %lu\n", (DWORD) pFormat->wFormatTag);
TRACE1("nChannels = %lu\n", (DWORD) pFormat->nChannels );
TRACE1("nSamplesPerSec = %lu\n", (DWORD) pFormat->nSamplesPerSec);
TRACE1("nAvgBytesPerSec = %lu\n", (DWORD) pFormat->nAvgBytesPerSec);
TRACE1("nBlockAlign = %lu\n", (DWORD) pFormat->nBlockAlign);
TRACE1("wBitsPerSample = %lu\n", (DWORD) pFormat->wBitsPerSample);
TRACE1("cbSize = %lu\n", (DWORD) pFormat->cbSize);
*/
// Ascend out of the format subchunk
mmioAscend(hmmio, &mmckinfoSubchunk, 0);
// Find the data subchunk
mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
mr = mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK);
if( mr )
{
WOTRACE(mr, __TEXT("mmioDescend"));
delete[] pFormat;
mmioClose(hmmio, 0);
return false;
}
// Get the size of the data subchunk
DWORD nDataSize = mmckinfoSubchunk.cksize;
if( !nDataSize )
{
OutputDebugString("Data chunk actually has no data\n");
delete[] pFormat;
mmioClose(hmmio, 0);
return false;
}
//TRACE1("Size of data is %lu\n", nDataSize);
// Allocate memory for the waveform data
HPSTR pData = (HPSTR)(new BYTE[nDataSize]);
if( !pData )
{
OutputDebugString("new[] -- Out of memory\n");
mmioClose(hmmio, 0);
delete[] pFormat;
return false;
}
// Read the waveform data subchunk
if( mmioRead(hmmio, pData, nDataSize) != (LONG)nDataSize )
{
OutputDebugString("mmioRead() -- Failed to read waveform data subchunk\n");
delete[] pData;
delete[] pFormat;
mmioClose(hmmio, 0);
return false;
}
// Update the object state
m_pFormat = pFormat;
m_nFormatSize = nFormatSize;
m_nOutputSize = nDataSize;
m_pDataOut1 = pData; //***
m_bOwnData = true;
return true;
}
//*********************************************************************
// Remember buffer and create a new one.
// Used when recording audio.
bool CtWave::Append()
{
WAVEHDR* pWaveHdr;
HPSTR pData;
if (m_bWaveInHdr1InUse)
{
pWaveHdr = m_pWaveInHdr2;
pData = m_pDataIn2;
}
else
{
pWaveHdr = m_pWaveInHdr1;
pData = m_pDataIn1;
}
m_listWaveData.AddTail( pData);
pData = NULL;
MMRESULT mr = waveInUnprepareHeader(m_hWaveIn, pWaveHdr, sizeof(WAVEHDR));
WITRACE(mr, __TEXT("waveInUnprepareHeader"));
// Cache recorded length
m_nRecordedSize = pWaveHdr->dwBytesRecorded;
// Remember the total size.
m_nTotalRecording += m_nRecordedSize;
CString info;
info.Format("CtWave::Append() -- BufSize(%d) Total(%d)\n", m_nRecordedSize, m_nTotalRecording);
OutputDebugString(info);
delete pWaveHdr;
pWaveHdr = 0;
return true;
}
//*********************************************************************
// Save all buffers to a WAV file.
bool CtWave::Save(LPCTSTR pszFileName)
{
// Make sure we've got some data
if( !m_pDataIn1 ) //***
{
return false;
}
assert(m_pFormat);
assert(m_nFormatSize);
assert(m_pDataIn1); //***
HANDLE hFile;
DWORD nBytesWritten;
hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if( hFile == INVALID_HANDLE_VALUE )
{
OutputDebugString("CreateFile() -- Can't open file: ");
OutputDebugString(pszFileName);
OutputDebugString("\n");
return false;
}
BYTE rgbRiffChunk[] = { 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'A', 'V', 'E', };
BYTE rgbFormatChunkTag[] = { 'f', 'm', 't', ' ', 0, 0, 0, 0, };
BYTE rgbDataChunkTag[] = { 'd', 'a', 't', 'a', 0, 0, 0, 0, };
// Write out the RIFF chunk
*((DWORD*)&rgbRiffChunk[4]) = 4 + sizeof(rgbFormatChunkTag) +
m_nFormatSize + sizeof(rgbDataChunkTag) +
m_nTotalRecording;
if( !WriteFile(hFile, rgbRiffChunk, sizeof(rgbRiffChunk), &nBytesWritten, 0) )
{
OutputDebugString("Can't write RIFF chunk\n");
CloseHandle(hFile);
return false;
}
// Write tag
*((DWORD*)&rgbFormatChunkTag[4]) = m_nFormatSize;
if( !WriteFile(hFile, rgbFormatChunkTag, sizeof(rgbFormatChunkTag), &nBytesWritten, 0) )
{
OutputDebugString("Can't write fmt chunk\n");
CloseHandle(hFile);
return false;
}
// Write out the canned format header
if( !WriteFile(hFile, m_pFormat, m_nFormatSize, &nBytesWritten, 0) )
{
OutputDebugString("Can't write WAVEFORMATEX chunk\n");
CloseHandle(hFile);
return false;
}
// Write out the data chunk tag
*((DWORD *)&rgbDataChunkTag[4]) = m_nTotalRecording;
if( !WriteFile(hFile, rgbDataChunkTag, sizeof(rgbDataChunkTag), &nBytesWritten, 0) )
{
OutputDebugString("Can't write data chunk tag\n");
CloseHandle(hFile);
return false;
}
POSITION pos = m_listWaveData.GetHeadPosition();
while (pos)
{
HPSTR pData = (HPSTR)m_listWaveData.GetNext(pos);
if (pData)
{
// Write out the data chunks
if( !WriteFile(hFile, pData, m_nDataBlockSize, &nBytesWritten, 0) )
{
OutputDebugString("Can't write data chunk\n");
CloseHandle(hFile);
return false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -