⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 output.cpp

📁 PPC流行的播放软件gsplayer源码2.24版
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#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 + -