📄 output.cpp
字号:
#include <windows.h>
#include "maplay.h"
#include "helper.h"
#include "output.h"
#include "effect.h"
#define FADE_BITS 16
#define FADE_TIME 750
#define FADE_BASE 0
COutput::COutput()
{
m_fScanPeek = FALSE;
m_hwo = NULL;
m_pHdr = NULL;
m_hEvent = NULL;
m_cWritten = 0;
m_dwWritten = 0;
m_pbBuf = NULL;
m_nCurrent = 0;
m_dwBufLen = 500;
m_cBuf = 8;
m_cbBuf = 16 * 1024;
m_nLPeek = 0;
m_nRPeek = 0;
memset(&m_pcm, 0, sizeof(PCMWAVEFORMAT));
m_fFade = FALSE;
m_nFadeSamples = 0;
m_dwTotalSamples = 0;
m_fPaused = FALSE;
m_fDoubleBuf = FALSE;
m_hEventThread = NULL;
m_hThread = NULL;
m_dwThreadId = 0;
m_pbSubBuf = NULL;
m_nHdrOut = 0;
m_nWriteCur = 0;
memset(m_HdrOut, 0, sizeof(m_HdrOut));
}
COutput::~COutput()
{
}
BOOL COutput::SetOutputParam(DWORD dwBufLen, BOOL fDoubleBuf, BOOL fFade)
{
CAutoLock lock(&m_csecDevice);
if (m_hwo)
return FALSE;
if (dwBufLen < 10)
return FALSE;
m_dwBufLen = dwBufLen;
m_fFade = fFade;
m_fDoubleBuf = fDoubleBuf;
return TRUE;
}
void COutput::GetOutputParam(LPDWORD pdwBufLen, LPBOOL pfDoubleBuf, LPBOOL pfFade)
{
*pdwBufLen = m_dwBufLen;
*pfFade = m_fFade;
*pfDoubleBuf = m_fDoubleBuf;
}
BOOL COutput::Open(int nChannels, int nSamplingRate, int nBitsPerSample)
{
MMRESULT mmr;
int i, nCount = 0;
CAutoLock lock(&m_csecDevice);
if (!waveOutGetNumDevs())
goto fail;
if (nChannels == m_pcm.wf.nChannels &&
(int)m_pcm.wf.nSamplesPerSec == nSamplingRate &&
m_pcm.wBitsPerSample == nBitsPerSample)
return TRUE;
CloseAll();
m_cbBuf = BUFLEN_BASE;
if (nSamplingRate > 11025)
m_cbBuf *= 2;
if (nSamplingRate > 22050)
m_cbBuf *= 2;
if (nChannels > 1)
m_cbBuf *= 2;
if (nBitsPerSample > 8)
m_cbBuf *= 2;
m_pcm.wf.wFormatTag = WAVE_FORMAT_PCM;
m_pcm.wf.nChannels = nChannels;
m_pcm.wf.nSamplesPerSec = nSamplingRate;
m_pcm.wf.nAvgBytesPerSec = nBitsPerSample * nSamplingRate * nChannels / 8;
m_pcm.wf.nBlockAlign = nBitsPerSample * nChannels / 8;
m_pcm.wBitsPerSample = nBitsPerSample;
// 僨僶僀僗偑僆乕僾儞偱偒傞傑偱嵞帋峴偡傞
for (i = 0; i < 10; i++) {
if (m_fDoubleBuf)
mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, (LPWAVEFORMATEX)&m_pcm, (DWORD)WaveOutCallback2, 0, CALLBACK_FUNCTION);
else
mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, (LPWAVEFORMATEX)&m_pcm, (DWORD)WaveOutCallback, 0, CALLBACK_FUNCTION);
if (mmr == MMSYSERR_NOERROR)
break;
else if (mmr != MMSYSERR_ALLOCATED)
goto fail;
Sleep(100);
}
m_fPaused = FALSE;
m_dwWritten = 0;
if (!PrepareBuffer())
goto fail;
if (m_fDoubleBuf && !PrepareSubBuffer())
goto fail;
m_nLPeek = 0;
m_nRPeek = 0;
if (m_fFade) {
m_nFadeCurrent = FADE_BASE << FADE_BITS;
m_nFadeSamples = m_pcm.wf.nSamplesPerSec * FADE_TIME / 1000;
m_nFadeRate = (int)((((double)1 - FADE_BASE) / m_nFadeSamples) * (1 << FADE_BITS));
m_nFadeRate += 1;
}
return TRUE;
fail:
CloseAll();
return FALSE;
}
void COutput::Close()
{
CAutoLock lock(&m_csecDevice);
if (!m_fDoubleBuf) {
CloseAll();
return;
}
Reset();
}
WAVEHDR* COutput::GetBuffer()
{
WaitForSingleObject(m_hEvent, INFINITE);
return &m_pHdr[m_nCurrent];
}
void COutput::PutBuffer(WAVEHDR* pHdr)
{
if (m_fScanPeek)
CheckPeek(pHdr);
CAutoLock lock(&m_csecBuff);
SetEvent(m_hEvent);
m_cWritten--;
}
void COutput::OutputBuffer(WAVEHDR* pHdr)
{
if (!pHdr->dwBytesRecorded) {
CAutoLock lock(&m_csecBuff);
SetEvent(m_hEvent);
return;
}
if (m_fDoubleBuf) {
FadeIn((LPBYTE)pHdr->lpData, pHdr->dwBytesRecorded);
CAutoLock lockBuf(&m_csecBuff); // !!!!
m_cWritten++;
if (m_cWritten >= m_cBuf)
ResetEvent(m_hEvent);
m_nCurrent = (m_nCurrent + 1) % m_cBuf;
m_dwWritten += pHdr->dwBytesRecorded / m_pcm.wf.nBlockAlign;
}
else {
CAutoLock lockDev(&m_csecDevice);
FadeIn((LPBYTE)pHdr->lpData, pHdr->dwBytesRecorded);
waveOutWrite(m_hwo, pHdr, sizeof(WAVEHDR));
CAutoLock lockBuf(&m_csecBuff);
m_cWritten++;
if (m_cWritten >= m_cBuf)
ResetEvent(m_hEvent);
m_nCurrent = (m_nCurrent + 1) % m_cBuf;
m_dwWritten += pHdr->dwBytesRecorded / m_pcm.wf.nBlockAlign;
}
}
BOOL COutput::PrepareBuffer()
{
CAutoLock lock(&m_csecBuff);
if (m_pHdr)
return FALSE;
m_cBuf = m_dwBufLen * m_pcm.wf.nAvgBytesPerSec / m_cbBuf / 1000 + 1;
if (m_cBuf < 2) m_cBuf = 2;
m_pHdr = new WAVEHDR[m_cBuf];
if (!m_pHdr)
return FALSE;
m_pbBuf = new BYTE[m_cBuf * m_cbBuf];
if (!m_pbBuf)
return FALSE;
memset(m_pbBuf, 0, m_cBuf * m_cbBuf);
for (UINT i = 0; i < m_cBuf; i++) {
memset(&m_pHdr[i], 0, sizeof(WAVEHDR));
m_pHdr[i].lpData = (LPSTR)m_pbBuf + (m_cbBuf * i);
m_pHdr[i].dwBufferLength = m_cbBuf;
if (m_fDoubleBuf)
m_pHdr[i].dwUser = 0;
else {
m_pHdr[i].dwUser = (DWORD)this;
waveOutPrepareHeader(m_hwo, &m_pHdr[i] , sizeof(WAVEHDR));
}
}
m_nCurrent = 0;
m_cWritten = 0;
m_hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
return TRUE;
}
void COutput::FreeBuffer()
{
CAutoLock lock(&m_csecBuff);
if (m_pHdr) {
delete [] m_pHdr;
m_pHdr = NULL;
}
if (m_pbBuf) {
delete [] m_pbBuf;
m_pbBuf = NULL;
}
if (m_hEvent) {
CloseHandle(m_hEvent);
m_hEvent = NULL;
}
m_nCurrent = 0;
}
void COutput::Reset()
{
if (!m_hwo)
return;
if (m_fDoubleBuf) {
CAutoLock lockDev(&m_csecDevice);
SetEvent(m_hEvent);
m_cWritten = 0;
m_dwWritten = 0;
m_nCurrent = 0;
m_nWriteCur = 0;
m_fPaused = TRUE;
m_dwTotalSamples = 0;
if (m_pHdr) {
CAutoLock lock(&m_csecBuff);
for (DWORD i = 0; i < m_cBuf; i++)
m_pHdr[i].dwUser = 0;
}
}
else {
CAutoLock lock(&m_csecDevice);
waveOutPause(m_hwo);
waveOutReset(m_hwo);
SetEvent(m_hEvent);
m_cWritten = 0;
m_dwWritten = 0;
m_nCurrent = 0;
m_nWriteCur = 0;
waveOutPause(m_hwo);
}
m_nLPeek = 0;
m_nRPeek = 0;
if (m_fFade) {
m_nFadeCurrent = FADE_BASE << FADE_BITS;
m_nFadeSamples = m_pcm.wf.nSamplesPerSec * FADE_TIME / 1000;
m_nFadeRate = (int)((((double)1 - FADE_BASE) / m_nFadeSamples) * (1 << FADE_BITS));
m_nFadeRate += 1;
}
}
void CALLBACK COutput::WaveOutCallback(HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
if (uMsg == WOM_DONE) {
COutput* pOutput = (COutput*)((WAVEHDR*)dwParam1)->dwUser;
pOutput->PutBuffer((WAVEHDR*)dwParam1);
}
}
void CALLBACK COutput::WaveOutCallback2(HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
if (uMsg == WOM_DONE) {
COutput* pOutput = (COutput*)((WAVEHDR*)dwParam1)->dwUser;
if (pOutput->m_fScanPeek)
pOutput->CheckPeek((WAVEHDR*)dwParam1);
InterlockedIncrement((long*)&pOutput->m_nSubBuf);
SetEvent(pOutput->m_hEventThread);
}
}
void COutput::Pause(BOOL fPause)
{
if (!m_hwo)
return;
if (m_fDoubleBuf)
m_fPaused = fPause;
else {
CAutoLock lock(&m_csecDevice);
if (fPause)
waveOutPause(m_hwo);
else
waveOutRestart(m_hwo);
}
}
DWORD COutput::GetCurrent()
{
CAutoLock lock(&m_csecDevice);
if (!m_hwo)
return 0;
if (m_fDoubleBuf)
return m_dwTotalSamples;
MMTIME time;
memset(&time, 0, sizeof(MMTIME));
time.wType = TIME_SAMPLES;
waveOutGetPosition(m_hwo, &time, sizeof(MMTIME));
return time.u.sample;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -