diff options
Diffstat (limited to 'portaudio/qa/loopback/src/paqa.c')
-rw-r--r-- | portaudio/qa/loopback/src/paqa.c | 1601 |
1 files changed, 0 insertions, 1601 deletions
diff --git a/portaudio/qa/loopback/src/paqa.c b/portaudio/qa/loopback/src/paqa.c deleted file mode 100644 index 5eb6283..0000000 --- a/portaudio/qa/loopback/src/paqa.c +++ /dev/null @@ -1,1601 +0,0 @@ - -/* - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * - * Copyright (c) 1999-2010 Phil Burk and Ross Bencina - * - * 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. - * - * 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. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * 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. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <memory.h> -#include <math.h> -#include <string.h> - -#include "portaudio.h" - -#include "qa_tools.h" - -#include "paqa_tools.h" -#include "audio_analyzer.h" -#include "test_audio_analyzer.h" - -/** Accumulate counts for how many tests pass or fail. */ -int g_testsPassed = 0; -int g_testsFailed = 0; - -#define MAX_NUM_GENERATORS (8) -#define MAX_NUM_RECORDINGS (8) -#define MAX_BACKGROUND_NOISE_RMS (0.0004) -#define LOOPBACK_DETECTION_DURATION_SECONDS (0.8) -#define DEFAULT_FRAMES_PER_BUFFER (0) -#define PAQA_WAIT_STREAM_MSEC (100) -#define PAQA_TEST_DURATION (1.2) - -// Use two separate streams instead of one full duplex stream. -#define PAQA_FLAG_TWO_STREAMS (1<<0) -// Use bloching read/write for loopback. -#define PAQA_FLAG_USE_BLOCKING_IO (1<<1) - -const char * s_FlagOnNames[] = -{ - "Two Streams (Half Duplex)", - "Blocking Read/Write" -}; - -const char * s_FlagOffNames[] = -{ - "One Stream (Full Duplex)", - "Callback" -}; - - -/** Parameters that describe a single test run. */ -typedef struct TestParameters_s -{ - PaStreamParameters inputParameters; - PaStreamParameters outputParameters; - double sampleRate; - int samplesPerFrame; - int framesPerBuffer; - int maxFrames; - double baseFrequency; - double amplitude; - PaStreamFlags streamFlags; // paClipOff, etc - int flags; // PAQA_FLAG_TWO_STREAMS, PAQA_FLAG_USE_BLOCKING_IO -} TestParameters; - -typedef struct LoopbackContext_s -{ - // Generate a unique signal on each channel. - PaQaSineGenerator generators[MAX_NUM_GENERATORS]; - // Record each channel individually. - PaQaRecording recordings[MAX_NUM_RECORDINGS]; - - // Reported by the stream after it's opened - PaTime streamInfoInputLatency; - PaTime streamInfoOutputLatency; - - // Measured at runtime. - volatile int callbackCount; // incremented for each callback - volatile int inputBufferCount; // incremented if input buffer not NULL - int inputUnderflowCount; - int inputOverflowCount; - - volatile int outputBufferCount; // incremented if output buffer not NULL - int outputOverflowCount; - int outputUnderflowCount; - - // Measure whether input or output is lagging behind. - volatile int minInputOutputDelta; - volatile int maxInputOutputDelta; - - int minFramesPerBuffer; - int maxFramesPerBuffer; - int primingCount; - TestParameters *test; - volatile int done; -} LoopbackContext; - -typedef struct UserOptions_s -{ - int sampleRate; - int framesPerBuffer; - int inputLatency; - int outputLatency; - int saveBadWaves; - int verbose; - int waveFileCount; - const char *waveFilePath; - PaDeviceIndex inputDevice; - PaDeviceIndex outputDevice; -} UserOptions; - -#define BIG_BUFFER_SIZE (sizeof(float) * 2 * 2 * 1024) -static unsigned char g_ReadWriteBuffer[BIG_BUFFER_SIZE]; - -#define MAX_CONVERSION_SAMPLES (2 * 32 * 1024) -#define CONVERSION_BUFFER_SIZE (sizeof(float) * 2 * MAX_CONVERSION_SAMPLES) -static unsigned char g_ConversionBuffer[CONVERSION_BUFFER_SIZE]; - -/*******************************************************************/ -static int RecordAndPlaySinesCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) -{ - int i; - LoopbackContext *loopbackContext = (LoopbackContext *) userData; - - - loopbackContext->callbackCount += 1; - if( statusFlags & paInputUnderflow ) loopbackContext->inputUnderflowCount += 1; - if( statusFlags & paInputOverflow ) loopbackContext->inputOverflowCount += 1; - if( statusFlags & paOutputUnderflow ) loopbackContext->outputUnderflowCount += 1; - if( statusFlags & paOutputOverflow ) loopbackContext->outputOverflowCount += 1; - if( statusFlags & paPrimingOutput ) loopbackContext->primingCount += 1; - if( framesPerBuffer > loopbackContext->maxFramesPerBuffer ) - { - loopbackContext->maxFramesPerBuffer = framesPerBuffer; - } - if( framesPerBuffer < loopbackContext->minFramesPerBuffer ) - { - loopbackContext->minFramesPerBuffer = framesPerBuffer; - } - - /* This may get called with NULL inputBuffer during initial setup. - * We may also use the same callback with output only streams. - */ - if( inputBuffer != NULL) - { - int channelsPerFrame = loopbackContext->test->inputParameters.channelCount; - float *in = (float *)inputBuffer; - PaSampleFormat inFormat = loopbackContext->test->inputParameters.sampleFormat; - - loopbackContext->inputBufferCount += 1; - - if( inFormat != paFloat32 ) - { - int samplesToConvert = framesPerBuffer * channelsPerFrame; - in = (float *) g_ConversionBuffer; - if( samplesToConvert > MAX_CONVERSION_SAMPLES ) - { - // Hack to prevent buffer overflow. - // @todo Loop with small buffer instead of failing. - printf("Format conversion buffer too small!\n"); - return paComplete; - } - PaQa_ConvertToFloat( inputBuffer, samplesToConvert, inFormat, (float *) g_ConversionBuffer ); - } - - // Read each channel from the buffer. - for( i=0; i<channelsPerFrame; i++ ) - { - loopbackContext->done |= PaQa_WriteRecording( &loopbackContext->recordings[i], - in + i, - framesPerBuffer, - channelsPerFrame ); - } - } - - if( outputBuffer != NULL ) - { - int channelsPerFrame = loopbackContext->test->outputParameters.channelCount; - float *out = (float *)outputBuffer; - PaSampleFormat outFormat = loopbackContext->test->outputParameters.sampleFormat; - - loopbackContext->outputBufferCount += 1; - - if( outFormat != paFloat32 ) - { - // If we need to convert then mix to the g_ConversionBuffer and then convert into the PA outputBuffer. - out = (float *) g_ConversionBuffer; - } - - PaQa_EraseBuffer( out, framesPerBuffer, channelsPerFrame ); - for( i=0; i<channelsPerFrame; i++ ) - { - PaQa_MixSine( &loopbackContext->generators[i], - out + i, - framesPerBuffer, - channelsPerFrame ); - } - - if( outFormat != paFloat32 ) - { - int samplesToConvert = framesPerBuffer * channelsPerFrame; - if( samplesToConvert > MAX_CONVERSION_SAMPLES ) - { - printf("Format conversion buffer too small!\n"); - return paComplete; - } - PaQa_ConvertFromFloat( out, framesPerBuffer * channelsPerFrame, outFormat, outputBuffer ); - } - - } - - // Measure whether the input or output are lagging behind. - // Don't measure lag at end. - if( !loopbackContext->done ) - { - int inputOutputDelta = loopbackContext->inputBufferCount - loopbackContext->outputBufferCount; - if( loopbackContext->maxInputOutputDelta < inputOutputDelta ) - { - loopbackContext->maxInputOutputDelta = inputOutputDelta; - } - if( loopbackContext->minInputOutputDelta > inputOutputDelta ) - { - loopbackContext->minInputOutputDelta = inputOutputDelta; - } - } - - return loopbackContext->done ? paComplete : paContinue; -} - -static void CopyStreamInfoToLoopbackContext( LoopbackContext *loopbackContext, PaStream *inputStream, PaStream *outputStream ) -{ - const PaStreamInfo *inputStreamInfo = Pa_GetStreamInfo( inputStream ); - const PaStreamInfo *outputStreamInfo = Pa_GetStreamInfo( outputStream ); - - loopbackContext->streamInfoInputLatency = inputStreamInfo ? inputStreamInfo->inputLatency : -1; - loopbackContext->streamInfoOutputLatency = outputStreamInfo ? outputStreamInfo->outputLatency : -1; -} - -/*******************************************************************/ -/** - * Open a full duplex audio stream. - * Generate sine waves on the output channels and record the input channels. - * Then close the stream. - * @return 0 if OK or negative error. - */ -int PaQa_RunLoopbackFullDuplex( LoopbackContext *loopbackContext ) -{ - PaStream *stream = NULL; - PaError err = 0; - TestParameters *test = loopbackContext->test; - loopbackContext->done = 0; - // Use one full duplex stream. - err = Pa_OpenStream( - &stream, - &test->inputParameters, - &test->outputParameters, - test->sampleRate, - test->framesPerBuffer, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - RecordAndPlaySinesCallback, - loopbackContext ); - if( err != paNoError ) goto error; - - CopyStreamInfoToLoopbackContext( loopbackContext, stream, stream ); - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - // Wait for stream to finish. - while( loopbackContext->done == 0 ) - { - Pa_Sleep(PAQA_WAIT_STREAM_MSEC); - } - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; - - return 0; - -error: - return err; -} - -/*******************************************************************/ -/** - * Open two audio streams, one for input and one for output. - * Generate sine waves on the output channels and record the input channels. - * Then close the stream. - * @return 0 if OK or paTimedOut. - */ - -int PaQa_WaitForStream( LoopbackContext *loopbackContext ) -{ - int timeoutMSec = 1000 * PAQA_TEST_DURATION * 2; - - // Wait for stream to finish or timeout. - while( (loopbackContext->done == 0) && (timeoutMSec > 0) ) - { - Pa_Sleep(PAQA_WAIT_STREAM_MSEC); - timeoutMSec -= PAQA_WAIT_STREAM_MSEC; - } - - if( loopbackContext->done == 0 ) - { - printf("ERROR - stream completion timed out!"); - return paTimedOut; - } - return 0; -} - -/*******************************************************************/ -/** - * Open two audio streams, one for input and one for output. - * Generate sine waves on the output channels and record the input channels. - * Then close the stream. - * @return 0 if OK or negative error. - */ -int PaQa_RunLoopbackHalfDuplex( LoopbackContext *loopbackContext ) -{ - PaStream *inStream = NULL; - PaStream *outStream = NULL; - PaError err = 0; - int timedOut = 0; - TestParameters *test = loopbackContext->test; - loopbackContext->done = 0; - - // Use two half duplex streams. - err = Pa_OpenStream( - &inStream, - &test->inputParameters, - NULL, - test->sampleRate, - test->framesPerBuffer, - test->streamFlags, - RecordAndPlaySinesCallback, - loopbackContext ); - if( err != paNoError ) goto error; - err = Pa_OpenStream( - &outStream, - NULL, - &test->outputParameters, - test->sampleRate, - test->framesPerBuffer, - test->streamFlags, - RecordAndPlaySinesCallback, - loopbackContext ); - if( err != paNoError ) goto error; - - CopyStreamInfoToLoopbackContext( loopbackContext, inStream, outStream ); - - err = Pa_StartStream( inStream ); - if( err != paNoError ) goto error; - - // Start output later so we catch the beginning of the waveform. - err = Pa_StartStream( outStream ); - if( err != paNoError ) goto error; - - timedOut = PaQa_WaitForStream( loopbackContext ); - - err = Pa_StopStream( inStream ); - if( err != paNoError ) goto error; - - err = Pa_StopStream( outStream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( inStream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( outStream ); - if( err != paNoError ) goto error; - - return timedOut; - -error: - return err; -} - - -/*******************************************************************/ -/** - * Open one audio streams, just for input. - * Record background level. - * Then close the stream. - * @return 0 if OK or negative error. - */ -int PaQa_RunInputOnly( LoopbackContext *loopbackContext ) -{ - PaStream *inStream = NULL; - PaError err = 0; - int timedOut = 0; - TestParameters *test = loopbackContext->test; - loopbackContext->done = 0; - - // Just open an input stream. - err = Pa_OpenStream( - &inStream, - &test->inputParameters, - NULL, - test->sampleRate, - test->framesPerBuffer, - paClipOff, /* We won't output out of range samples so don't bother clipping them. */ - RecordAndPlaySinesCallback, - loopbackContext ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( inStream ); - if( err != paNoError ) goto error; - - timedOut = PaQa_WaitForStream( loopbackContext ); - - err = Pa_StopStream( inStream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( inStream ); - if( err != paNoError ) goto error; - - return timedOut; - -error: - return err; -} - -/*******************************************************************/ -static int RecordAndPlayBlockingIO( PaStream *inStream, - PaStream *outStream, - LoopbackContext *loopbackContext - ) -{ - int i; - float *in = (float *)g_ReadWriteBuffer; - float *out = (float *)g_ReadWriteBuffer; - PaError err; - int done = 0; - long available; - const long maxPerBuffer = 64; - TestParameters *test = loopbackContext->test; - long framesPerBuffer = test->framesPerBuffer; - if( framesPerBuffer <= 0 ) - { - framesPerBuffer = maxPerBuffer; // bigger values might run past end of recording - } - - // Read in audio. - err = Pa_ReadStream( inStream, in, framesPerBuffer ); - // Ignore an overflow on the first read. - //if( !((loopbackContext->callbackCount == 0) && (err == paInputOverflowed)) ) - if( err != paInputOverflowed ) - { - QA_ASSERT_EQUALS( "Pa_ReadStream failed", paNoError, err ); - } - else - { - loopbackContext->inputOverflowCount += 1; - } - - - // Save in a recording. - for( i=0; i<loopbackContext->test->inputParameters.channelCount; i++ ) - { - done |= PaQa_WriteRecording( &loopbackContext->recordings[i], - in + i, - framesPerBuffer, - loopbackContext->test->inputParameters.channelCount ); - } - - // Synthesize audio. - available = Pa_GetStreamWriteAvailable( outStream ); - if( available > (2*framesPerBuffer) ) available = (2*framesPerBuffer); - PaQa_EraseBuffer( out, available, loopbackContext->test->outputParameters.channelCount ); - for( i=0; i<loopbackContext->test->outputParameters.channelCount; i++ ) - { - PaQa_MixSine( &loopbackContext->generators[i], - out + i, - available, - loopbackContext->test->outputParameters.channelCount ); - } - - // Write out audio. - err = Pa_WriteStream( outStream, out, available ); - // Ignore an underflow on the first write. - //if( !((loopbackContext->callbackCount == 0) && (err == paOutputUnderflowed)) ) - if( err != paOutputUnderflowed ) - { - QA_ASSERT_EQUALS( "Pa_WriteStream failed", paNoError, err ); - } - else - { - loopbackContext->outputUnderflowCount += 1; - } - - - loopbackContext->callbackCount += 1; - - return done; -error: - return err; -} - - -/*******************************************************************/ -/** - * Open two audio streams with non-blocking IO. - * Generate sine waves on the output channels and record the input channels. - * Then close the stream. - * @return 0 if OK or negative error. - */ -int PaQa_RunLoopbackHalfDuplexBlockingIO( LoopbackContext *loopbackContext ) -{ - PaStream *inStream = NULL; - PaStream *outStream = NULL; - PaError err = 0; - TestParameters *test = loopbackContext->test; - - // Use two half duplex streams. - err = Pa_OpenStream( - &inStream, - &test->inputParameters, - NULL, - test->sampleRate, - test->framesPerBuffer, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - NULL, // causes non-blocking IO - NULL ); - if( err != paNoError ) goto error1; - err = Pa_OpenStream( - &outStream, - NULL, - &test->outputParameters, - test->sampleRate, - test->framesPerBuffer, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - NULL, // causes non-blocking IO - NULL ); - if( err != paNoError ) goto error2; - - CopyStreamInfoToLoopbackContext( loopbackContext, inStream, outStream ); - - err = Pa_StartStream( outStream ); - if( err != paNoError ) goto error3; - - err = Pa_StartStream( inStream ); - if( err != paNoError ) goto error3; - - while( err == 0 ) - { - err = RecordAndPlayBlockingIO( inStream, outStream, loopbackContext ); - if( err < 0 ) goto error3; - } - - err = Pa_StopStream( inStream ); - if( err != paNoError ) goto error3; - - err = Pa_StopStream( outStream ); - if( err != paNoError ) goto error3; - - err = Pa_CloseStream( outStream ); - if( err != paNoError ) goto error2; - - err = Pa_CloseStream( inStream ); - if( err != paNoError ) goto error1; - - - return 0; - -error3: - Pa_CloseStream( outStream ); -error2: - Pa_CloseStream( inStream ); -error1: - return err; -} - - -/*******************************************************************/ -/** - * Open one audio stream with non-blocking IO. - * Generate sine waves on the output channels and record the input channels. - * Then close the stream. - * @return 0 if OK or negative error. - */ -int PaQa_RunLoopbackFullDuplexBlockingIO( LoopbackContext *loopbackContext ) -{ - PaStream *stream = NULL; - PaError err = 0; - TestParameters *test = loopbackContext->test; - - // Use one full duplex stream. - err = Pa_OpenStream( - &stream, - &test->inputParameters, - &test->outputParameters, - test->sampleRate, - test->framesPerBuffer, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - NULL, // causes non-blocking IO - NULL ); - if( err != paNoError ) goto error1; - - CopyStreamInfoToLoopbackContext( loopbackContext, stream, stream ); - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error2; - - while( err == 0 ) - { - err = RecordAndPlayBlockingIO( stream, stream, loopbackContext ); - if( err < 0 ) goto error2; - } - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error2; - - - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error1; - - - return 0; - -error2: - Pa_CloseStream( stream ); -error1: - return err; -} - - -/*******************************************************************/ -/** - * Run some kind of loopback test. - * @return 0 if OK or negative error. - */ -int PaQa_RunLoopback( LoopbackContext *loopbackContext ) -{ - PaError err = 0; - TestParameters *test = loopbackContext->test; - - - if( test->flags & PAQA_FLAG_TWO_STREAMS ) - { - if( test->flags & PAQA_FLAG_USE_BLOCKING_IO ) - { - err = PaQa_RunLoopbackHalfDuplexBlockingIO( loopbackContext ); - } - else - { - err = PaQa_RunLoopbackHalfDuplex( loopbackContext ); - } - } - else - { - if( test->flags & PAQA_FLAG_USE_BLOCKING_IO ) - { - err = PaQa_RunLoopbackFullDuplexBlockingIO( loopbackContext ); - } - else - { - err = PaQa_RunLoopbackFullDuplex( loopbackContext ); - } - } - - if( err != paNoError ) - { - printf("PortAudio error = %s\n", Pa_GetErrorText( err ) ); - } - return err; -} - -/*******************************************************************/ -static int PaQa_SaveTestResultToWaveFile( UserOptions *userOptions, PaQaRecording *recording ) -{ - if( userOptions->saveBadWaves ) - { - char filename[256]; -#ifdef WIN32 - _snprintf( filename, sizeof(filename), "%s\\paloopback_%d.wav", userOptions->waveFilePath, userOptions->waveFileCount++ ); -#else - snprintf( filename, sizeof(filename), "%s/paloopback_%d.wav", userOptions->waveFilePath, userOptions->waveFileCount++ ); -#endif - printf( "\"%s\", ", filename ); - return PaQa_SaveRecordingToWaveFile( recording, filename ); - } - return 0; -} - -/*******************************************************************/ -static int PaQa_SetupLoopbackContext( LoopbackContext *loopbackContextPtr, TestParameters *testParams ) -{ - int i; - // Setup loopback context. - memset( loopbackContextPtr, 0, sizeof(LoopbackContext) ); - loopbackContextPtr->test = testParams; - for( i=0; i<testParams->samplesPerFrame; i++ ) - { - int err = PaQa_InitializeRecording( &loopbackContextPtr->recordings[i], testParams->maxFrames, testParams->sampleRate ); - QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", paNoError, err ); - } - for( i=0; i<testParams->samplesPerFrame; i++ ) - { - PaQa_SetupSineGenerator( &loopbackContextPtr->generators[i], PaQa_GetNthFrequency( testParams->baseFrequency, i ), - testParams->amplitude, testParams->sampleRate ); - } - loopbackContextPtr->minFramesPerBuffer = 0x0FFFFFFF; - return 0; -error: - return -1; -} - -/*******************************************************************/ -static void PaQa_TeardownLoopbackContext( LoopbackContext *loopbackContextPtr ) -{ - int i; - if( loopbackContextPtr->test != NULL ) - { - for( i=0; i<loopbackContextPtr->test->samplesPerFrame; i++ ) - { - PaQa_TerminateRecording( &loopbackContextPtr->recordings[i] ); - } - } -} - -/*******************************************************************/ -static void PaQa_PrintShortErrorReport( PaQaAnalysisResult *analysisResultPtr, int channel ) -{ - printf("channel %d ", channel); - if( analysisResultPtr->popPosition > 0 ) - { - printf("POP %0.3f at %d, ", (double)analysisResultPtr->popAmplitude, (int)analysisResultPtr->popPosition ); - } - else - { - if( analysisResultPtr->addedFramesPosition > 0 ) - { - printf("ADD %d at %d ", (int)analysisResultPtr->numAddedFrames, (int)analysisResultPtr->addedFramesPosition ); - } - - if( analysisResultPtr->droppedFramesPosition > 0 ) - { - printf("DROP %d at %d ", (int)analysisResultPtr->numDroppedFrames, (int)analysisResultPtr->droppedFramesPosition ); - } - } -} - -/*******************************************************************/ -static void PaQa_PrintFullErrorReport( PaQaAnalysisResult *analysisResultPtr, int channel ) -{ - printf("\n=== Loopback Analysis ===================\n"); - printf(" channel: %d\n", channel ); - printf(" latency: %10.3f\n", analysisResultPtr->latency ); - printf(" amplitudeRatio: %10.3f\n", (double)analysisResultPtr->amplitudeRatio ); - printf(" popPosition: %10.3f\n", (double)analysisResultPtr->popPosition ); - printf(" popAmplitude: %10.3f\n", (double)analysisResultPtr->popAmplitude ); - printf(" num added frames: %10.3f\n", analysisResultPtr->numAddedFrames ); - printf(" added frames at: %10.3f\n", analysisResultPtr->addedFramesPosition ); - printf(" num dropped frames: %10.3f\n", analysisResultPtr->numDroppedFrames ); - printf(" dropped frames at: %10.3f\n", analysisResultPtr->droppedFramesPosition ); -} - -/*******************************************************************/ -/** - * Test loopback connection using the given parameters. - * @return number of channels with glitches, or negative error. - */ -static int PaQa_SingleLoopBackTest( UserOptions *userOptions, TestParameters *testParams ) -{ - int i; - LoopbackContext loopbackContext; - PaError err = paNoError; - PaQaTestTone testTone; - PaQaAnalysisResult analysisResult; - int numBadChannels = 0; - - printf("| %5d | %6d | ", ((int)(testParams->sampleRate+0.5)), testParams->framesPerBuffer ); - fflush(stdout); - - testTone.samplesPerFrame = testParams->samplesPerFrame; - testTone.sampleRate = testParams->sampleRate; - testTone.amplitude = testParams->amplitude; - testTone.startDelay = 0; - - err = PaQa_SetupLoopbackContext( &loopbackContext, testParams ); - if( err ) return err; - - err = PaQa_RunLoopback( &loopbackContext ); - QA_ASSERT_TRUE("loopback did not run", (loopbackContext.callbackCount > 1) ); - - printf( "%7.2f %7.2f %7.2f | ", - loopbackContext.streamInfoInputLatency * 1000.0, - loopbackContext.streamInfoOutputLatency * 1000.0, - (loopbackContext.streamInfoInputLatency + loopbackContext.streamInfoOutputLatency) * 1000.0 - ); - - printf( "%4d/%4d/%4d, %4d/%4d/%4d | ", - loopbackContext.inputOverflowCount, - loopbackContext.inputUnderflowCount, - loopbackContext.inputBufferCount, - loopbackContext.outputOverflowCount, - loopbackContext.outputUnderflowCount, - loopbackContext.outputBufferCount - ); - - // Analyse recording to detect glitches. - for( i=0; i<testParams->samplesPerFrame; i++ ) - { - double freq = PaQa_GetNthFrequency( testParams->baseFrequency, i ); - testTone.frequency = freq; - - PaQa_AnalyseRecording( &loopbackContext.recordings[i], &testTone, &analysisResult ); - - if( i==0 ) - { - double latencyMSec; - - printf( "%4d-%4d | ", - loopbackContext.minFramesPerBuffer, - loopbackContext.maxFramesPerBuffer - ); - - latencyMSec = 1000.0 * analysisResult.latency / testParams->sampleRate; - printf("%7.2f | ", latencyMSec ); - - } - - if( analysisResult.valid ) - { - int badChannel = ( (analysisResult.popPosition > 0) - || (analysisResult.addedFramesPosition > 0) - || (analysisResult.droppedFramesPosition > 0) ); - - if( badChannel ) - { - if( userOptions->verbose ) - { - PaQa_PrintFullErrorReport( &analysisResult, i ); - } - else - { - PaQa_PrintShortErrorReport( &analysisResult, i ); - } - PaQa_SaveTestResultToWaveFile( userOptions, &loopbackContext.recordings[i] ); - } - numBadChannels += badChannel; - } - else - { - printf( "[%d] No or low signal, ampRatio = %f", i, analysisResult.amplitudeRatio ); - numBadChannels += 1; - } - - } - if( numBadChannels == 0 ) - { - printf( "OK" ); - } - - // Print the # errors so far to make it easier to see where the error occurred. - printf( " - #errs = %d\n", g_testsFailed ); - - PaQa_TeardownLoopbackContext( &loopbackContext ); - if( numBadChannels > 0 ) - { - g_testsFailed += 1; - } - return numBadChannels; - -error: - PaQa_TeardownLoopbackContext( &loopbackContext ); - printf( "\n" ); - g_testsFailed += 1; - return err; -} - -/*******************************************************************/ -static void PaQa_SetDefaultTestParameters( TestParameters *testParamsPtr, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice ) -{ - memset( testParamsPtr, 0, sizeof(TestParameters) ); - - testParamsPtr->samplesPerFrame = 2; - testParamsPtr->amplitude = 0.5; - testParamsPtr->sampleRate = 44100; - testParamsPtr->maxFrames = (int) (PAQA_TEST_DURATION * testParamsPtr->sampleRate); - testParamsPtr->framesPerBuffer = DEFAULT_FRAMES_PER_BUFFER; - testParamsPtr->baseFrequency = 200.0; - testParamsPtr->flags = PAQA_FLAG_TWO_STREAMS; - testParamsPtr->streamFlags = paClipOff; /* we won't output out of range samples so don't bother clipping them */ - - testParamsPtr->inputParameters.device = inputDevice; - testParamsPtr->inputParameters.sampleFormat = paFloat32; - testParamsPtr->inputParameters.channelCount = testParamsPtr->samplesPerFrame; - testParamsPtr->inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputDevice )->defaultLowInputLatency; - //testParamsPtr->inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputDevice )->defaultHighInputLatency; - - testParamsPtr->outputParameters.device = outputDevice; - testParamsPtr->outputParameters.sampleFormat = paFloat32; - testParamsPtr->outputParameters.channelCount = testParamsPtr->samplesPerFrame; - testParamsPtr->outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputDevice )->defaultLowOutputLatency; - //testParamsPtr->outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputDevice )->defaultHighOutputLatency; -} - -/*******************************************************************/ -static void PaQa_OverrideTestParameters( TestParameters *testParamsPtr, UserOptions *userOptions ) -{ - // Check to see if a specific value was requested. - if( userOptions->sampleRate >= 0 ) - { - testParamsPtr->sampleRate = userOptions->sampleRate; - testParamsPtr->maxFrames = (int) (PAQA_TEST_DURATION * testParamsPtr->sampleRate); - } - if( userOptions->framesPerBuffer >= 0 ) - { - testParamsPtr->framesPerBuffer = userOptions->framesPerBuffer; - } - if( userOptions->inputLatency >= 0 ) - { - testParamsPtr->inputParameters.suggestedLatency = userOptions->inputLatency * 0.001; - } - if( userOptions->outputLatency >= 0 ) - { - testParamsPtr->outputParameters.suggestedLatency = userOptions->outputLatency * 0.001; - } - printf( " Running with suggested latency (msec): input = %5.2f, out = %5.2f\n", - (testParamsPtr->inputParameters.suggestedLatency * 1000.0), - (testParamsPtr->outputParameters.suggestedLatency * 1000.0) ); -} - -/*******************************************************************/ -/** - * Run a series of tests on this loopback connection. - * @return number of bad channel results - */ -static int PaQa_AnalyzeLoopbackConnection( UserOptions *userOptions, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice ) -{ - int iFlags; - int iRate; - int iSize; - int iFormat; - int savedValue; - TestParameters testParams; - const PaDeviceInfo *inputDeviceInfo = Pa_GetDeviceInfo( inputDevice ); - const PaDeviceInfo *outputDeviceInfo = Pa_GetDeviceInfo( outputDevice ); - int totalBadChannels = 0; - - // test half duplex first because it is more likely to work. - int flagSettings[] = { PAQA_FLAG_TWO_STREAMS, 0 }; - int numFlagSettings = (sizeof(flagSettings)/sizeof(int)); - - double sampleRates[] = { 8000.0, 11025.0, 16000.0, 22050.0, 32000.0, 44100.0, 48000.0, 96000.0 }; - int numRates = (sizeof(sampleRates)/sizeof(double)); - - // framesPerBuffer==0 means PA decides on the buffer size. - int framesPerBuffers[] = { 0, 16, 32, 40, 64, 100, 128, 256, 512, 1024 }; - int numBufferSizes = (sizeof(framesPerBuffers)/sizeof(int)); - - PaSampleFormat sampleFormats[] = { paFloat32, paUInt8, paInt8, paInt16, paInt32 }; - const char *sampleFormatNames[] = { "paFloat32", "paUInt8", "paInt8", "paInt16", "paInt32" }; - int numSampleFormats = (sizeof(sampleFormats)/sizeof(PaSampleFormat)); - - printf( "=============== Analysing Loopback %d to %d =====================\n", outputDevice, inputDevice ); - printf( " Devices: %s => %s\n", outputDeviceInfo->name, inputDeviceInfo->name); - - PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice ); - - PaQa_OverrideTestParameters( &testParams, userOptions ); - - // Loop though combinations of audio parameters. - for( iFlags=0; iFlags<numFlagSettings; iFlags++ ) - { - int numRuns = 0; - - testParams.flags = flagSettings[iFlags]; - printf( "\n************ Mode = %s ************\n", - (( testParams.flags & 1 ) ? s_FlagOnNames[0] : s_FlagOffNames[0]) ); - - printf("|- requested -|- stream info latency -|- measured ------------------------------\n"); - printf("|-sRate-|-fr/buf-|- in - out - total -|- over/under/calls for in, out -|- frm/buf -|-latency-|- channel results -\n"); - - // Loop though various sample rates. - if( userOptions->sampleRate < 0 ) - { - savedValue = testParams.sampleRate; - for( iRate=0; iRate<numRates; iRate++ ) - { - int numBadChannels; - - // SAMPLE RATE - testParams.sampleRate = sampleRates[iRate]; - testParams.maxFrames = (int) (PAQA_TEST_DURATION * testParams.sampleRate); - - numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams ); - totalBadChannels += numBadChannels; - } - testParams.sampleRate = savedValue; - testParams.maxFrames = (int) (PAQA_TEST_DURATION * testParams.sampleRate); - printf( "\n" ); - numRuns += 1; - } - - // Loop through various buffer sizes. - if( userOptions->framesPerBuffer < 0 ) - { - savedValue = testParams.framesPerBuffer; - for( iSize=0; iSize<numBufferSizes; iSize++ ) - { - int numBadChannels; - - // BUFFER SIZE - testParams.framesPerBuffer = framesPerBuffers[iSize]; - - numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams ); - totalBadChannels += numBadChannels; - } - testParams.framesPerBuffer = savedValue; - printf( "\n" ); - numRuns += 1; - } - // Run one with single parameters in case we did not do a series. - if( numRuns == 0 ) - { - int numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams ); - totalBadChannels += numBadChannels; - } - } - - printf("\nTest Sample Formats using Half Duplex IO -----\n" ); - - PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice ); - testParams.flags = PAQA_FLAG_TWO_STREAMS; - for( iFlags= 0; iFlags<4; iFlags++ ) - { - // Cycle through combinations of flags. - testParams.streamFlags = 0; - if( iFlags & 1 ) testParams.streamFlags |= paClipOff; - if( iFlags & 2 ) testParams.streamFlags |= paDitherOff; - - for( iFormat=0; iFormat<numSampleFormats; iFormat++ ) - { - int numBadChannels; - PaSampleFormat format = sampleFormats[ iFormat ]; - testParams.inputParameters.sampleFormat = format; - testParams.outputParameters.sampleFormat = format; - printf("Sample format = %d = %s, PaStreamFlags = 0x%02X\n", (int) format, sampleFormatNames[iFormat], (unsigned int) testParams.streamFlags ); - numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams ); - totalBadChannels += numBadChannels; - } - } - printf( "\n" ); - printf( "****************************************\n"); - - return totalBadChannels; -} - -/*******************************************************************/ -int PaQa_CheckForClippedLoopback( LoopbackContext *loopbackContextPtr ) -{ - int clipped = 0; - TestParameters *testParamsPtr = loopbackContextPtr->test; - - // Start in the middle assuming past latency. - int startFrame = testParamsPtr->maxFrames/2; - int numFrames = testParamsPtr->maxFrames/2; - - // Check to see if the signal is clipped. - double amplitudeLeft = PaQa_MeasureSineAmplitudeBySlope( &loopbackContextPtr->recordings[0], - testParamsPtr->baseFrequency, testParamsPtr->sampleRate, - startFrame, numFrames ); - double gainLeft = amplitudeLeft / testParamsPtr->amplitude; - double amplitudeRight = PaQa_MeasureSineAmplitudeBySlope( &loopbackContextPtr->recordings[1], - testParamsPtr->baseFrequency, testParamsPtr->sampleRate, - startFrame, numFrames ); - double gainRight = amplitudeLeft / testParamsPtr->amplitude; - printf(" Loop gain: left = %f, right = %f\n", gainLeft, gainRight ); - - if( (amplitudeLeft > 1.0 ) || (amplitudeRight > 1.0) ) - { - printf("ERROR - loop gain is too high. Should be around than 1.0. Please lower output level and/or input gain.\n" ); - clipped = 1; - } - return clipped; -} - -/*******************************************************************/ -int PaQa_MeasureBackgroundNoise( LoopbackContext *loopbackContextPtr, double *rmsPtr ) -{ - int result = 0; - *rmsPtr = 0.0; - // Rewind so we can record some input. - loopbackContextPtr->recordings[0].numFrames = 0; - loopbackContextPtr->recordings[1].numFrames = 0; - result = PaQa_RunInputOnly( loopbackContextPtr ); - if( result == 0 ) - { - double leftRMS = PaQa_MeasureRootMeanSquare( loopbackContextPtr->recordings[0].buffer, - loopbackContextPtr->recordings[0].numFrames ); - double rightRMS = PaQa_MeasureRootMeanSquare( loopbackContextPtr->recordings[1].buffer, - loopbackContextPtr->recordings[1].numFrames ); - *rmsPtr = (leftRMS + rightRMS) / 2.0; - } - return result; -} - -/*******************************************************************/ -/** - * Output a sine wave then try to detect it on input. - * - * @return 1 if loopback connected, 0 if not, or negative error. - */ -int PaQa_CheckForLoopBack( UserOptions *userOptions, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice ) -{ - TestParameters testParams; - LoopbackContext loopbackContext; - const PaDeviceInfo *inputDeviceInfo; - const PaDeviceInfo *outputDeviceInfo; - PaError err = paNoError; - double minAmplitude; - int loopbackIsConnected; - int startFrame, numFrames; - double magLeft, magRight; - - inputDeviceInfo = Pa_GetDeviceInfo( inputDevice ); - if( inputDeviceInfo == NULL ) - { - printf("ERROR - Pa_GetDeviceInfo for input returned NULL.\n"); - return paInvalidDevice; - } - if( inputDeviceInfo->maxInputChannels < 2 ) - { - return 0; - } - - outputDeviceInfo = Pa_GetDeviceInfo( outputDevice ); - if( outputDeviceInfo == NULL ) - { - printf("ERROR - Pa_GetDeviceInfo for output returned NULL.\n"); - return paInvalidDevice; - } - if( outputDeviceInfo->maxOutputChannels < 2 ) - { - return 0; - } - - printf( "Look for loopback cable between \"%s\" => \"%s\"\n", outputDeviceInfo->name, inputDeviceInfo->name); - - printf( " Default suggested input latency (msec): low = %5.2f, high = %5.2f\n", - (inputDeviceInfo->defaultLowInputLatency * 1000.0), - (inputDeviceInfo->defaultHighInputLatency * 1000.0) ); - printf( " Default suggested output latency (msec): low = %5.2f, high = %5.2f\n", - (outputDeviceInfo->defaultLowOutputLatency * 1000.0), - (outputDeviceInfo->defaultHighOutputLatency * 1000.0) ); - - PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice ); - - PaQa_OverrideTestParameters( &testParams, userOptions ); - - testParams.maxFrames = (int) (LOOPBACK_DETECTION_DURATION_SECONDS * testParams.sampleRate); - minAmplitude = testParams.amplitude / 4.0; - - // Check to see if the selected formats are supported. - if( Pa_IsFormatSupported( &testParams.inputParameters, NULL, testParams.sampleRate ) != paFormatIsSupported ) - { - printf( "Input not supported for this format!\n" ); - return 0; - } - if( Pa_IsFormatSupported( NULL, &testParams.outputParameters, testParams.sampleRate ) != paFormatIsSupported ) - { - printf( "Output not supported for this format!\n" ); - return 0; - } - - PaQa_SetupLoopbackContext( &loopbackContext, &testParams ); - - if( inputDevice == outputDevice ) - { - // Use full duplex if checking for loopback on one device. - testParams.flags &= ~PAQA_FLAG_TWO_STREAMS; - } - else - { - // Use half duplex if checking for loopback on two different device. - testParams.flags = PAQA_FLAG_TWO_STREAMS; - } - err = PaQa_RunLoopback( &loopbackContext ); - QA_ASSERT_TRUE("loopback detection callback did not run", (loopbackContext.callbackCount > 1) ); - - // Analyse recording to see if we captured the output. - // Start in the middle assuming past latency. - startFrame = testParams.maxFrames/2; - numFrames = testParams.maxFrames/2; - magLeft = PaQa_CorrelateSine( &loopbackContext.recordings[0], - loopbackContext.generators[0].frequency, - testParams.sampleRate, - startFrame, numFrames, NULL ); - magRight = PaQa_CorrelateSine( &loopbackContext.recordings[1], - loopbackContext.generators[1].frequency, - testParams.sampleRate, - startFrame, numFrames, NULL ); - printf(" Amplitudes: left = %f, right = %f\n", magLeft, magRight ); - - // Check for backwards cable. - loopbackIsConnected = ((magLeft > minAmplitude) && (magRight > minAmplitude)); - - if( !loopbackIsConnected ) - { - double magLeftReverse = PaQa_CorrelateSine( &loopbackContext.recordings[0], - loopbackContext.generators[1].frequency, - testParams.sampleRate, - startFrame, numFrames, NULL ); - - double magRightReverse = PaQa_CorrelateSine( &loopbackContext.recordings[1], - loopbackContext.generators[0].frequency, - testParams.sampleRate, - startFrame, numFrames, NULL ); - - if ((magLeftReverse > minAmplitude) && (magRightReverse>minAmplitude)) - { - printf("ERROR - You seem to have the left and right channels swapped on the loopback cable!\n"); - } - } - else - { - double rms = 0.0; - if( PaQa_CheckForClippedLoopback( &loopbackContext ) ) - { - // Clipped so don't use this loopback. - loopbackIsConnected = 0; - } - - err = PaQa_MeasureBackgroundNoise( &loopbackContext, &rms ); - printf(" Background noise = %f\n", rms ); - if( err ) - { - printf("ERROR - Could not measure background noise on this input!\n"); - loopbackIsConnected = 0; - } - else if( rms > MAX_BACKGROUND_NOISE_RMS ) - { - printf("ERROR - There is too much background noise on this input!\n"); - loopbackIsConnected = 0; - } - } - - PaQa_TeardownLoopbackContext( &loopbackContext ); - return loopbackIsConnected; - -error: - PaQa_TeardownLoopbackContext( &loopbackContext ); - return err; -} - -/*******************************************************************/ -/** - * If there is a loopback connection then run the analysis. - */ -static int CheckLoopbackAndScan( UserOptions *userOptions, - PaDeviceIndex iIn, PaDeviceIndex iOut ) -{ - int loopbackConnected = PaQa_CheckForLoopBack( userOptions, iIn, iOut ); - if( loopbackConnected > 0 ) - { - PaQa_AnalyzeLoopbackConnection( userOptions, iIn, iOut ); - return 1; - } - return 0; -} - -/*******************************************************************/ -/** - * Scan every combination of output to input device. - * If a loopback is found the analyse the combination. - * The scan can be overridden using the -i and -o command line options. - */ -static int ScanForLoopback(UserOptions *userOptions) -{ - PaDeviceIndex iIn,iOut; - int numLoopbacks = 0; - int numDevices; - numDevices = Pa_GetDeviceCount(); - - // If both devices are specified then just use that combination. - if ((userOptions->inputDevice >= 0) && (userOptions->outputDevice >= 0)) - { - numLoopbacks += CheckLoopbackAndScan( userOptions, userOptions->inputDevice, userOptions->outputDevice ); - } - else if (userOptions->inputDevice >= 0) - { - // Just scan for output. - for( iOut=0; iOut<numDevices; iOut++ ) - { - numLoopbacks += CheckLoopbackAndScan( userOptions, userOptions->inputDevice, iOut ); - } - } - else if (userOptions->outputDevice >= 0) - { - // Just scan for input. - for( iIn=0; iIn<numDevices; iIn++ ) - { - numLoopbacks += CheckLoopbackAndScan( userOptions, iIn, userOptions->outputDevice ); - } - } - else - { - // Scan both. - for( iOut=0; iOut<numDevices; iOut++ ) - { - for( iIn=0; iIn<numDevices; iIn++ ) - { - numLoopbacks += CheckLoopbackAndScan( userOptions, iIn, iOut ); - } - } - } - QA_ASSERT_TRUE( "No good loopback cable found.", (numLoopbacks > 0) ); - return numLoopbacks; - -error: - return -1; -} - -/*==========================================================================================*/ -int TestSampleFormatConversion( void ) -{ - int i; - const float floatInput[] = { 1.0, 0.5, -0.5, -1.0 }; - - const char charInput[] = { 127, 64, -64, -128 }; - const unsigned char ucharInput[] = { 255, 128+64, 64, 0 }; - const short shortInput[] = { 32767, 32768/2, -32768/2, -32768 }; - const int intInput[] = { 2147483647, 2147483647/2, -1073741824 /*-2147483648/2 doesn't work in msvc*/, -2147483648 }; - - float floatOutput[4]; - short shortOutput[4]; - int intOutput[4]; - unsigned char ucharOutput[4]; - char charOutput[4]; - - QA_ASSERT_EQUALS("int must be 32-bit", 4, (int) sizeof(int) ); - QA_ASSERT_EQUALS("short must be 16-bit", 2, (int) sizeof(short) ); - - // from Float ====== - PaQa_ConvertFromFloat( floatInput, 4, paUInt8, ucharOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE_INT( "paFloat32 -> paUInt8 -> error", ucharInput[i], ucharOutput[i], 1 ); - } - - PaQa_ConvertFromFloat( floatInput, 4, paInt8, charOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE_INT( "paFloat32 -> paInt8 -> error", charInput[i], charOutput[i], 1 ); - } - - PaQa_ConvertFromFloat( floatInput, 4, paInt16, shortOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE_INT( "paFloat32 -> paInt16 error", shortInput[i], shortOutput[i], 1 ); - } - - PaQa_ConvertFromFloat( floatInput, 4, paInt32, intOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE_INT( "paFloat32 -> paInt32 error", intInput[i], intOutput[i], 0x00010000 ); - } - - - // to Float ====== - memset( floatOutput, 0, sizeof(floatOutput) ); - PaQa_ConvertToFloat( ucharInput, 4, paUInt8, floatOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE( "paUInt8 -> paFloat32 error", floatInput[i], floatOutput[i], 0.01 ); - } - - memset( floatOutput, 0, sizeof(floatOutput) ); - PaQa_ConvertToFloat( charInput, 4, paInt8, floatOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE( "paInt8 -> paFloat32 error", floatInput[i], floatOutput[i], 0.01 ); - } - - memset( floatOutput, 0, sizeof(floatOutput) ); - PaQa_ConvertToFloat( shortInput, 4, paInt16, floatOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE( "paInt16 -> paFloat32 error", floatInput[i], floatOutput[i], 0.001 ); - } - - memset( floatOutput, 0, sizeof(floatOutput) ); - PaQa_ConvertToFloat( intInput, 4, paInt32, floatOutput ); - for( i=0; i<4; i++ ) - { - QA_ASSERT_CLOSE( "paInt32 -> paFloat32 error", floatInput[i], floatOutput[i], 0.00001 ); - } - - return 0; - -error: - return -1; -} - - -/*******************************************************************/ -void usage( const char *name ) -{ - printf("%s [-i# -o# -l# -r# -s# -m -w -dDir]\n", name); - printf(" -i# - Input device ID. Will scan for loopback cable if not specified.\n"); - printf(" -o# - Output device ID. Will scan for loopback if not specified.\n"); - printf(" -l# - Latency for both input and output in milliseconds.\n"); - printf(" --inputLatency # Input latency in milliseconds.\n"); - printf(" --outputLatency # Output latency in milliseconds.\n"); - printf(" -r# - Sample Rate in Hz. Will use multiple common rates if not specified.\n"); - printf(" -s# - Size of callback buffer in frames, framesPerBuffer. Will use common values if not specified.\n"); - printf(" -w - Save bad recordings in a WAV file.\n"); - printf(" -dDir - Path for Directory for WAV files. Default is current directory.\n"); - printf(" -m - Just test the DSP Math code and not the audio devices.\n"); - printf(" -v - Verbose reports.\n"); -} - -/*******************************************************************/ -int main( int argc, char **argv ) -{ - int i; - UserOptions userOptions; - int result = 0; - int justMath = 0; - char *executableName = argv[0]; - - printf("PortAudio LoopBack Test built " __DATE__ " at " __TIME__ "\n"); - - if( argc > 1 ){ - printf("running with arguments:"); - for(i=1; i < argc; ++i ) - printf(" %s", argv[i] ); - printf("\n"); - }else{ - printf("running with no arguments\n"); - } - - memset(&userOptions, 0, sizeof(userOptions)); - userOptions.inputDevice = paNoDevice; - userOptions.outputDevice = paNoDevice; - userOptions.sampleRate = -1; - userOptions.framesPerBuffer = -1; - userOptions.inputLatency = -1; - userOptions.outputLatency = -1; - userOptions.waveFilePath = "."; - - // Process arguments. Skip name of executable. - i = 1; - while( i<argc ) - { - char *arg = argv[i]; - if( arg[0] == '-' ) - { - switch(arg[1]) - { - case 'i': - userOptions.inputDevice = atoi(&arg[2]); - break; - case 'o': - userOptions.outputDevice = atoi(&arg[2]); - break; - case 'l': - userOptions.inputLatency = userOptions.outputLatency = atoi(&arg[2]); - break; - case 'r': - userOptions.sampleRate = atoi(&arg[2]); - break; - case 's': - userOptions.framesPerBuffer = atoi(&arg[2]); - break; - - case 'm': - printf("Option -m set so just testing math and not the audio devices.\n"); - justMath = 1; - break; - - case 'w': - userOptions.saveBadWaves = 1; - break; - case 'd': - userOptions.waveFilePath = &arg[2]; - break; - - case 'v': - userOptions.verbose = 1; - break; - - case 'h': - usage( executableName ); - exit(0); - break; - - case '-': - { - if( strcmp( &arg[2], "inputLatency" ) == 0 ) - { - i += 1; - userOptions.inputLatency = atoi(argv[i]); - } - else if( strcmp( &arg[2], "outputLatency" ) == 0 ) - { - i += 1; - userOptions.outputLatency = atoi(argv[i]); - } - else - { - printf("Illegal option: %s\n", arg); - usage( executableName ); - exit(1); - } - - } - break; - - - default: - printf("Illegal option: %s\n", arg); - usage( executableName ); - exit(1); - break; - } - } - else - { - printf("Illegal argument: %s\n", arg); - usage( executableName ); - exit(1); - - } - i += 1; - } - - result = PaQa_TestAnalyzer(); - - // Test sample format conversion tool. - result = TestSampleFormatConversion(); - - if( (result == 0) && (justMath == 0) ) - { - Pa_Initialize(); - printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n", - Pa_GetVersion(), Pa_GetVersionText() ); - printf( "=============== PortAudio Devices ========================\n" ); - PaQa_ListAudioDevices(); - if( Pa_GetDeviceCount() == 0 ) - printf( "no devices found.\n" ); - - printf( "=============== Detect Loopback ==========================\n" ); - ScanForLoopback(&userOptions); - - Pa_Terminate(); - } - - if (g_testsFailed == 0) - { - printf("PortAudio QA SUCCEEDED! %d tests passed, %d tests failed\n", g_testsPassed, g_testsFailed ); - return 0; - - } - else - { - printf("PortAudio QA FAILED! %d tests passed, %d tests failed\n", g_testsPassed, g_testsFailed ); - return 1; - } -} |