📄 pa_win_ds.c
字号:
} else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; } /* IMPLEMENT ME: - if a full duplex stream is requested, check that the combination of input and output parameters is supported if necessary - check that the device supports sampleRate Because the buffer adapter handles conversion between all standard sample formats, the following checks are only required if paCustomFormat is implemented, or under some other unusual conditions. - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format */ return paFormatIsSupported;}/*************************************************************************** Determine minimum number of buffers required for this host based** on minimum latency. Latency can be optionally set by user by setting** an environment variable. For example, to set latency to 200 msec, put:**** set PA_MIN_LATENCY_MSEC=200**** in the AUTOEXEC.BAT file and reboot.** If the environment variable is not set, then the latency will be determined** based on the OS. Windows NT has higher latency than Win95.*/#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")#define PA_ENV_BUF_SIZE (32)static int PaWinDs_GetMinLatencyFrames( double sampleRate ){ char envbuf[PA_ENV_BUF_SIZE]; DWORD hresult; int minLatencyMsec = 0; /* Let user determine minimal latency by setting environment variable. */ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { minLatencyMsec = atoi( envbuf ); } else { minLatencyMsec = PaWinDS_GetMinSystemLatency();#if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));#endif } return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC);}static HRESULT InitInputBuffer( PaWinDsStream *stream, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer ){ DSCBUFFERDESC captureDesc; WAVEFORMATEX wfFormat; HRESULT result; stream->bytesPerInputFrame = nChannels * sizeof(short); // Define the buffer format wfFormat.wFormatTag = WAVE_FORMAT_PCM; wfFormat.nChannels = nChannels; wfFormat.nSamplesPerSec = nFrameRate; wfFormat.wBitsPerSample = 8 * sizeof(short); wfFormat.nBlockAlign = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8)); wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; wfFormat.cbSize = 0; /* No extended format info. */ stream->inputSize = bytesPerBuffer; // ---------------------------------------------------------------------- // Setup the secondary buffer description ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC)); captureDesc.dwSize = sizeof(DSCBUFFERDESC); captureDesc.dwFlags = 0; captureDesc.dwBufferBytes = bytesPerBuffer; captureDesc.lpwfxFormat = &wfFormat; // Create the capture buffer if ((result = IDirectSoundCapture_CreateCaptureBuffer( stream->pDirectSoundCapture, &captureDesc, &stream->pDirectSoundInputBuffer, NULL)) != DS_OK) return result; stream->readOffset = 0; // reset last read position to start of buffer return DS_OK;}static HRESULT InitOutputBuffer( PaWinDsStream *stream, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer ){ DWORD dwDataLen; DWORD playCursor; HRESULT result; LPDIRECTSOUNDBUFFER pPrimaryBuffer; HWND hWnd; HRESULT hr; WAVEFORMATEX wfFormat; DSBUFFERDESC primaryDesc; DSBUFFERDESC secondaryDesc; unsigned char* pDSBuffData; LARGE_INTEGER counterFrequency; stream->outputBufferSizeBytes = bytesPerBuffer; stream->outputIsRunning = FALSE; stream->outputUnderflowCount = 0; stream->dsw_framesWritten = 0; stream->bytesPerOutputFrame = nChannels * sizeof(short); // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the // applications's window. Also if that window is closed before the Buffer is closed // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.) // So we will use GetDesktopWindow() which was suggested by Miller Puckette. // hWnd = GetForegroundWindow(); // // FIXME: The example code I have on the net creates a hidden window that // is managed by our code - I think we should do that - one hidden // window for the whole of Pa_DS // hWnd = GetDesktopWindow(); // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz. // Exclusize also prevents unexpected sounds from other apps during a performance. if ((hr = IDirectSound_SetCooperativeLevel( stream->pDirectSound, hWnd, DSSCL_EXCLUSIVE)) != DS_OK) { return hr; } // ----------------------------------------------------------------------- // Create primary buffer and set format just so we can specify our custom format. // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz. // Setup the primary buffer description ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC)); primaryDesc.dwSize = sizeof(DSBUFFERDESC); primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth primaryDesc.dwBufferBytes = 0; primaryDesc.lpwfxFormat = NULL; // Create the buffer if ((result = IDirectSound_CreateSoundBuffer( stream->pDirectSound, &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result; // Define the buffer format wfFormat.wFormatTag = WAVE_FORMAT_PCM; wfFormat.nChannels = nChannels; wfFormat.nSamplesPerSec = nFrameRate; wfFormat.wBitsPerSample = 8 * sizeof(short); wfFormat.nBlockAlign = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8)); wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; wfFormat.cbSize = 0; /* No extended format info. */ // Set the primary buffer's format if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result; // ---------------------------------------------------------------------- // Setup the secondary buffer description ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC)); secondaryDesc.dwSize = sizeof(DSBUFFERDESC); secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; secondaryDesc.dwBufferBytes = bytesPerBuffer; secondaryDesc.lpwfxFormat = &wfFormat; // Create the secondary buffer if ((result = IDirectSound_CreateSoundBuffer( stream->pDirectSound, &secondaryDesc, &stream->pDirectSoundOutputBuffer, NULL)) != DS_OK) return result; // Lock the DS buffer if ((result = IDirectSoundBuffer_Lock( stream->pDirectSoundOutputBuffer, 0, stream->outputBufferSizeBytes, (LPVOID*)&pDSBuffData, &dwDataLen, NULL, 0, 0)) != DS_OK) return result; // Zero the DS buffer ZeroMemory(pDSBuffData, dwDataLen); // Unlock the DS buffer if ((result = IDirectSoundBuffer_Unlock( stream->pDirectSoundOutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result; if( QueryPerformanceFrequency( &counterFrequency ) ) { int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short)); stream->perfCounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate; } else { stream->perfCounterTicksPerBuffer.QuadPart = 0; } // Let DSound set the starting write position because if we set it to zero, it looks like the // buffer is full to begin with. This causes a long pause before sound starts when using large buffers. hr = IDirectSoundBuffer_GetCurrentPosition( stream->pDirectSoundOutputBuffer, &playCursor, &stream->outputBufferWriteOffsetBytes ); if( hr != DS_OK ) { return hr; } stream->dsw_framesWritten = stream->outputBufferWriteOffsetBytes / stream->bytesPerOutputFrame; /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */ return DS_OK;}/***********************************************************************************//* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ){ PaError result = paNoError; PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; PaWinDsStream *stream = 0; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; suggestedInputLatencyFrames = (unsigned long)(inputParameters->suggestedLatency * sampleRate); /* IDEA: the following 3 checks could be performed by default by pa_front unless some flag indicated otherwise */ /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate hostApiSpecificStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; inputSampleFormat = 0; suggestedInputLatencyFrames = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate); /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate hostApiSpecificStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; outputSampleFormat = 0; suggestedOutputLatencyFrames = 0; } /* IMPLEMENT ME: ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() ) - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - if a full duplex stream is requested, check that the combination of input and output parameters is supported - check that the device supports sampleRate - alter sampleRate to a close allowable rate if possible / necessary - validate suggestedInputLatency and suggestedOutputLatency parameters, use default values where necessary */ /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) ); if( !stream ) { result = paInsufficientMemory;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -