BOOL CWaveManagerDoc::RecordWave()
{
// 查询系统是否安装有波形音频输入设备
if (waveInGetNumDevs() == 0)
{
// 系统没有波形音频输入设备
return FALSE;
}
m_nBlockAlign = m_nChannels*m_wBitsPerSample/8;
m_dwBufferSize = m_nSamplesPerSec*m_nBlockAlign;
// 设置录音格式
m_Format.wFormatTag = WAVE_FORMAT_PCM;
m_Format.nChannels = m_nChannels;
m_Format.nSamplesPerSec = m_nSamplesPerSec;
m_Format.nAvgBytesPerSec = m_nSamplesPerSec*m_nBlockAlign;
m_Format.nBlockAlign = m_nBlockAlign;
m_Format.wBitsPerSample = m_wBitsPerSample;
m_Format.cbSize = sizeof(WAVEFORMATEX);
// 打开波形音频设备
if (MMSYSERR_NOERROR !=
waveInOpen(&m_hWaveIn, WAVE_MAPPER, &m_Format,
(UINT)GetView()->m_hWnd, 0L, CALLBACK_WINDOW))
{
// 打开波形音频设备出错
return FALSE;
}
// 给第一缓冲区及波形数据头WAVEHDR分配、锁定全局内存
m_lpWaveHdr1 = (LPWAVEHDR)GlobalAllocPtr(
GMEM_MOVEABLE | GMEM_SHARE,
(DWORD) sizeof(WAVEHDR));
if (!m_lpWaveHdr1)
{
//分配全局内存出错
return FALSE;
}
m_lpBuffer1 = (LPSTR)GlobalAllocPtr(
GMEM_MOVEABLE | GMEM_SHARE,
m_dwBufferSize);
if (!m_lpBuffer1)
{
//分配全局内存出错
FreeGlobalPtr( m_lpWaveHdr1 );
return FALSE;
}
// 准备第一数据缓冲区,并送入设备
m_lpWaveHdr1->lpData = m_lpBuffer1;
m_lpWaveHdr1->dwBufferLength = m_dwBufferSize;
m_lpWaveHdr1->dwBytesRecorded = 0L;
m_lpWaveHdr1->dwUser = 0L;
m_lpWaveHdr1->dwFlags = 0L;
m_lpWaveHdr1->dwLoops = 1L;
m_lpWaveHdr1->lpNext = NULL;
m_lpWaveHdr1->reserved=0L;
if(MMSYSERR_NOERROR !=
waveInPrepareHeader(m_hWaveIn,
m_lpWaveHdr1, sizeof(WAVEHDR)))
{
// 准备WAVEHDR结构数据出错
FreeGlobalPtr( m_lpWaveHdr1 );
FreeGlobalPtr( m_lpBuffer1 );
return FALSE;
}
waveInAddBuffer(m_hWaveIn, m_lpWaveHdr1, sizeof(WAVEHDR));
// 给第二缓冲区及波形数据头WAVEHDR分配、锁定全局内存
m_lpWaveHdr2 = (LPWAVEHDR)GlobalAllocPtr(
GMEM_MOVEABLE | GMEM_SHARE,
(DWORD) sizeof(WAVEHDR));
if (!m_lpWaveHdr2)
{
//分配全局内存出错
FreeGlobalPtr( m_lpWaveHdr1 );
FreeGlobalPtr( m_lpBuffer1 );
return FALSE;
}
m_lpBuffer2 = (LPSTR)GlobalAllocPtr(
GMEM_MOVEABLE | GMEM_SHARE,
m_dwBufferSize);
if (!m_lpBuffer2)
{
//分配全局内存出错
FreeGlobalPtr( m_lpWaveHdr1 );
FreeGlobalPtr( m_lpBuffer1 );
FreeGlobalPtr( m_lpWaveHdr2 );
return FALSE;
}
// 准备第二数据缓冲区,并送入设备
m_lpWaveHdr2->lpData = m_lpBuffer2;
m_lpWaveHdr2->dwBufferLength = m_dwBufferSize;
m_lpWaveHdr2->dwBytesRecorded = 0L;
m_lpWaveHdr2->dwUser = 0L;
m_lpWaveHdr2->dwFlags = 0L;
m_lpWaveHdr2->dwLoops = 1L;
m_lpWaveHdr2->lpNext = NULL;
m_lpWaveHdr2->reserved=0L;
if(MMSYSERR_NOERROR !=
waveInPrepareHeader(m_hWaveIn,
m_lpWaveHdr2, sizeof(WAVEHDR)))
{
// 准备WAVEHDR结构数据出错
FreeGlobalPtr( m_lpWaveHdr1 );
FreeGlobalPtr( m_lpBuffer1 );
FreeGlobalPtr( m_lpWaveHdr2 );
FreeGlobalPtr( m_lpBuffer2 );
return FALSE;
}
waveInAddBuffer(m_hWaveIn, m_lpWaveHdr2, sizeof(WAVEHDR));
// 为波形音频数据预先分配内存,初始大小为1字节
FreeGlobalPtr( m_lpData );
m_lpData = (HPSTR)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, 1);
// 开始录音
m_dwDataLength = 0L;
waveInStart(m_hWaveIn);
return TRUE;
}
/********************************************************/
void CWaveManagerDoc::WimData(LPARAM lParam)
{
// 获取消息参数
LPWAVEHDR pWaveHdr = (LPWAVEHDR)lParam;
HPSTR pBuffer = pWaveHdr->lpData;
// 重新分配内存大小
m_lpData = (HPSTR)GlobalReAllocPtr(m_lpData,
pWaveHdr->dwBytesRecorded+m_dwDataLength,
GMEM_MOVEABLE | GMEM_SHARE);
if (! m_lpData)
{
// 重新分配内存大小出错
waveInClose(m_hWaveIn);
return;
}
// 将新录制的数据加道数据块中
::CopyMemory((HPSTR)(m_lpData+m_dwDataLength),
pBuffer,
(UINT)(pWaveHdr->dwBytesRecorded));
// 更新数据块大小
m_dwDataLength += pWaveHdr->dwBytesRecorded;
// 将缓冲区重新送入设备
pWaveHdr->dwBufferLength = m_dwBufferSize;
pWaveHdr->dwBytesRecorded = 0L;
pWaveHdr->dwFlags = 0L;
waveInAddBuffer(m_hWaveIn, pWaveHdr, sizeof(WAVEHDR));
}
/********************************************************/
BOOL CWaveManagerDoc::WriteWaveFile(LPCTSTR lpszFileName)
{
HMMIO hmmio;
MMCKINFO mmckinfoParent;
MMCKINFO mmckinfoSubchunk;
// 打开文件,使用缓冲区输入/输出
if(!(hmmio = mmioOpen((LPSTR)lpszFileName, NULL,
MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF)))
{
// 打开文件出错
return FALSE;
}
// Create the output file RIFF chunk of form type 'WAVE'.
mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
if (MMSYSERR_NOERROR !=
mmioCreateChunk(hmmio, &mmckinfoParent, MMIO_CREATERIFF))
{
mmioClose(hmmio, 0);
return FALSE;
}
//We are now descended into the 'RIFF' chunk we just created.
//Now create the 'fmt ' chunk. Since we know the size of this chunk,
//specify it in the MMCKINFO structure so MMIO doesn't have to seek
//back and set the chunk size after ascending from the chunk.
mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
mmckinfoSubchunk.cksize = sizeof(m_Format); // we know the size of this ck.
if (MMSYSERR_NOERROR !=
mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0))
{
mmioClose(hmmio, 0);
return FALSE;
}
// Write the WAVEFORMATX structure to the 'fmt ' chunk.
if (mmioWrite(hmmio, (HPSTR) &m_Format, sizeof(m_Format))
!= sizeof(m_Format))
{
mmioClose(hmmio, 0);
return FALSE;
}
// Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
if (MMSYSERR_NOERROR !=
mmioAscend(hmmio, &mmckinfoSubchunk, 0))
{
mmioClose(hmmio, 0);
return FALSE;
}
// Create the 'data' chunk that holds the waveform samples.
mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (MMSYSERR_NOERROR !=
mmioCreateChunk(hmmio, &mmckinfoSubchunk, 0))
{
mmioClose(hmmio, 0);
return FALSE;
}
if (mmioWrite(hmmio, m_lpData, m_dwDataLength)
!= (LONG)m_dwDataLength)
{
mmioClose(hmmio, 0);
return FALSE;
}
if (MMSYSERR_NOERROR !=
mmioAscend(hmmio, &mmckinfoSubchunk, 0))
{
mmioClose(hmmio, 0);
return FALSE;
}
// Ascend the output file out of the 'RIFF' chunk -- this will cause
// the chunk size of the 'RIFF' chunk to be written.
// We are done -- files are closed below.
mmckinfoParent.cksize=m_dwDataLength + sizeof(WAVEFORMATEX);
if (MMSYSERR_NOERROR !=
mmioAscend(hmmio, &mmckinfoParent, 0))
{
mmioClose(hmmio, 0);
return FALSE;
}
// 文件已使用完毕,关闭它
mmioClose(hmmio, 0);
return TRUE;
}
/********************************************************/
void CWaveManagerView::OnDraw(CDC* pDC)
{
CWaveManagerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (! pDoc->m_dwSampleNum || ! pDoc->m_dwDataLength)
return;
CRect rc;
GetClientRect(&rc);
int nWidth = rc.Width();
int nHeight = rc.Height();
float fYUnit;
float fXUnit = (float)nWidth/(float)pDoc->m_dwSampleNum;
CPen pen(PS_SOLID, 1, RGB(0,0,0));
CPen *pOldPen = pDC->SelectObject(&pen);
if (pDoc->m_Format.wBitsPerSample == 8)
fYUnit = (float)((float)nHeight/255.0);
else if (pDoc->m_Format.wBitsPerSample == 16)
fYUnit = (float)((float)nHeight/65535.0);
int i, j, k, x, y;
y = (int)((float)pDoc->m_lpDrawValue[0]*fYUnit);
pDC->MoveTo(0, y);
for (x=1; x<nWidth; x++)
{
j = (int)((float)(x-1)/fXUnit);
i = (int)((float)x/fXUnit);
for (k=j; k<i; k+=(i-j)/10)
{
y = (int)((float)pDoc->m_lpDrawValue[k]*fYUnit);
pDC->MoveTo(x, y);
pDC->LineTo(x, nHeight-y);
}
}
pDC->SelectObject(pOldPen);
}