📄 pa_win_wmme.c
字号:
}
return result;
error:
return result;
}
/*******************************************************************/
PaError PaHost_OpenOutputStream( internalPortAudioStream *stream )
{
PaError result = paNoError;
MMRESULT mmresult;
PaWMMEStreamData *wmmeStreamData;
int i;
int outputMmID;
int bytesPerOutputFrame;
WAVEFORMATEX wfx;
const PaDeviceInfo *deviceInfo;
wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_OutputDeviceID));
deviceInfo = Pa_GetDeviceInfo( stream->past_OutputDeviceID );
if( deviceInfo == NULL ) return paInternalError;
switch( deviceInfo->nativeSampleFormats )
{
case paInt32:
case paFloat32:
bytesPerOutputFrame = sizeof(float) * stream->past_NumOutputChannels;
break;
default:
bytesPerOutputFrame = sizeof(short) * stream->past_NumOutputChannels;
break;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = (WORD) stream->past_NumOutputChannels;
wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate;
wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * stream->past_SampleRate);
wfx.nBlockAlign = (WORD)bytesPerOutputFrame;
wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/stream->past_NumOutputChannels) * 8);
wfx.cbSize = 0;
outputMmID = PaDeviceIdToWinId( stream->past_OutputDeviceID );
#if PA_USE_TIMER_CALLBACK
mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx,
0, 0, CALLBACK_NULL );
#else
wmmeStreamData->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( wmmeStreamData->abortEvent == NULL )
{
result = paHostError;
sPaHostError = GetLastError();
goto error;
}
wmmeStreamData->abortEventInited = 1;
mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx,
(DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
#endif
if( mmresult != MMSYSERR_NOERROR )
{
ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n"));
result = paHostError;
sPaHostError = mmresult;
goto error;
}
/* Allocate an array to hold the buffer pointers. */
wmmeStreamData->outputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */
if( wmmeStreamData->outputBuffers == NULL )
{
result = paInsufficientMemory;
goto error;
}
/* Allocate each buffer. */
for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
{
wmmeStreamData->outputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostOutputBuffer ); /* MEM */
if( wmmeStreamData->outputBuffers[i].lpData == NULL )
{
result = paInsufficientMemory;
goto error;
}
wmmeStreamData->outputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostOutputBuffer;
wmmeStreamData->outputBuffers[i].dwUser = i;
if( (mmresult = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mmresult;
goto error;
}
}
return result;
error:
return result;
}
/*******************************************************************/
PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *stream )
{
PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
return wmmeStreamData->numHostBuffers * wmmeStreamData->framesPerHostBuffer;
}
/*******************************************************************
* Determine number of WAVE Buffers
* and how many User Buffers we can put into each WAVE buffer.
*/
static void PaHost_CalcNumHostBuffers( internalPortAudioStream *stream )
{
PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
unsigned int minNumBuffers;
int minframesPerHostBuffer;
int maxframesPerHostBuffer;
int minTotalFrames;
int userBuffersPerHostBuffer;
int framesPerHostBuffer;
int numHostBuffers;
/* Calculate minimum and maximum sizes based on timing and sample rate. */
minframesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001);
minframesPerHostBuffer = (minframesPerHostBuffer + 7) & ~7;
DBUG(("PaHost_CalcNumHostBuffers: minframesPerHostBuffer = %d\n", minframesPerHostBuffer ));
maxframesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001);
maxframesPerHostBuffer = (maxframesPerHostBuffer + 7) & ~7;
DBUG(("PaHost_CalcNumHostBuffers: maxframesPerHostBuffer = %d\n", maxframesPerHostBuffer ));
/* Determine number of user buffers based on minimum latency. */
minNumBuffers = Pa_GetMinNumBuffers( stream->past_FramesPerUserBuffer, stream->past_SampleRate );
stream->past_NumUserBuffers = ( minNumBuffers > stream->past_NumUserBuffers ) ? minNumBuffers : stream->past_NumUserBuffers;
DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", stream->past_NumUserBuffers ));
minTotalFrames = stream->past_NumUserBuffers * stream->past_FramesPerUserBuffer;
/* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */
if( (int) stream->past_FramesPerUserBuffer < minframesPerHostBuffer )
{
userBuffersPerHostBuffer =
(minframesPerHostBuffer + stream->past_FramesPerUserBuffer - 1) /
stream->past_FramesPerUserBuffer;
}
else
{
userBuffersPerHostBuffer = 1;
}
framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
/* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
/* Make sure we have anough WAVE buffers. */
if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS)
{
numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
}
else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) &&
((int) stream->past_FramesPerUserBuffer < (maxframesPerHostBuffer/2) ) )
{
/* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */
while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS)
{
userBuffersPerHostBuffer += 1;
framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
/* If we have gone too far, back up one. */
if( (framesPerHostBuffer > maxframesPerHostBuffer) ||
(numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) )
{
userBuffersPerHostBuffer -= 1;
framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
break;
}
}
}
wmmeStreamData->userBuffersPerHostBuffer = userBuffersPerHostBuffer;
wmmeStreamData->framesPerHostBuffer = framesPerHostBuffer;
wmmeStreamData->numHostBuffers = numHostBuffers;
DBUG(("PaHost_CalcNumHostBuffers: userBuffersPerHostBuffer = %d\n", wmmeStreamData->userBuffersPerHostBuffer ));
DBUG(("PaHost_CalcNumHostBuffers: numHostBuffers = %d\n", wmmeStreamData->numHostBuffers ));
DBUG(("PaHost_CalcNumHostBuffers: framesPerHostBuffer = %d\n", wmmeStreamData->framesPerHostBuffer ));
DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", stream->past_NumUserBuffers ));
}
/*******************************************************************/
PaError PaHost_OpenStream( internalPortAudioStream *stream )
{
PaError result = paNoError;
PaWMMEStreamData *wmmeStreamData;
result = PaHost_AllocateWMMEStreamData( stream );
if( result != paNoError ) return result;
wmmeStreamData = PaHost_GetWMMEStreamData( stream );
/* Figure out how user buffers fit into WAVE buffers. */
PaHost_CalcNumHostBuffers( stream );
{
int msecLatency = (int) ((PaHost_GetTotalBufferFrames(stream) * 1000) / stream->past_SampleRate);
DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(stream), msecLatency ));
}
InitializeCriticalSection( &wmmeStreamData->streamLock );
wmmeStreamData->streamLockInited = 1;
#if (PA_USE_TIMER_CALLBACK == 0)
wmmeStreamData->bufferEventInited = 0;
wmmeStreamData->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if( wmmeStreamData->bufferEvent == NULL )
{
result = paHostError;
sPaHostError = GetLastError();
goto error;
}
wmmeStreamData->bufferEventInited = 1;
#endif /* (PA_USE_TIMER_CALLBACK == 0) */
/* ------------------ OUTPUT */
wmmeStreamData->bytesPerUserOutputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumOutputChannels * sizeof(short);
wmmeStreamData->bytesPerHostOutputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserOutputBuffer;
if( (stream->past_OutputDeviceID != paNoDevice) && (stream->past_NumOutputChannels > 0) )
{
result = PaHost_OpenOutputStream( stream );
if( result < 0 ) goto error;
}
/* ------------------ INPUT */
wmmeStreamData->bytesPerUserInputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumInputChannels * sizeof(short);
wmmeStreamData->bytesPerHostInputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserInputBuffer;
if( (stream->past_InputDeviceID != paNoDevice) && (stream->past_NumInputChannels > 0) )
{
result = PaHost_OpenInputStream( stream );
if( result < 0 ) goto error;
}
Pa_InitializeCpuUsageScalar( stream );
return result;
error:
PaHost_CloseStream( stream );
return result;
}
/*************************************************************************/
PaError PaHost_StartOutput( internalPortAudioStream *stream )
{
PaError result = paNoError;
MMRESULT mmresult;
int i;
PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream );
if( wmmeStreamData == NULL ) return paInternalError;
if( stream->past_OutputDeviceID != paNoDevice )
{
if( (mmresult = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mmresult;
goto error;
}
for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
{
ZeroMemory( wmmeStreamData->outputBuffers[i].lpData, wmmeStreamData->outputBuffers[i].dwBufferLength );
mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) );
if( mmresult != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mmresult;
goto error;
}
stream->past_FrameCount += wmmeStreamData->framesPerHostBuffer;
}
wmmeStreamData->currentOutputBuffer = 0;
if( (mmresult = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mmresult;
goto error;
}
}
error:
DBUG(("PaHost_StartOutput: wave returned mmresult = 0x%X.\n", mmresult));
return result;
}
/*************************************************************************/
PaError PaHost_StartInput( internalPortAudioStream *internalStream )
{
PaError result = paNoError;
MMRESULT mmresult;
int i;
PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream );
if( wmmeStreamData == NULL ) return paInternalError;
if( internalStream->past_InputDeviceID != paNoDevice )
{
for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
{
mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) );
if( mmresult != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mmresult;
goto error;
}
}
wmmeStreamData->currentInputBuffer = 0;
mmresult = waveInStart( wmmeStreamData->hWaveIn );
DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));
if( mmresult != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mmresult;
goto error;
}
}
error:
return result;
}
/*************************************************************************/
PaError PaHost_StartEngine( internalPortAudioStream *stream )
{
PaError result = paNoError;
PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream );
#if PA_USE_TIMER_CALLBACK
int resolution;
int bufsPerTimerCallback;
int msecPerBuffer;
#endif /* PA_USE_TIMER_CALLBACK */
if( wmmeStreamData == NULL ) return paInternalError;
stream->past_StopSoon = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -