diff options
author | Miller Puckette <millerpuckette@users.sourceforge.net> | 2005-12-31 01:32:12 +0000 |
---|---|---|
committer | Miller Puckette <millerpuckette@users.sourceforge.net> | 2005-12-31 01:32:12 +0000 |
commit | fe8aa4ce5e8eebc1c6f762f4fc40328718a13e22 (patch) | |
tree | 90aabb628eeade33b37c3fe967557ca9b27ead62 /pd/portaudio_v18/pa_win_wmme | |
parent | 65a1b98552d7c6a93aedfb7c9b5d83f9038227cb (diff) |
Deleted unused (?) files
svn path=/trunk/; revision=4318
Diffstat (limited to 'pd/portaudio_v18/pa_win_wmme')
-rw-r--r-- | pd/portaudio_v18/pa_win_wmme/Makefile.cygwin | 34 | ||||
-rw-r--r-- | pd/portaudio_v18/pa_win_wmme/pa_win_wmme.c | 1714 |
2 files changed, 0 insertions, 1748 deletions
diff --git a/pd/portaudio_v18/pa_win_wmme/Makefile.cygwin b/pd/portaudio_v18/pa_win_wmme/Makefile.cygwin deleted file mode 100644 index 5cb4acef..00000000 --- a/pd/portaudio_v18/pa_win_wmme/Makefile.cygwin +++ /dev/null @@ -1,34 +0,0 @@ - -# Makefile for PortAudio on cygwin -# Contributed by Bill Eldridge on 6/13/2001 - -ARCH= pa_win_wmme - -TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) - -.c.o: - -gcc -c -I./pa_common $< -o $*.o - -gcc $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm - -all: sharedlib tests - -sharedlib: ./pa_common/pa_lib.c - gcc -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o - gcc -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o - dlltool --export-all --output-def pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o - gcc -shared -Wl,--enable-auto-image-base -o pa_win_wmme/portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/lib/w32api -lwinmm - cp pa_win_wmme/portaudio.dll /usr/local/bin - -tests: $(TESTS:.c=.o) - -sine: - gcc -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o - gcc pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm - -clean: - -rm ./pa_tests/*.exe - -nothing: - gcc pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm - - diff --git a/pd/portaudio_v18/pa_win_wmme/pa_win_wmme.c b/pd/portaudio_v18/pa_win_wmme/pa_win_wmme.c deleted file mode 100644 index 9dc03826..00000000 --- a/pd/portaudio_v18/pa_win_wmme/pa_win_wmme.c +++ /dev/null @@ -1,1714 +0,0 @@ -/* - * $Id: pa_win_wmme.c,v 1.6.4.3 2003/04/28 17:43:48 philburk Exp $ - * pa_win_wmme.c - * Implementation of PortAudio for Windows MultiMedia Extensions (WMME) - * - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * - * Authors: Ross Bencina and Phil Burk - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -/* - All memory allocations and frees are marked with MEM for quick review. -*/ - -/* Modification History: - PLB = Phil Burk - JM = Julien Maillard - RDB = Ross Bencina - PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer) - PLB20010413 - check for excessive numbers of channels - PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC - including condition including of memory.h, - and explicit typecasting on memory allocation - PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory - PLB20010816 - pass process instead of thread to SetPriorityClass() - PLB20010927 - use number of frames instead of real-time for CPULoad calculation. - JM20020118 - prevent hung thread when buffers underflow. - PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount - RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init - RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices - refactoring, renaming and fixed a few edge case bugs - PLB20020612 - added 8000.0 Hz to custom sampling rates array -*/ -#pragma warning (disable: 4115) -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <windows.h> -#include <mmsystem.h> -#include <process.h> -/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ -#ifndef __MWERKS__ -#include <malloc.h> -#include <memory.h> -#endif /* __MWERKS__ */ -#include "portaudio.h" -#include "pa_host.h" -#include "pa_trace.h" - -/************************************************* Constants ********/ -#define PA_TRACK_MEMORY (0) - -#define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ -/* Switches for debugging. */ -#define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ - -/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ -#define PA_TRACE_RUN (0) -#define PA_TRACE_START_STOP (1) - -#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ - -#if PA_USE_HIGH_LATENCY - #define PA_MIN_MSEC_PER_HOST_BUFFER (100) - #define PA_MAX_MSEC_PER_HOST_BUFFER (300) /* Do not exceed unless user buffer exceeds */ - #define PA_MIN_NUM_HOST_BUFFERS (4) - #define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ - #define PA_WIN_9X_LATENCY (400) -#else - #define PA_MIN_MSEC_PER_HOST_BUFFER (10) - #define PA_MAX_MSEC_PER_HOST_BUFFER (100) /* Do not exceed unless user buffer exceeds */ - #define PA_MIN_NUM_HOST_BUFFERS (3) - #define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ - #define PA_WIN_9X_LATENCY (200) -#endif -#define MIN_TIMEOUT_MSEC (1000) - -/* -** Use higher latency for NT because it is even worse at real-time -** operation than Win9x. -*/ -#define PA_WIN_NT_LATENCY (PA_WIN_9X_LATENCY * 2) -#define PA_WIN_WDM_LATENCY (PA_WIN_9X_LATENCY) - -#if PA_SIMULATE_UNDERFLOW -static gUnderCallbackCounter = 0; -#define UNDER_SLEEP_AT (40) -#define UNDER_SLEEP_FOR (500) -#endif - -#define PRINT(x) { printf x; fflush(stdout); } -#define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) */ -#define DBUGX(x) /* PRINT(x) */ -/************************************************* Definitions ********/ -/************************************************************** - * Structure for internal host specific stream data. - * This is allocated on a per stream basis. - */ -typedef struct PaWMMEStreamData -{ - /* Input -------------- */ - HWAVEIN hWaveIn; - WAVEHDR *inputBuffers; - int currentInputBuffer; - int bytesPerHostInputBuffer; - int bytesPerUserInputBuffer; /* native buffer size in bytes */ - /* Output -------------- */ - HWAVEOUT hWaveOut; - WAVEHDR *outputBuffers; - int currentOutputBuffer; - int bytesPerHostOutputBuffer; - int bytesPerUserOutputBuffer; /* native buffer size in bytes */ - /* Run Time -------------- */ - PaTimestamp framesPlayed; - long lastPosition; /* used to track frames played. */ - /* For measuring CPU utilization. */ - LARGE_INTEGER entryCount; - double inverseTicksPerHostBuffer; - /* Init Time -------------- */ - int numHostBuffers; - int framesPerHostBuffer; - int userBuffersPerHostBuffer; - CRITICAL_SECTION streamLock; /* Mutext to prevent threads from colliding. */ - INT streamLockInited; -#if PA_USE_TIMER_CALLBACK - BOOL ifInsideCallback; /* Test for reentrancy. */ - MMRESULT timerID; -#else - HANDLE abortEvent; - int abortEventInited; - HANDLE bufferEvent; - int bufferEventInited; - HANDLE engineThread; - DWORD engineThreadID; -#endif -} -PaWMMEStreamData; -/************************************************* Shared Data ********/ -/* FIXME - put Mutex around this shared data. */ -static int sNumInputDevices = 0; -static int sNumOutputDevices = 0; -static int sNumDevices = 0; -static PaDeviceInfo **sDevicePtrs = NULL; -static int sDefaultInputDeviceID = paNoDevice; -static int sDefaultOutputDeviceID = paNoDevice; -static int sPaHostError = 0; -static const char sMapperSuffixInput[] = " - Input"; -static const char sMapperSuffixOutput[] = " - Output"; - -#if PA_TRACK_MEMORY -static int sNumAllocations = 0; -#endif - -/************************************************* Macros ********/ -/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ -#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) -/************************************************* Prototypes **********/ - -void Pa_InitializeNumDevices( void ); -PaError Pa_AllocateDevicePtrs( void ); - -static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, - DWORD dwUser, DWORD dw1, DWORD dw2); -PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); -static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ); -static PaError PaHost_BackgroundManager( internalPortAudioStream *past ); - -static void *PaHost_AllocateTrackedMemory( long numBytes ); -static void PaHost_FreeTrackedMemory( void *addr ); - -/*******************************************************************/ -static PaError PaHost_AllocateWMMEStreamData( internalPortAudioStream *stream ) -{ - PaError result = paNoError; - PaWMMEStreamData *wmmeStreamData; - - wmmeStreamData = (PaWMMEStreamData *) PaHost_AllocateFastMemory(sizeof(PaWMMEStreamData)); /* MEM */ - if( wmmeStreamData == NULL ) - { - result = paInsufficientMemory; - goto error; - } - memset( wmmeStreamData, 0, sizeof(PaWMMEStreamData) ); - stream->past_DeviceData = (void *) wmmeStreamData; - - return result; - -error: - return result; -} - -/*******************************************************************/ -static void PaHost_FreeWMMEStreamData( internalPortAudioStream *internalStream ) -{ - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) internalStream->past_DeviceData; - - PaHost_FreeFastMemory( wmmeStreamData, sizeof(PaWMMEStreamData) ); /* MEM */ - internalStream->past_DeviceData = NULL; -} -/*************************************************************************/ -static PaWMMEStreamData* PaHost_GetWMMEStreamData( internalPortAudioStream* internalStream ) -{ - PaWMMEStreamData *result = NULL; - - if( internalStream != NULL ) - { - result = (PaWMMEStreamData *) internalStream->past_DeviceData; - } - return result; -} -/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ -/* FIXME: the cpu usage code should be factored out into a common module */ -static void Pa_InitializeCpuUsageScalar( internalPortAudioStream *stream ) -{ - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - - LARGE_INTEGER frequency; - if( QueryPerformanceFrequency( &frequency ) == 0 ) - { - wmmeStreamData->inverseTicksPerHostBuffer = 0.0; - } - else - { - wmmeStreamData->inverseTicksPerHostBuffer = stream->past_SampleRate / - ( (double)frequency.QuadPart * stream->past_FramesPerUserBuffer * wmmeStreamData->userBuffersPerHostBuffer ); - DBUG(("inverseTicksPerHostBuffer = %g\n", wmmeStreamData->inverseTicksPerHostBuffer )); - } -} -static void Pa_StartUsageCalculation( internalPortAudioStream *stream ) -{ - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - - if( wmmeStreamData == NULL ) return; - /* Query system timer for usage analysis and to prevent overuse of CPU. */ - QueryPerformanceCounter( &wmmeStreamData->entryCount ); -} -static void Pa_EndUsageCalculation( internalPortAudioStream *stream ) -{ - LARGE_INTEGER CurrentCount; - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - - if( wmmeStreamData == NULL ) return; - /* - * Measure CPU utilization during this callback. Note that this calculation - * assumes that we had the processor the whole time. - */ -#define LOWPASS_COEFFICIENT_0 (0.9) -#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) - if( QueryPerformanceCounter( &CurrentCount ) ) - { - LONGLONG InsideCount = CurrentCount.QuadPart - wmmeStreamData->entryCount.QuadPart; - double newUsage = InsideCount * wmmeStreamData->inverseTicksPerHostBuffer; - stream->past_Usage = (LOWPASS_COEFFICIENT_0 * stream->past_Usage) + - (LOWPASS_COEFFICIENT_1 * newUsage); - } -} -/****************************************** END CPU UTILIZATION *******/ - -static void Pa_InitializeNumDevices( void ) -{ - sNumInputDevices = waveInGetNumDevs(); - if( sNumInputDevices > 0 ) - { - sNumInputDevices += 1; /* add one extra for the WAVE_MAPPER */ - sDefaultInputDeviceID = 0; - } - else - { - sDefaultInputDeviceID = paNoDevice; - } - - sNumOutputDevices = waveOutGetNumDevs(); - if( sNumOutputDevices > 0 ) - { - sNumOutputDevices += 1; /* add one extra for the WAVE_MAPPER */ - sDefaultOutputDeviceID = sNumInputDevices; - } - else - { - sDefaultOutputDeviceID = paNoDevice; - } - - sNumDevices = sNumInputDevices + sNumOutputDevices; -} - -static PaError Pa_AllocateDevicePtrs( void ) -{ - int numBytes; - int i; - - /* Allocate structures to hold device info. */ - /* PLB20010402 - was allocating too much memory. */ - /* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */ - - if( sNumDevices > 0 ) - { - numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ - sDevicePtrs = (PaDeviceInfo **) PaHost_AllocateTrackedMemory( numBytes ); /* MEM */ - if( sDevicePtrs == NULL ) return paInsufficientMemory; - - for( i = 0; i < sNumDevices; i++ ) - sDevicePtrs[i] = NULL; /* RDB20020417 explicitly set each ptr to NULL */ - } - else - { - sDevicePtrs = NULL; - } - - return paNoError; -} -/*************************************************************************/ -long Pa_GetHostError() -{ - 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; - - DBUG(( "Pa_GetDeviceInfo( %d )\n", id )); - 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; - DBUG(( "Pa_GetDeviceInfo: input %s, maxChannels = %d\n", deviceInfo->name, deviceInfo->maxInputChannels )); - /* 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; - DBUG(( "Pa_GetDeviceInfo: output %s, maxChannels = %d\n", deviceInfo->name, deviceInfo->maxOutputChannels )); - /* 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)); - DBUG(( "Pa_GetDeviceInfo: waveOutOpen( ... WAVE_FORMAT_QUERY at SR = %d\n", customSamplingRates[i] )); - if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) - { - sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i]; - } - } - } - DBUG(( "Pa_GetDeviceInfo: done.\n" )); - 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 ); - AddTraceMessage("Pa_TimeSlice: got input buffer # ", wmmeStreamData->currentInputBuffer ); -#endif - - } - /* If we can't do anything then bail out. */ - if( !gotInput && !gotOutput ) break; - buffersProcessed += 1; - /* Each Wave buffer contains multiple user buffers so do them all now. */ - /* Base Usage on time it took to process one host buffer. */ - Pa_StartUsageCalculation( stream ); - for( i=0; i<wmmeStreamData->userBuffersPerHostBuffer; i++ ) - { - if( done ) - { - if( gotOutput ) - { - /* Clear remainder of wave buffer if we are waiting for stop. */ - AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); - memset( outBufPtr, 0, wmmeStreamData->bytesPerUserOutputBuffer ); - } - } - else - { - /* Convert 16 bit native data to user data and call user routine. */ - result = Pa_CallConvertInt16( stream, (short *) inBufPtr, (short *) outBufPtr ); - if( result != 0) done = 1; - } - if( gotInput ) inBufPtr += wmmeStreamData->bytesPerUserInputBuffer; - if( gotOutput) outBufPtr += wmmeStreamData->bytesPerUserOutputBuffer; - } - Pa_EndUsageCalculation( stream ); - /* Send WAVE buffer to Wave Device to be refilled. */ - if( gotInput ) - { - mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, - &wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ], - sizeof(WAVEHDR) ); - if( mmresult != MMSYSERR_NOERROR ) - { - sPaHostError = mmresult; - result = paHostError; - break; - } - wmmeStreamData->currentInputBuffer = (wmmeStreamData->currentInputBuffer+1 >= wmmeStreamData->numHostBuffers) ? - 0 : wmmeStreamData->currentInputBuffer+1; - } - /* Write WAVE buffer to Wave Device. */ - if( gotOutput ) - { -#if PA_TRACE_START_STOP - AddTraceMessage( "Pa_TimeSlice: writing buffer ", wmmeStreamData->currentOutputBuffer ); -#endif - mmresult = waveOutWrite( wmmeStreamData->hWaveOut, - &wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ], - sizeof(WAVEHDR) ); - if( mmresult != MMSYSERR_NOERROR ) - { - sPaHostError = mmresult; - result = paHostError; - break; - } - wmmeStreamData->currentOutputBuffer = (wmmeStreamData->currentOutputBuffer+1 >= wmmeStreamData->numHostBuffers) ? - 0 : wmmeStreamData->currentOutputBuffer+1; - } - - } - -#if PA_TRACE_RUN - AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed ); -#endif - return (result != 0) ? result : done; -} - -/*******************************************************************/ -static PaError PaHost_BackgroundManager( internalPortAudioStream *stream ) -{ - PaError result = paNoError; - int i; - int numQueuedoutputBuffers = 0; - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - - /* Has someone asked us to abort by calling Pa_AbortStream()? */ - if( stream->past_StopNow ) - { - stream->past_IsActive = 0; /* Will cause thread to return. */ - } - /* Has someone asked us to stop by calling Pa_StopStream() - * OR has a user callback returned '1' to indicate finished. - */ - else if( stream->past_StopSoon ) - { - /* Poll buffer and when all have played then exit thread. */ - /* Count how many output buffers are queued. */ - numQueuedoutputBuffers = 0; - if( stream->past_NumOutputChannels > 0 ) - { - for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) - { - if( !( wmmeStreamData->outputBuffers[ i ].dwFlags & WHDR_DONE) ) - { -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_BackgroundManager: waiting for buffer ", i ); -#endif - numQueuedoutputBuffers++; - } - } - } -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_BackgroundManager: numQueuedoutputBuffers ", numQueuedoutputBuffers ); -#endif - if( numQueuedoutputBuffers == 0 ) - { - stream->past_IsActive = 0; /* Will cause thread to return. */ - } - } - else - { - /* Process full input buffer and fill up empty output buffers. */ - if( (result = Pa_TimeSlice( stream )) != 0) - { - /* User callback has asked us to stop. */ -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_BackgroundManager: TimeSlice() returned ", result ); -#endif - stream->past_StopSoon = 1; /* Request that audio play out then stop. */ - result = paNoError; - } - } - - PaHost_UpdateStreamTime( wmmeStreamData ); - return result; -} - -#if PA_USE_TIMER_CALLBACK -/*******************************************************************/ -static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) -{ - internalPortAudioStream *stream; - PaWMMEStreamData *wmmeStreamData; - PaError result; - - stream = (internalPortAudioStream *) dwUser; - if( stream == NULL ) return; - wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - if( wmmeStreamData == NULL ) return; - if( wmmeStreamData->ifInsideCallback ) - { - if( wmmeStreamData->timerID != 0 ) - { - timeKillEvent(wmmeStreamData->timerID); /* Stop callback timer. */ - wmmeStreamData->timerID = 0; - } - return; - } - wmmeStreamData->ifInsideCallback = 1; - /* Manage flags and audio processing. */ - result = PaHost_BackgroundManager( stream ); - if( result != paNoError ) - { - stream->past_IsActive = 0; - } - wmmeStreamData->ifInsideCallback = 0; -} -#else /* PA_USE_TIMER_CALLBACK */ -/*******************************************************************/ -static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) -{ - internalPortAudioStream *stream; - PaWMMEStreamData *wmmeStreamData; - HANDLE events[2]; - int numEvents = 0; - DWORD result = 0; - DWORD waitResult; - DWORD numTimeouts = 0; - DWORD timeOut; - stream = (internalPortAudioStream *) pArg; - wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; -#if PA_TRACE_START_STOP - AddTraceMessage( "WinMMPa_OutputThreadProc: timeoutPeriod", timeoutPeriod ); - AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", stream->past_NumUserBuffers ); -#endif - /* Calculate timeOut as half the time it would take to play all buffers. */ - timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( stream ) / stream->past_SampleRate); - /* Get event(s) ready for wait. */ - events[numEvents++] = wmmeStreamData->bufferEvent; - if( wmmeStreamData->abortEventInited ) events[numEvents++] = wmmeStreamData->abortEvent; - /* Stay in this thread as long as we are "active". */ - while( stream->past_IsActive ) - { - /*******************************************************************/ - /******** WAIT here for an event from WMME or PA *******************/ - /*******************************************************************/ - waitResult = WaitForMultipleObjects( numEvents, events, FALSE, timeOut ); - /* Error? */ - if( waitResult == WAIT_FAILED ) - { - sPaHostError = GetLastError(); - result = paHostError; - stream->past_IsActive = 0; - } - /* Timeout? Don't stop. Just keep polling for DONE.*/ - else if( waitResult == WAIT_TIMEOUT ) - { -#if PA_TRACE_START_STOP - AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedoutputBuffers ); -#endif - numTimeouts += 1; - } - /* Manage flags and audio processing. */ - result = PaHost_BackgroundManager( stream ); - if( result != paNoError ) - { - stream->past_IsActive = 0; - } - } - return result; -} -#endif - -/*******************************************************************/ -PaError PaHost_OpenInputStream( internalPortAudioStream *stream ) -{ - PaError result = paNoError; - MMRESULT mmresult; - PaWMMEStreamData *wmmeStreamData; - int i; - int inputMmId; - int bytesPerInputFrame; - WAVEFORMATEX wfx; - const PaDeviceInfo *deviceInfo; - - wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_InputDeviceID)); - deviceInfo = Pa_GetDeviceInfo( stream->past_InputDeviceID ); - if( deviceInfo == NULL ) return paInternalError; - - switch( deviceInfo->nativeSampleFormats ) - { - case paInt32: - case paFloat32: - bytesPerInputFrame = sizeof(float) * stream->past_NumInputChannels; - break; - default: - bytesPerInputFrame = sizeof(short) * stream->past_NumInputChannels; - break; - } - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = (WORD) stream->past_NumInputChannels; - wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate; - wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * stream->past_SampleRate); - wfx.nBlockAlign = (WORD)bytesPerInputFrame; - wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/stream->past_NumInputChannels) * 8); - wfx.cbSize = 0; - inputMmId = PaDeviceIdToWinId( stream->past_InputDeviceID ); -#if PA_USE_TIMER_CALLBACK - mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, - 0, 0, CALLBACK_NULL ); -#else - mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, - (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); -#endif - if( mmresult != MMSYSERR_NOERROR ) - { - ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n")); - result = paHostError; - sPaHostError = mmresult; - goto error; - } - /* Allocate an array to hold the buffer pointers. */ - wmmeStreamData->inputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ - if( wmmeStreamData->inputBuffers == NULL ) - { - result = paInsufficientMemory; - goto error; - } - /* Allocate each buffer. */ - for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) - { - wmmeStreamData->inputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostInputBuffer ); /* MEM */ - if( wmmeStreamData->inputBuffers[i].lpData == NULL ) - { - result = paInsufficientMemory; - goto error; - } - wmmeStreamData->inputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostInputBuffer; - wmmeStreamData->inputBuffers[i].dwUser = i; - if( ( mmresult = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) - { - result = paHostError; - sPaHostError = mmresult; - goto error; - } - } - 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; - stream->past_StopNow = 0; - stream->past_IsActive = 1; - wmmeStreamData->framesPlayed = 0.0; - wmmeStreamData->lastPosition = 0; -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); -#endif -#if PA_USE_TIMER_CALLBACK - /* Create timer that will wake us up so we can fill the DSound buffer. */ - bufsPerTimerCallback = wmmeStreamData->numHostBuffers/4; - if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; - if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; - msecPerBuffer = (1000 * bufsPerTimerCallback * - wmmeStreamData->userBuffersPerHostBuffer * - internalStream->past_FramesPerUserBuffer ) / (int) internalStream->past_SampleRate; - if( msecPerBuffer < 10 ) msecPerBuffer = 10; - else if( msecPerBuffer > 100 ) msecPerBuffer = 100; - resolution = msecPerBuffer/4; - wmmeStreamData->timerID = timeSetEvent( msecPerBuffer, resolution, - (LPTIMECALLBACK) Pa_TimerCallback, - (DWORD) stream, TIME_PERIODIC ); - if( wmmeStreamData->timerID == 0 ) - { - result = paHostError; - sPaHostError = GetLastError();; - goto error; - } -#else /* PA_USE_TIMER_CALLBACK */ - ResetEvent( wmmeStreamData->abortEvent ); - /* Create thread that waits for audio buffers to be ready for processing. */ - wmmeStreamData->engineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, stream, 0, &wmmeStreamData->engineThreadID ); - if( wmmeStreamData->engineThread == NULL ) - { - result = paHostError; - sPaHostError = GetLastError();; - goto error; - } -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StartEngine: thread ", (int) wmmeStreamData->engineThread ); -#endif - /* I used to pass the thread which was failing. I now pass GetCurrentProcess(). - * This fix could improve latency for some applications. It could also result in CPU - * starvation if the callback did too much processing. - * I also added result checks, so we might see more failures at initialization. - * Thanks to Alberto di Bene for spotting this. - */ - if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */ - { - result = paHostError; - sPaHostError = GetLastError();; - goto error; - } - if( !SetThreadPriority( wmmeStreamData->engineThread, THREAD_PRIORITY_HIGHEST ) ) - { - result = paHostError; - sPaHostError = GetLastError();; - goto error; - } -#endif - -error: - return result; -} -/*************************************************************************/ -PaError PaHost_StopEngine( internalPortAudioStream *internalStream, int abort ) -{ - int timeOut; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - - if( wmmeStreamData == NULL ) return paNoError; - - /* Tell background thread to stop generating more data and to let current data play out. */ - internalStream->past_StopSoon = 1; - /* If aborting, tell background thread to stop NOW! */ - if( abort ) internalStream->past_StopNow = 1; - - /* Calculate timeOut longer than longest time it could take to play all buffers. */ - timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( internalStream ) / internalStream->past_SampleRate); - if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; - -#if PA_USE_TIMER_CALLBACK - if( (internalStream->past_OutputDeviceID != paNoDevice) && - internalStream->past_IsActive && - (wmmeStreamData->timerID != 0) ) - { - /* Wait for IsActive to drop. */ - while( (internalStream->past_IsActive) && (timeOut > 0) ) - { - Sleep(10); - timeOut -= 10; - } - timeKillEvent( wmmeStreamData->timerID ); /* Stop callback timer. */ - wmmeStreamData->timerID = 0; - } -#else /* PA_USE_TIMER_CALLBACK */ -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopEngine: thread ", (int) wmmeStreamData->engineThread ); -#endif - if( (internalStream->past_OutputDeviceID != paNoDevice) && - (internalStream->past_IsActive) && - (wmmeStreamData->engineThread != NULL) ) - { - DWORD got; - /* Tell background thread to stop generating more data and to let current data play out. */ - DBUG(("PaHost_StopEngine: waiting for background thread.\n")); - got = WaitForSingleObject( wmmeStreamData->engineThread, timeOut ); - if( got == WAIT_TIMEOUT ) - { - ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread to finish.\n")); - return paTimedOut; - } - CloseHandle( wmmeStreamData->engineThread ); - wmmeStreamData->engineThread = NULL; - } -#endif /* PA_USE_TIMER_CALLBACK */ - - internalStream->past_IsActive = 0; - return paNoError; -} -/*************************************************************************/ -PaError PaHost_StopInput( internalPortAudioStream *stream, int abort ) -{ - MMRESULT mmresult; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); - - if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ - (void) abort; /* unused parameter */ - - if( wmmeStreamData->hWaveIn != NULL ) - { - mmresult = waveInReset( wmmeStreamData->hWaveIn ); - if( mmresult != MMSYSERR_NOERROR ) - { - sPaHostError = mmresult; - return paHostError; - } - } - return paNoError; -} -/*************************************************************************/ -PaError PaHost_StopOutput( internalPortAudioStream *internalStream, int abort ) -{ - MMRESULT mmresult; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - - if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ - (void) abort; /* unused parameter */ - -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopOutput: hWaveOut ", (int) wmmeStreamData->hWaveOut ); -#endif - if( wmmeStreamData->hWaveOut != NULL ) - { - mmresult = waveOutReset( wmmeStreamData->hWaveOut ); - if( mmresult != MMSYSERR_NOERROR ) - { - sPaHostError = mmresult; - return paHostError; - } - } - return paNoError; -} -/*******************************************************************/ -PaError PaHost_CloseStream( internalPortAudioStream *stream ) -{ - int i; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); - - if( stream == NULL ) return paBadStreamPtr; - if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return no error? */ - -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_CloseStream: hWaveOut ", (int) wmmeStreamData->hWaveOut ); -#endif - /* Free data and device for output. */ - if( wmmeStreamData->hWaveOut ) - { - if( wmmeStreamData->outputBuffers ) - { - for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) - { - waveOutUnprepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); - PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers[i].lpData ); /* MEM */ - } - PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers ); /* MEM */ - } - waveOutClose( wmmeStreamData->hWaveOut ); - } - /* Free data and device for input. */ - if( wmmeStreamData->hWaveIn ) - { - if( wmmeStreamData->inputBuffers ) - { - for( i=0; i<wmmeStreamData->numHostBuffers; i++ ) - { - waveInUnprepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); - PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers[i].lpData ); /* MEM */ - } - PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers ); /* MEM */ - } - waveInClose( wmmeStreamData->hWaveIn ); - } -#if (PA_USE_TIMER_CALLBACK == 0) - if( wmmeStreamData->abortEventInited ) CloseHandle( wmmeStreamData->abortEvent ); - if( wmmeStreamData->bufferEventInited ) CloseHandle( wmmeStreamData->bufferEvent ); -#endif - if( wmmeStreamData->streamLockInited ) - DeleteCriticalSection( &wmmeStreamData->streamLock ); - - PaHost_FreeWMMEStreamData( stream ); - - return paNoError; -} -/************************************************************************* - * 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") -int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) -{ - char envbuf[PA_ENV_BUF_SIZE]; - DWORD hresult; - int minLatencyMsec = 0; - double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; - int minBuffers; - - /* 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 ); /* REVIEW: will we crash if the environment variable contains some nasty value? */ - } - else - { - /* Set minimal latency based on whether NT or other OS. - * NT has higher latency. - */ - OSVERSIONINFO osvi; - osvi.dwOSVersionInfoSize = sizeof( osvi ); - GetVersionEx( &osvi ); - DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); - DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); - DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); - /* Check for NT */ - if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) - { - minLatencyMsec = PA_WIN_NT_LATENCY; - } - else if(osvi.dwMajorVersion >= 5) - { - minLatencyMsec = PA_WIN_WDM_LATENCY; - } - else - { - minLatencyMsec = PA_WIN_9X_LATENCY; - } -#if PA_USE_HIGH_LATENCY - PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); -#endif - - } - DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); - minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); - if( minBuffers < 2 ) minBuffers = 2; - return minBuffers; -} -/************************************************************************* - * Cleanup device info. - */ -PaError PaHost_Term( void ) -{ - int i; - - if( sNumDevices > 0 ) - { - if( sDevicePtrs != NULL ) - { - for( i=0; i<sNumDevices; i++ ) - { - if( sDevicePtrs[i] != NULL ) - { - PaHost_FreeTrackedMemory( (char*)sDevicePtrs[i]->name ); /* MEM */ - PaHost_FreeTrackedMemory( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ - PaHost_FreeTrackedMemory( sDevicePtrs[i] ); /* MEM */ - } - } - PaHost_FreeTrackedMemory( sDevicePtrs ); /* MEM */ - sDevicePtrs = NULL; - } - sNumDevices = 0; - } - -#if PA_TRACK_MEMORY - PRINT(("PaHost_Term: sNumAllocations = %d\n", sNumAllocations )); -#endif - - return paNoError; -} -/*************************************************************************/ -void Pa_Sleep( long msec ) -{ - Sleep( msec ); -} -/************************************************************************* -FIXME: the following memory allocation routines should not be declared here - * Allocate memory that can be accessed in real-time. - * This may need to be held in physical memory so that it is not - * paged to virtual memory. - * This call MUST be balanced with a call to PaHost_FreeFastMemory(). - * Memory will be set to zero. - */ -void *PaHost_AllocateFastMemory( long numBytes ) -{ - return PaHost_AllocateTrackedMemory( numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */ -} -/************************************************************************* - * Free memory that could be accessed in real-time. - * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). - */ -void PaHost_FreeFastMemory( void *addr, long numBytes ) -{ - (void) numBytes; /* unused parameter */ - - PaHost_FreeTrackedMemory( addr ); /* MEM */ -} - -/************************************************************************* - * Track memory allocations to avoid leaks. - */ -static void *PaHost_AllocateTrackedMemory( long numBytes ) -{ - void *result = GlobalAlloc( GPTR, numBytes ); /* MEM */ - -#if PA_TRACK_MEMORY - if( result != NULL ) sNumAllocations += 1; -#endif - return result; -} - -static void PaHost_FreeTrackedMemory( void *addr ) -{ - if( addr != NULL ) - { - GlobalFree( addr ); /* MEM */ -#if PA_TRACK_MEMORY - sNumAllocations -= 1; -#endif - } -} - -/***********************************************************************/ -PaError PaHost_StreamActive( internalPortAudioStream *internalStream ) -{ - if( internalStream == NULL ) return paBadStreamPtr; - - return (PaError) internalStream->past_IsActive; -} -/************************************************************************* - * This must be called periodically because mmtime.u.sample - * is a DWORD and can wrap and lose sync after a few hours. - */ -static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ) -{ - MMRESULT mmresult; - MMTIME mmtime; - mmtime.wType = TIME_SAMPLES; - - if( wmmeStreamData->hWaveOut != NULL ) - { - mmresult = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) ); - } - else - { - mmresult = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) ); - } - - if( mmresult != MMSYSERR_NOERROR ) - { - sPaHostError = mmresult; - return paHostError; - } - - /* This data has two variables and is shared by foreground and background. - * So we need to make it thread safe. */ - EnterCriticalSection( &wmmeStreamData->streamLock ); - wmmeStreamData->framesPlayed += ((long)mmtime.u.sample) - wmmeStreamData->lastPosition; - wmmeStreamData->lastPosition = (long)mmtime.u.sample; - LeaveCriticalSection( &wmmeStreamData->streamLock ); - - return paNoError; -} -/*************************************************************************/ -PaTimestamp Pa_StreamTime( PortAudioStream *stream ) -{ - internalPortAudioStream *internalStream = PaHost_GetStreamRepresentation( stream ); - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - - if( internalStream == NULL ) return paBadStreamPtr; - if( wmmeStreamData == NULL ) return paInternalError; - - PaHost_UpdateStreamTime( wmmeStreamData ); - return wmmeStreamData->framesPlayed; -} -/*************************************************************************/ - - - |