📄 pa_win_wmme.c
字号:
return sPaHostError;}/*************************************************************************/int Pa_CountDevices(){ if( PaHost_IsInitialized() ) return sNumDevices; else return 0;}/************************************************************************* * If a PaDeviceInfo structure has not already been created, * then allocate one and fill it in for the selected device. * * We create one extra input and one extra output device for the WAVE_MAPPER. * [Does anyone know how to query the default device and get its name?] */const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ){#define NUM_STANDARDSAMPLINGRATES 3 /* 11025, 22050, 44100 */ static DWORD customSamplingRates[] = { 8000, 32000, 48000, 64000, 88200, 96000 };#define NUM_CUSTOMSAMPLINGRATES (sizeof(customSamplingRates)/sizeof(DWORD))#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES) PaDeviceInfo *deviceInfo; double *sampleRates; /* non-const ptr */ int i; char *s; if( id < 0 || id >= sNumDevices ) return NULL; if( sDevicePtrs[ id ] != NULL ) { return sDevicePtrs[ id ]; } deviceInfo = (PaDeviceInfo *)PaHost_AllocateTrackedMemory( sizeof(PaDeviceInfo) ); /* MEM */ if( deviceInfo == NULL ) return NULL; deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->numSampleRates = 0; sampleRates = (double*)PaHost_AllocateTrackedMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */ deviceInfo->sampleRates = sampleRates; deviceInfo->nativeSampleFormats = paInt16; /* should query for higher bit depths below */ if( id < sNumInputDevices ) { /* input device */ int inputMmID = PaDeviceIdToWinId(id); WAVEINCAPS wic; if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR ) goto error; /* Append I/O suffix to WAVE_MAPPER device. */ if( inputMmID == WAVE_MAPPER ) { s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */ strcpy( s, wic.szPname ); strcat( s, sMapperSuffixInput ); } else { s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 ); /* MEM */ strcpy( s, wic.szPname ); } deviceInfo->name = s; deviceInfo->maxInputChannels = wic.wChannels; /* Sometimes a device can return a rediculously large number of channels. * This happened with an SBLive card on a Windows ME box. * If that happens, then force it to 2 channels. PLB20010413 */ if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) ) { ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); deviceInfo->maxInputChannels = 2; } /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on the format flags. */ if( wic.dwFormats & WAVE_FORMAT_1M16 ||wic.dwFormats & WAVE_FORMAT_1S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 11025.; if( wic.dwFormats & WAVE_FORMAT_2M16 ||wic.dwFormats & WAVE_FORMAT_2S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; if( wic.dwFormats & WAVE_FORMAT_4M16 ||wic.dwFormats & WAVE_FORMAT_4S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on opening the device successfully. */ for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) { WAVEFORMATEX wfx; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nSamplesPerSec = customSamplingRates[i]; wfx.wBitsPerSample = 16; wfx.cbSize = 0; /* ignored */ wfx.nChannels = (WORD)deviceInfo->maxInputChannels; wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); if( waveInOpen( NULL, inputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) { sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i]; } } } else if( id - sNumInputDevices < sNumOutputDevices ) { /* output device */ int outputMmID = PaDeviceIdToWinId(id); WAVEOUTCAPS woc; if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR ) goto error; /* Append I/O suffix to WAVE_MAPPER device. */ if( outputMmID == WAVE_MAPPER ) { s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */ strcpy( s, woc.szPname ); strcat( s, sMapperSuffixOutput ); } else { s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 ); /* MEM */ strcpy( s, woc.szPname ); } deviceInfo->name = s; deviceInfo->maxOutputChannels = woc.wChannels; /* Sometimes a device can return a rediculously large number of channels. * This happened with an SBLive card on a Windows ME box. * It also happens on Win XP! */ if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) ) {#if 1 deviceInfo->maxOutputChannels = 2;#else /* If channel max is goofy, then query for max channels. PLB20020228 * This doesn't seem to help. Disable code for now. Remove it later. */ ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d!", deviceInfo->maxOutputChannels )); deviceInfo->maxOutputChannels = 0; /* Attempt to find the correct maximum by querying the device. */ for( i=2; i<16; i += 2 ) { WAVEFORMATEX wfx; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nSamplesPerSec = 44100; wfx.wBitsPerSample = 16; wfx.cbSize = 0; /* ignored */ wfx.nChannels = (WORD) i; wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) { deviceInfo->maxOutputChannels = i; } else { break; } }#endif ERR_RPT((" Changed to %d.\n", deviceInfo->maxOutputChannels )); } /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on the format flags. */ if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 11025.; if( woc.dwFormats & WAVE_FORMAT_2M16 ||woc.dwFormats & WAVE_FORMAT_2S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on opening the device successfully. */ for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) { WAVEFORMATEX wfx; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nSamplesPerSec = customSamplingRates[i]; wfx.wBitsPerSample = 16; wfx.cbSize = 0; /* ignored */ wfx.nChannels = (WORD)deviceInfo->maxOutputChannels; wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) { sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i]; } } } sDevicePtrs[ id ] = deviceInfo; return deviceInfo;error: PaHost_FreeTrackedMemory( sampleRates ); /* MEM */ PaHost_FreeTrackedMemory( deviceInfo ); /* MEM */ return NULL;}/************************************************************************* * Returns recommended device ID. * On the PC, the recommended device can be specified by the user by * setting an environment variable. For example, to use device #1. * * set PA_RECOMMENDED_OUTPUT_DEVICE=1 * * The user should first determine the available device ID by using * the supplied application "pa_devs". */#define PA_ENV_BUF_SIZE (32)#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ){ DWORD hresult; char envbuf[PA_ENV_BUF_SIZE]; PaDeviceID recommendedID = paNoDevice; /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { recommendedID = atoi( envbuf ); } return recommendedID;}/********************************************************************** * Check for environment variable, else query devices and use result. */PaDeviceID Pa_GetDefaultInputDeviceID( void ){ PaDeviceID result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); if( result == paNoDevice || result < 0 || result >= sNumInputDevices ) { result = sDefaultInputDeviceID; } return result;}PaDeviceID Pa_GetDefaultOutputDeviceID( void ){ PaDeviceID result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); if( result == paNoDevice || result < sNumInputDevices || result >= sNumDevices ) { result = sDefaultOutputDeviceID; } return result;}/********************************************************************** * Initialize Host dependant part of API. */PaError PaHost_Init( void ){#if PA_TRACK_MEMORY PRINT(("PaHost_Init: sNumAllocations = %d\n", sNumAllocations ));#endif#if PA_SIMULATE_UNDERFLOW PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n"));#endif Pa_InitializeNumDevices(); return Pa_AllocateDevicePtrs();}/********************************************************************** * Check WAVE buffers to see if they are done. * Fill any available output buffers and use any available * input buffers by calling user callback. * * This routine will loop until: * user callback returns !=0 OR * all output buffers are filled OR * past->past_StopSoon is set OR * an error occurs when calling WMME. * * Returns >0 when user requests a stop, <0 on error. * */static PaError Pa_TimeSlice( internalPortAudioStream *stream ){ PaError result = paNoError; MMRESULT mmresult; char *inBufPtr; char *outBufPtr; int gotInput = 0; int gotOutput = 0; int i; int buffersProcessed = 0; int done = 0; PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; if( wmmeStreamData == NULL ) return paInternalError; stream->past_NumCallbacks += 1;#if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", stream->past_NumCallbacks );#endif /* JM20020118 - prevent hung thread when buffers underflow. */ /* while( !done ) /* BAD */ while( !done && !stream->past_StopSoon ) /* GOOD */ {#if PA_SIMULATE_UNDERFLOW if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) { Sleep(UNDER_SLEEP_FOR); }#endif /* If we are using output, then we need an empty output buffer. */ gotOutput = 0; outBufPtr = NULL; if( stream->past_NumOutputChannels > 0 ) { if((wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].dwFlags & WHDR_DONE) == 0) { break; /* If none empty then bail and try again later. */ } else { outBufPtr = wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].lpData; gotOutput = 1; } } /* Use an input buffer if one is available. */ gotInput = 0; inBufPtr = NULL; if( ( stream->past_NumInputChannels > 0 ) && (wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].dwFlags & WHDR_DONE) ) { inBufPtr = wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].lpData; gotInput = 1;#if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: got input buffer at ", (int)inBufPtr );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -