📄 soundcardpmo.cpp
字号:
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Portions Copyright (C) 1998-1999 EMusic.com
Portions Copyright (C) 1997 Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: soundcardpmo.cpp,v 1.77 2000/11/01 14:22:45 robert Exp $
____________________________________________________________________________*/
/* system headers */
#include <windows.h>
#include <winbase.h>
#include <stdlib.h>
#include <string.h>
/* project headers */
//#include "config.h"
#include "SoundCardPMO.h"
#include "eventdata.h"
#include "debug.h"
#define DB Debug_v("%s:%d", __FILE__, __LINE__);
#define MAXINT32 0x7FFFFFFF
const int iFramesPerHeader = 8;
Mutex *g_pHeaderMutex;
extern "C"
{
PhysicalMediaOutput *Initialize(FAContext *context)
{
return new SoundCardPMO(context);
}
}
static void CALLBACK
MCICallBack(HWAVEOUT hwo, UINT msg, DWORD dwInstance,
DWORD dwParam1, DWORD dwParam2)
{
switch (msg)
{
case WOM_DONE:
{
LPWAVEHDR lpWaveHdr = (LPWAVEHDR) dwParam1;
g_pHeaderMutex->Acquire();
lpWaveHdr->dwUser = -((int)lpWaveHdr->dwUser);
g_pHeaderMutex->Release();
break;
}
}
}
SoundCardPMO::SoundCardPMO(FAContext *context) :
PhysicalMediaOutput(context)
{
MMRESULT mmresult = 0;
Int32PropValue *pProp;
m_hWnd =0;
m_wfex = NULL;
m_wavehdr_array = NULL;
m_hwo = NULL;
m_channels = 0;
m_samples_per_second = 0;
m_samples_per_frame = 0;
m_hdr_size = 0;
m_data_size = 0;
m_initialized = false;
m_pBufferThread = NULL;
g_pHeaderMutex = new Mutex();
m_iHead = 0;
m_iTail = 0;
m_iOffset = 0;
m_iBaseTime = MAXINT32;
m_iBytesPerSample = 0;
m_num_headers = 0;
m_iLastTime = 0;
// lillian
m_volume = NULL;
pBase = 0;
if (!m_pBufferThread)
{
m_pBufferThread = Thread::CreateThread();
assert(m_pBufferThread);
m_pBufferThread->Create(SoundCardPMO::StartWorkerThread, this);
}
if (IsError(m_pContext->props->GetProperty("MainWindow",
(PropValue **)&pProp)))
return;
else
m_hWnd = (HWND)pProp->GetInt32();
m_volume = new Win32Volume(Win32Volume::eWaveOut, m_hWnd);
}
SoundCardPMO::~SoundCardPMO()
{
m_bExit = true;
m_pSleepSem->Signal();
m_pPauseSem->Signal();
if (m_initialized)
{
waveOutReset(m_hwo);
for(int iLoop = 0; iLoop < m_num_headers; iLoop++)
{
if ((int)m_wavehdr_array[iLoop].dwUser < 0)
{
waveOutUnprepareHeader(m_hwo, &m_wavehdr_array[iLoop], sizeof(WAVEHDR));
}
}
while (waveOutClose(m_hwo) == WAVERR_STILLPLAYING)
{
usleep(100000);
}
delete m_wavehdr_array;
delete m_wfex;
}
if (m_pBufferThread)
{
m_pBufferThread->Join();
delete m_pBufferThread;
}
if (g_pHeaderMutex)
{
delete g_pHeaderMutex;
g_pHeaderMutex = NULL;
}
if ( m_volume )
{
delete m_volume;
m_volume = NULL;
}
}
void SoundCardPMO::GetVolume(int32 &left, int32 &right)
{
m_volume->GetVolume(left, right);
}
void SoundCardPMO::SetVolume(int32 left, int32 right)
{
m_volume->SetVolume(left, right);
}
Error SoundCardPMO::Init(OutputInfo * info)
{
Error result = kError_UnknownErr;
MMRESULT mmresult = 0;
Int32PropValue *pProp = NULL;
m_channels = info->number_of_channels;
m_samples_per_second = info->samples_per_second;
m_samples_per_frame = info->samples_per_frame;
m_data_size = info->max_buffer_size;
m_iBytesPerSample = info->number_of_channels * (info->bits_per_sample / 8);
m_num_headers = (m_pInputBuffer->GetBufferSize() / m_data_size) - 1;
m_hdr_size = sizeof(WAVEHDR);
m_wfex = new WAVEFORMATEX;
m_wfex->wBitsPerSample = info->bits_per_sample;
m_wfex->wFormatTag = WAVE_FORMAT_PCM;
m_wfex->nChannels = (WORD) m_channels;
m_wfex->nSamplesPerSec = info->samples_per_second;
m_wfex->nBlockAlign = (info->bits_per_sample / 8) * m_channels;
m_wfex->nAvgBytesPerSec = info->samples_per_second * m_wfex->nBlockAlign;
m_wfex->cbSize = 0;
mmresult = waveOutOpen(&m_hwo,
WAVE_MAPPER,
m_wfex,
(DWORD) MCICallBack,
NULL,
WAVE_ALLOWSYNC | CALLBACK_FUNCTION);
if (mmresult == MMSYSERR_NOERROR)
{
result = kError_NoErr;
}
uint32 i;
m_wavehdr_array = new WAVEHDR[m_num_headers];
for (i = 0; i < m_num_headers; i++)
{
m_wavehdr_array[i].dwBufferLength = m_data_size;
m_wavehdr_array[i].dwBytesRecorded = 0;
m_wavehdr_array[i].dwUser = 0;
m_wavehdr_array[i].dwLoops = 0;
m_wavehdr_array[i].dwFlags = NULL;
}
m_iBytesPerSample = info->number_of_channels * (info->bits_per_sample / 8);
m_initialized = true;
return result;
}
void SoundCardPMO::HandleTimeInfoEvent(PMOTimeInfoEvent *pEvent)
{
MediaTimeInfoEvent *pmtpi;
int32 hours, minutes, seconds;
int iTotalTime = 0;
MMTIME sTime;
if (m_iBaseTime == MAXINT32)
{
if (!pEvent)
return;
m_iBaseTime = (pEvent->GetFrameNumber() * m_samples_per_frame) /
m_samples_per_second;
sTime.wType = TIME_BYTES;
if (waveOutGetPosition(m_hwo, &sTime, sizeof(sTime)) != MMSYSERR_NOERROR)
return;
m_iBaseTime -= (sTime.u.cb / (m_samples_per_second * m_iBytesPerSample));
m_iLastTime = 0;
}
if (m_samples_per_second <= 0)
return;
sTime.wType = TIME_BYTES;
if (waveOutGetPosition(m_hwo, &sTime, sizeof(sTime)) != MMSYSERR_NOERROR)
return;
iTotalTime = (sTime.u.cb / (m_samples_per_second * m_iBytesPerSample)) +
m_iBaseTime;
// Time needs to be greater or equal to the last time for each pass,
// otherwise we have a break in playback, in which case we need to
// reset the base time. After a break in playback the waveOutGetPosition()
// function will reset back to 0.
// Alternatively, if m_iBaseTime gets messed up (i.e. its more than 24 hours!)
// force a reset as well.
if (iTotalTime < m_iLastTime || (m_iBaseTime > 86400 && m_iBaseTime < MAXINT32))
{
Debug_v("Reset: %d %d %d", iTotalTime, m_iLastTime, m_iBaseTime);
m_iBaseTime = MAXINT32;
return;
}
hours = iTotalTime / 3600;
minutes = (iTotalTime -
(hours * 3600)) / 60;
seconds = iTotalTime -
(hours * 3600) -
(minutes * 60);
// If something became wonky, reset.
if (minutes < 0 || minutes > 59 ||
seconds < 0 || seconds > 59 ||
hours < 0 || hours > 24)
{
m_iBaseTime = MAXINT32;
return;
}
pmtpi = new MediaTimeInfoEvent(hours, minutes, seconds, 0,
(float)iTotalTime, 0);
m_pTarget->AcceptEvent(pmtpi);
m_iLastTime = iTotalTime;
}
bool SoundCardPMO::WaitForDrain(void)
{
unsigned iLoop, iNumHeadersPending = 0;
for(; !m_bExit && !m_bPause; )
{
g_pHeaderMutex->Acquire();
for(iLoop = 0, iNumHeadersPending = 0; iLoop < m_num_headers; iLoop++)
{
if ((int)m_wavehdr_array[iLoop].dwUser > 0)
iNumHeadersPending++;
}
g_pHeaderMutex->Release();
if (iNumHeadersPending == 0)
{
return true;
}
WasteTime();
HandleTimeInfoEvent(NULL);
}
return false;
}
void SoundCardPMO::Pause(void)
{
m_iBaseTime = MAXINT32;
PhysicalMediaOutput::Pause();
}
void SoundCardPMO::Resume(void)
{
if (m_initialized)
waveOutRestart(m_hwo);
PhysicalMediaOutput::Resume();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -