📄 pa_win_wmme.c
字号:
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = (WORD) past->past_NumInputChannels;
wfx.nSamplesPerSec = (DWORD) past->past_SampleRate;
wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * past->past_SampleRate);
wfx.nBlockAlign = (WORD)bytesPerInputFrame;
wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/past->past_NumInputChannels) * 8);
wfx.cbSize = 0;
inputMmId = PaDeviceIdToWinId( past->past_InputDeviceID );
#if PA_USE_TIMER_CALLBACK
mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx,
0, 0, CALLBACK_NULL );
#else
mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx,
(DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT );
#endif
if( mr != MMSYSERR_NOERROR )
{
ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n"));
result = paHostError;
sPaHostError = mr;
goto error;
}
/* Allocate an array to hold the buffer pointers. */
pahsc->pahsc_InputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */
if( pahsc->pahsc_InputBuffers == NULL )
{
result = paInsufficientMemory;
goto error;
}
/* Allocate each buffer. */
for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
pahsc->pahsc_InputBuffers[i].lpData = (char *)GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostInputBuffer ); /* MEM */
if( pahsc->pahsc_InputBuffers[i].lpData == NULL )
{
result = paInsufficientMemory;
goto error;
}
pahsc->pahsc_InputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostInputBuffer;
pahsc->pahsc_InputBuffers[i].dwUser = i;
if( ( mr = waveInPrepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mr;
goto error;
}
}
return result;
error:
return result;
}
/*******************************************************************/
PaError PaHost_OpenOutputStream( internalPortAudioStream *past )
{
MMRESULT mr;
PaError result = paNoError;
PaHostSoundControl *pahsc;
int i;
int outputMmID;
int bytesPerOutputFrame;
WAVEFORMATEX wfx;
const PaDeviceInfo *pad;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
pad = Pa_GetDeviceInfo( past->past_OutputDeviceID );
if( pad == NULL ) return paInternalError;
switch( pad->nativeSampleFormats )
{
case paInt32:
case paFloat32:
bytesPerOutputFrame = sizeof(float) * past->past_NumOutputChannels;
break;
default:
bytesPerOutputFrame = sizeof(short) * past->past_NumOutputChannels;
break;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = (WORD) past->past_NumOutputChannels;
wfx.nSamplesPerSec = (DWORD) past->past_SampleRate;
wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * past->past_SampleRate);
wfx.nBlockAlign = (WORD)bytesPerOutputFrame;
wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/past->past_NumOutputChannels) * 8);
wfx.cbSize = 0;
outputMmID = PaDeviceIdToWinId( past->past_OutputDeviceID );
#if PA_USE_TIMER_CALLBACK
mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx,
0, 0, CALLBACK_NULL );
#else
pahsc->pahsc_AbortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( pahsc->pahsc_AbortEvent == NULL )
{
result = paHostError;
sPaHostError = GetLastError();
goto error;
}
pahsc->pahsc_AbortEventInited = 1;
mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx,
(DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT );
#endif
if( mr != MMSYSERR_NOERROR )
{
ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n"));
result = paHostError;
sPaHostError = mr;
goto error;
}
/* Allocate an array to hold the buffer pointers. */
pahsc->pahsc_OutputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */
if( pahsc->pahsc_OutputBuffers == NULL )
{
result = paInsufficientMemory;
goto error;
}
/* Allocate each buffer. */
for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
pahsc->pahsc_OutputBuffers[i].lpData = (char *) GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostOutputBuffer ); /* MEM */
if( pahsc->pahsc_OutputBuffers[i].lpData == NULL )
{
result = paInsufficientMemory;
goto error;
}
pahsc->pahsc_OutputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostOutputBuffer;
pahsc->pahsc_OutputBuffers[i].dwUser = i;
if( (mr = waveOutPrepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mr;
goto error;
}
}
return result;
error:
return result;
}
/*******************************************************************/
PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer;
}
/*******************************************************************
* Determine number of WAVE Buffers
* and how many User Buffers we can put into each WAVE buffer.
*/
static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->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 * past->past_SampleRate / 1000.0);
minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0);
maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7;
DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer ));
/* Determine number of user buffers based on minimum latency. */
minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
/* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */
if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
{
userBuffersPerHostBuffer =
(minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
past->past_FramesPerUserBuffer;
}
else
{
userBuffersPerHostBuffer = 1;
}
framesPerHostBuffer = past->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) past->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 = past->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 = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
break;
}
}
}
pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer;
pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer;
pahsc->pahsc_NumHostBuffers = numHostBuffers;
DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers ));
DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
}
/*******************************************************************/
PaError PaHost_OpenStream( internalPortAudioStream *past )
{
PaError result = paNoError;
PaHostSoundControl *pahsc;
/* Allocate and initialize host data. */
pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */
if( pahsc == NULL )
{
result = paInsufficientMemory;
goto error;
}
memset( pahsc, 0, sizeof(PaHostSoundControl) );
past->past_DeviceData = (void *) pahsc;
/* Figure out how user buffers fit into WAVE buffers. */
PaHost_CalcNumHostBuffers( past );
{
int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate);
DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency ));
}
InitializeCriticalSection( &pahsc->pahsc_StreamLock );
pahsc->pahsc_StreamLockInited = 1;
#if (PA_USE_TIMER_CALLBACK == 0)
pahsc->pahsc_BufferEventInited = 0;
pahsc->pahsc_BufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if( pahsc->pahsc_BufferEvent == NULL ){
result = paHostError;
sPaHostError = GetLastError();
goto error;
}
pahsc->pahsc_BufferEventInited = 1;
#endif /* (PA_USE_TIMER_CALLBACK == 0) */
/* ------------------ OUTPUT */
pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels * sizeof(short);
pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer;
if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) )
{
result = PaHost_OpenOutputStream( past );
if( result < 0 ) goto error;
}
/* ------------------ INPUT */
pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(short);
pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer;
if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) )
{
result = PaHost_OpenInputStream( past );
if( result < 0 ) goto error;
}
/* Calculate scalar used in CPULoad calculation. */
{
LARGE_INTEGER frequency;
if( QueryPerformanceFrequency( &frequency ) == 0 )
{
pahsc->pahsc_InverseTicksPerHostBuffer = 0.0;
}
else
{
pahsc->pahsc_InverseTicksPerHostBuffer = past->past_SampleRate /
( (double)frequency.QuadPart * past->past_FramesPerUserBuffer * pahsc->pahsc_UserBuffersPerHostBuffer );
DBUG(("pahsc_InverseTicksPerHostBuffer = %g\n", pahsc->pahsc_InverseTicksPerHostBuffer ));
}
}
return result;
error:
PaHost_CloseStream( past );
return result;
}
/*************************************************************************/
PaError PaHost_StartOutput( internalPortAudioStream *past )
{
MMRESULT mr;
PaHostSoundControl *pahsc;
PaError result = paNoError;
int i;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( past->past_OutputDeviceID != paNoDevice )
{
if( (mr = waveOutPause( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mr;
goto error;
}
for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
ZeroMemory( pahsc->pahsc_OutputBuffers[i].lpData, pahsc->pahsc_OutputBuffers[i].dwBufferLength );
mr = waveOutWrite( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) );
if( mr != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mr;
goto error;
}
past->past_FrameCount += pahsc->pahsc_FramesPerHostBuffer;
}
pahsc->pahsc_CurrentOutputBuffer = 0;
if( (mr = waveOutRestart( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mr;
goto error;
}
}
DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
error:
return result;
}
/*************************************************************************/
PaError PaHost_StartInput( internalPortAudioStream *past )
{
PaError result = paNoError;
MMRESULT mr;
int i;
PaHostSoundControl *pahsc;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( past->past_InputDeviceID != paNoDevice )
{
for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
mr = waveInAddBuffer( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) );
if( mr != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mr;
goto error;
}
}
pahsc->pahsc_CurrentInputBuffer = 0;
mr = waveInStart( pahsc->pahsc_HWaveIn );
DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", hr));
if( mr != MMSYSERR_NOERROR )
{
result = paHostError;
sPaHostError = mr;
goto error;
}
}
error:
return result;
}
/*************************************************************************/
PaError PaHost_StartEngine( internalPortAudioStream *past )
{
PaError result = paNoError;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
#if PA_USE_TIMER_CALLBACK
int resolution;
int bufsPerTimerCallback;
int msecPerBuffer;
#endif /* PA_USE_TIMER_CALLBACK */
//GJG20030416 I use this file to get runtime info
//you can pull this logging code out once everything is working
FILE *pa_stdout; // for portaudio logging
char pa_buf[256]; //char buffer for text
int pa_len; //length in bytes to write
int pa_nbw; //number of bytes written
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -