summaryrefslogtreecommitdiff
path: root/portaudio/qa
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-08-27 23:52:56 -0500
committersanine <sanine.not@pm.me>2022-08-27 23:52:56 -0500
commita4dd0ad63c00f4dee3b86dfd3075d1d61b2b3180 (patch)
tree13bd5bfa15e6fea2a12f176bae79adf9c6fd0933 /portaudio/qa
parentbde3e4f1bb7b8f8abca0884a7d994ee1c17a66b1 (diff)
add plibsys
Diffstat (limited to 'portaudio/qa')
-rw-r--r--portaudio/qa/loopback/README.txt92
-rw-r--r--portaudio/qa/loopback/src/audio_analyzer.c706
-rw-r--r--portaudio/qa/loopback/src/audio_analyzer.h187
-rwxr-xr-xportaudio/qa/loopback/src/biquad_filter.c123
-rwxr-xr-xportaudio/qa/loopback/src/biquad_filter.h38
-rw-r--r--portaudio/qa/loopback/src/paqa.c1601
-rw-r--r--portaudio/qa/loopback/src/paqa_tools.c171
-rw-r--r--portaudio/qa/loopback/src/paqa_tools.h52
-rwxr-xr-xportaudio/qa/loopback/src/qa_tools.h83
-rw-r--r--portaudio/qa/loopback/src/test_audio_analyzer.c718
-rw-r--r--portaudio/qa/loopback/src/test_audio_analyzer.h46
-rwxr-xr-xportaudio/qa/loopback/src/write_wav.c242
-rwxr-xr-xportaudio/qa/loopback/src/write_wav.h103
-rw-r--r--portaudio/qa/paqa_devs.c454
-rw-r--r--portaudio/qa/paqa_errs.c403
-rw-r--r--portaudio/qa/paqa_latency.c482
16 files changed, 0 insertions, 5501 deletions
diff --git a/portaudio/qa/loopback/README.txt b/portaudio/qa/loopback/README.txt
deleted file mode 100644
index 5ad0280..0000000
--- a/portaudio/qa/loopback/README.txt
+++ /dev/null
@@ -1,92 +0,0 @@
-README for PortAudio Loopback Test
-
-Copyright (c) 1999-2010 Phil Burk and Ross Bencina
-See complete license at end of file.
-
-This folder contains code for a single executable that does a standalone test of PortAudio.
-It does not require a human to listen to the result. Instead it listens to itself using
-a loopback cable connected between the audio output and the audio input. Special pop detectors
-and phase analysers can detect errors in the audio stream.
-
-This test can be run from a script as part of a nightly build and test.
-
---- How to Build the Loopback Test ---
-
-The loopback test is not normally built by the makefile.
-To build the loopback test, enter:
-
- ./configure && make loopback
-
-This will build the "bin/paloopback" executable.
-
---- How To Run Test ---
-
-Connect stereo cables from one or more output audio devices to audio input devices.
-The test will scan all the ports and find the cables.
-
-Adjust the volume levels of the hardware so you get a decent signal that will not clip.
-
-Run the test from the command line with the following options:
-
- -i# Input device ID. Will scan for loopback if not specified.
- -o# Output device ID. Will scan for loopback if not specified.
- -r# Sample Rate in Hz. Will use multiple common rates if not specified.
- -s# Size of callback buffer in frames, framesPerBuffer.
- -w Save bad recordings in a WAV file.
- -dDir Path for Directory for WAV files. Default is current directory.
- -m Just test the DSP Math code and not the audio devices.
-
-If the -w option is set then any tests that fail will save the recording of the broken
-channel in a WAV file. The files will be numbered and shown in the report.
-
---- ToDo ---
-
-* Add check for harmonic and enharmonic distortion.
-* Measure min/max peak values.
-* Detect DC bias.
-* Test against matrix of devices/APIs and settings.
-* Detect mono vs stereo loopback.
-* More command line options
- --quick
- --latency
- --duration
-* Automated build and test script with cron job.
-* Test on Windows.
-
-
-/*
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Copyright (c) 1999-2008 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.
- */
diff --git a/portaudio/qa/loopback/src/audio_analyzer.c b/portaudio/qa/loopback/src/audio_analyzer.c
deleted file mode 100644
index fbdd631..0000000
--- a/portaudio/qa/loopback/src/audio_analyzer.c
+++ /dev/null
@@ -1,706 +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 <string.h>
-#include <assert.h>
-#include <math.h>
-#include "qa_tools.h"
-#include "audio_analyzer.h"
-#include "write_wav.h"
-
-#define PAQA_POP_THRESHOLD (0.04)
-
-/*==========================================================================================*/
-double PaQa_GetNthFrequency( double baseFrequency, int index )
-{
- // Use 13 tone equal tempered scale because it does not generate harmonic ratios.
- return baseFrequency * pow( 2.0, index / 13.0 );
-}
-
-/*==========================================================================================*/
-void PaQa_EraseBuffer( float *buffer, int numFrames, int samplesPerFrame )
-{
- int i;
- int numSamples = numFrames * samplesPerFrame;
- for( i=0; i<numSamples; i++ )
- {
- *buffer++ = 0.0;
- }
-}
-
-/*==========================================================================================*/
-void PaQa_SetupSineGenerator( PaQaSineGenerator *generator, double frequency, double amplitude, double frameRate )
-{
- generator->phase = 0.0;
- generator->amplitude = amplitude;
- generator->frequency = frequency;
- generator->phaseIncrement = 2.0 * frequency * MATH_PI / frameRate;
-}
-
-/*==========================================================================================*/
-void PaQa_MixSine( PaQaSineGenerator *generator, float *buffer, int numSamples, int stride )
-{
- int i;
- for( i=0; i<numSamples; i++ )
- {
- float value = sinf( (float) generator->phase ) * generator->amplitude;
- *buffer += value; // Mix with existing value.
- buffer += stride;
- // Advance phase and wrap around.
- generator->phase += generator->phaseIncrement;
- if (generator->phase > MATH_TWO_PI)
- {
- generator->phase -= MATH_TWO_PI;
- }
- }
-}
-
-/*==========================================================================================*/
-void PaQa_GenerateCrackDISABLED( float *buffer, int numSamples, int stride )
-{
- int i;
- int offset = numSamples/2;
- for( i=0; i<numSamples; i++ )
- {
- float phase = (MATH_TWO_PI * 0.5 * (i - offset)) / numSamples;
- float cosp = cosf( phase );
- float cos2 = cosp * cosp;
- // invert second half of signal
- float value = (i < offset) ? cos2 : (0-cos2);
- *buffer = value;
- buffer += stride;
- }
-}
-
-
-/*==========================================================================================*/
-int PaQa_InitializeRecording( PaQaRecording *recording, int maxFrames, int frameRate )
-{
- int numBytes = maxFrames * sizeof(float);
- recording->buffer = (float*)malloc(numBytes);
- QA_ASSERT_TRUE( "Allocate recording buffer.", (recording->buffer != NULL) );
- recording->maxFrames = maxFrames; recording->sampleRate = frameRate;
- recording->numFrames = 0;
- return 0;
-error:
- return 1;
-}
-
-/*==========================================================================================*/
-void PaQa_TerminateRecording( PaQaRecording *recording )
-{
- if (recording->buffer != NULL)
- {
- free( recording->buffer );
- recording->buffer = NULL;
- }
- recording->maxFrames = 0;
-}
-
-/*==========================================================================================*/
-int PaQa_WriteRecording( PaQaRecording *recording, float *buffer, int numFrames, int stride )
-{
- int i;
- int framesToWrite;
- float *data = &recording->buffer[recording->numFrames];
-
- framesToWrite = numFrames;
- if ((framesToWrite + recording->numFrames) > recording->maxFrames)
- {
- framesToWrite = recording->maxFrames - recording->numFrames;
- }
-
- for( i=0; i<framesToWrite; i++ )
- {
- *data++ = *buffer;
- buffer += stride;
- }
- recording->numFrames += framesToWrite;
- return (recording->numFrames >= recording->maxFrames);
-}
-
-/*==========================================================================================*/
-int PaQa_WriteSilence( PaQaRecording *recording, int numFrames )
-{
- int i;
- int framesToRecord;
- float *data = &recording->buffer[recording->numFrames];
-
- framesToRecord = numFrames;
- if ((framesToRecord + recording->numFrames) > recording->maxFrames)
- {
- framesToRecord = recording->maxFrames - recording->numFrames;
- }
-
- for( i=0; i<framesToRecord; i++ )
- {
- *data++ = 0.0f;
- }
- recording->numFrames += framesToRecord;
- return (recording->numFrames >= recording->maxFrames);
-}
-
-/*==========================================================================================*/
-int PaQa_RecordFreeze( PaQaRecording *recording, int numFrames )
-{
- int i;
- int framesToRecord;
- float *data = &recording->buffer[recording->numFrames];
-
- framesToRecord = numFrames;
- if ((framesToRecord + recording->numFrames) > recording->maxFrames)
- {
- framesToRecord = recording->maxFrames - recording->numFrames;
- }
-
- for( i=0; i<framesToRecord; i++ )
- {
- // Copy old value forward as if the signal had frozen.
- data[i] = data[i-1];
- }
- recording->numFrames += framesToRecord;
- return (recording->numFrames >= recording->maxFrames);
-}
-
-/*==========================================================================================*/
-/**
- * Write recording to WAV file.
- */
-int PaQa_SaveRecordingToWaveFile( PaQaRecording *recording, const char *filename )
-{
- WAV_Writer writer;
- int result = 0;
-#define NUM_SAMPLES (200)
- short data[NUM_SAMPLES];
- const int samplesPerFrame = 1;
- int numLeft = recording->numFrames;
- float *buffer = &recording->buffer[0];
-
- result = Audio_WAV_OpenWriter( &writer, filename, recording->sampleRate, samplesPerFrame );
- if( result < 0 ) goto error;
-
- while( numLeft > 0 )
- {
- int i;
- int numToSave = (numLeft > NUM_SAMPLES) ? NUM_SAMPLES : numLeft;
- // Convert double samples to shorts.
- for( i=0; i<numToSave; i++ )
- {
- double fval = *buffer++;
- // Convert float to int and clip to short range.
- int ival = fval * 32768.0;
- if( ival > 32767 ) ival = 32767;
- else if( ival < -32768 ) ival = -32768;
- data[i] = ival;
- }
- result = Audio_WAV_WriteShorts( &writer, data, numToSave );
- if( result < 0 ) goto error;
- numLeft -= numToSave;
- }
-
- result = Audio_WAV_CloseWriter( &writer );
- if( result < 0 ) goto error;
-
- return 0;
-
-error:
- printf("ERROR: result = %d\n", result );
- return result;
-#undef NUM_SAMPLES
-}
-
-/*==========================================================================================*/
-
-double PaQa_MeasureCrossingSlope( float *buffer, int numFrames )
-{
- int i;
- double slopeTotal = 0.0;
- int slopeCount = 0;
- float previous;
- double averageSlope = 0.0;
-
- previous = buffer[0];
- for( i=1; i<numFrames; i++ )
- {
- float current = buffer[i];
- if( (current > 0.0) && (previous < 0.0) )
- {
- double delta = current - previous;
- slopeTotal += delta;
- slopeCount += 1;
- }
- previous = current;
- }
- if( slopeCount > 0 )
- {
- averageSlope = slopeTotal / slopeCount;
- }
- return averageSlope;
-}
-
-/*==========================================================================================*/
-/*
- * We can't just measure the peaks cuz they may be clipped.
- * But the zero crossing should be intact.
- * The measured slope of a sine wave at zero should be:
- *
- * slope = sin( 2PI * frequency / sampleRate )
- *
- */
-double PaQa_MeasureSineAmplitudeBySlope( PaQaRecording *recording,
- double frequency, double frameRate,
- int startFrame, int numFrames )
-{
- float *buffer = &recording->buffer[startFrame];
- double measuredSlope = PaQa_MeasureCrossingSlope( buffer, numFrames );
- double unitySlope = sin( MATH_TWO_PI * frequency / frameRate );
- double estimatedAmplitude = measuredSlope / unitySlope;
- return estimatedAmplitude;
-}
-
-/*==========================================================================================*/
-double PaQa_CorrelateSine( PaQaRecording *recording, double frequency, double frameRate,
- int startFrame, int numFrames, double *phasePtr )
-{
- double magnitude = 0.0;
- int numLeft = numFrames;
- double phase = 0.0;
- double phaseIncrement = 2.0 * MATH_PI * frequency / frameRate;
- double sinAccumulator = 0.0;
- double cosAccumulator = 0.0;
- float *data = &recording->buffer[startFrame];
-
- QA_ASSERT_TRUE( "startFrame out of bounds", (startFrame < recording->numFrames) );
- QA_ASSERT_TRUE( "numFrames out of bounds", ((startFrame+numFrames) <= recording->numFrames) );
-
- while( numLeft > 0 )
- {
- double sample = (double) *data++;
- sinAccumulator += sample * sin( phase );
- cosAccumulator += sample * cos( phase );
- phase += phaseIncrement;
- if (phase > MATH_TWO_PI)
- {
- phase -= MATH_TWO_PI;
- }
- numLeft -= 1;
- }
- sinAccumulator = sinAccumulator / numFrames;
- cosAccumulator = cosAccumulator / numFrames;
- // TODO Why do I have to multiply by 2.0? Need it to make result come out right.
- magnitude = 2.0 * sqrt( (sinAccumulator * sinAccumulator) + (cosAccumulator * cosAccumulator ));
- if( phasePtr != NULL )
- {
- double phase = atan2( cosAccumulator, sinAccumulator );
- *phasePtr = phase;
- }
- return magnitude;
-error:
- return -1.0;
-}
-
-/*==========================================================================================*/
-void PaQa_FilterRecording( PaQaRecording *input, PaQaRecording *output, BiquadFilter *filter )
-{
- int numToFilter = (input->numFrames > output->maxFrames) ? output->maxFrames : input->numFrames;
- BiquadFilter_Filter( filter, &input->buffer[0], &output->buffer[0], numToFilter );
- output->numFrames = numToFilter;
-}
-
-/*==========================================================================================*/
-/** Scan until we get a correlation of a single that goes over the tolerance level,
- * peaks then drops to half the peak.
- * Look for inverse correlation as well.
- */
-double PaQa_FindFirstMatch( PaQaRecording *recording, float *buffer, int numFrames, double threshold )
-{
- int ic,is;
- // How many buffers will fit in the recording?
- int maxCorrelations = recording->numFrames - numFrames;
- double maxSum = 0.0;
- int peakIndex = -1;
- double inverseMaxSum = 0.0;
- int inversePeakIndex = -1;
- double location = -1.0;
-
- QA_ASSERT_TRUE( "numFrames out of bounds", (numFrames < recording->numFrames) );
-
- for( ic=0; ic<maxCorrelations; ic++ )
- {
- int pastPeak;
- int inversePastPeak;
-
- double sum = 0.0;
- // Correlate buffer against the recording.
- float *recorded = &recording->buffer[ ic ];
- for( is=0; is<numFrames; is++ )
- {
- float s1 = buffer[is];
- float s2 = *recorded++;
- sum += s1 * s2;
- }
- if( (sum > maxSum) )
- {
- maxSum = sum;
- peakIndex = ic;
- }
- if( ((-sum) > inverseMaxSum) )
- {
- inverseMaxSum = -sum;
- inversePeakIndex = ic;
- }
- pastPeak = (maxSum > threshold) && (sum < 0.5*maxSum);
- inversePastPeak = (inverseMaxSum > threshold) && ((-sum) < 0.5*inverseMaxSum);
- //printf("PaQa_FindFirstMatch: ic = %4d, sum = %8f, maxSum = %8f, inverseMaxSum = %8f\n", ic, sum, maxSum, inverseMaxSum );
- if( pastPeak && inversePastPeak )
- {
- if( maxSum > inverseMaxSum )
- {
- location = peakIndex;
- }
- else
- {
- location = inversePeakIndex;
- }
- break;
- }
-
- }
- //printf("PaQa_FindFirstMatch: location = %4d\n", (int)location );
- return location;
-error:
- return -1.0;
-}
-
-/*==========================================================================================*/
-// Measure the area under the curve by summing absolute value of each value.
-double PaQa_MeasureArea( float *buffer, int numFrames, int stride )
-{
- int is;
- double area = 0.0;
- for( is=0; is<numFrames; is++ )
- {
- area += fabs( *buffer );
- buffer += stride;
- }
- return area;
-}
-
-/*==========================================================================================*/
-// Measure the area under the curve by summing absolute value of each value.
-double PaQa_MeasureRootMeanSquare( float *buffer, int numFrames )
-{
- int is;
- double area = 0.0;
- double root;
- for( is=0; is<numFrames; is++ )
- {
- float value = *buffer++;
- area += value * value;
- }
- root = sqrt( area );
- return root / numFrames;
-}
-
-
-/*==========================================================================================*/
-// Compare the amplitudes of these two signals.
-// Return ratio of recorded signal over buffer signal.
-
-double PaQa_CompareAmplitudes( PaQaRecording *recording, int startAt, float *buffer, int numFrames )
-{
- QA_ASSERT_TRUE( "startAt+numFrames out of bounds", ((startAt+numFrames) < recording->numFrames) );
-
- {
- double recordedArea = PaQa_MeasureArea( &recording->buffer[startAt], numFrames, 1 );
- double bufferArea = PaQa_MeasureArea( buffer, numFrames, 1 );
- if( bufferArea == 0.0 ) return 100000000.0;
- return recordedArea / bufferArea;
- }
-error:
- return -1.0;
-}
-
-
-/*==========================================================================================*/
-double PaQa_ComputePhaseDifference( double phase1, double phase2 )
-{
- double delta = phase1 - phase2;
- while( delta > MATH_PI )
- {
- delta -= MATH_TWO_PI;
- }
- while( delta < -MATH_PI )
- {
- delta += MATH_TWO_PI;
- }
- return delta;
-}
-
-/*==========================================================================================*/
-int PaQa_MeasureLatency( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult )
-{
- double threshold;
- PaQaSineGenerator generator;
-#define MAX_BUFFER_SIZE 2048
- float buffer[MAX_BUFFER_SIZE];
- double period = testTone->sampleRate / testTone->frequency;
- int cycleSize = (int) (period + 0.5);
- //printf("PaQa_AnalyseRecording: frequency = %8f, frameRate = %8f, period = %8f, cycleSize = %8d\n",
- // testTone->frequency, testTone->sampleRate, period, cycleSize );
- analysisResult->latency = -1;
- analysisResult->valid = (0);
-
- // Set up generator to find matching first cycle.
- QA_ASSERT_TRUE( "cycleSize out of bounds", (cycleSize < MAX_BUFFER_SIZE) );
- PaQa_SetupSineGenerator( &generator, testTone->frequency, testTone->amplitude, testTone->sampleRate );
- PaQa_EraseBuffer( buffer, cycleSize, testTone->samplesPerFrame );
- PaQa_MixSine( &generator, buffer, cycleSize, testTone->samplesPerFrame );
-
- threshold = cycleSize * 0.02;
- analysisResult->latency = PaQa_FindFirstMatch( recording, buffer, cycleSize, threshold );
- QA_ASSERT_TRUE( "Could not find the start of the signal.", (analysisResult->latency >= 0) );
- analysisResult->amplitudeRatio = PaQa_CompareAmplitudes( recording, analysisResult->latency, buffer, cycleSize );
- return 0;
-error:
- return -1;
-}
-
-/*==========================================================================================*/
-// Apply cosine squared window.
-void PaQa_FadeInRecording( PaQaRecording *recording, int startFrame, int count )
-{
- int is;
- double phase = 0.5 * MATH_PI;
- // Advance a quarter wave
- double phaseIncrement = 0.25 * 2.0 * MATH_PI / count;
-
- assert( startFrame >= 0 );
- assert( count > 0 );
-
- /* Zero out initial part of the recording. */
- for( is=0; is<startFrame; is++ )
- {
- recording->buffer[ is ] = 0.0f;
- }
- /* Fade in where signal begins. */
- for( is=0; is<count; is++ )
- {
- double c = cos( phase );
- double w = c * c;
- float x = recording->buffer[ is + startFrame ];
- float y = x * w;
- //printf("FADE %d : w=%f, x=%f, y=%f\n", is, w, x, y );
- recording->buffer[ is + startFrame ] = y;
-
- phase += phaseIncrement;
- }
-}
-
-
-/*==========================================================================================*/
-/** Apply notch filter and high pass filter then detect remaining energy.
- */
-int PaQa_DetectPop( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult )
-{
- int result = 0;
- int i;
- double maxAmplitude;
- int maxPosition;
-
- PaQaRecording notchOutput = { 0 };
- BiquadFilter notchFilter;
-
- PaQaRecording hipassOutput = { 0 };
- BiquadFilter hipassFilter;
-
- int frameRate = (int) recording->sampleRate;
-
- analysisResult->popPosition = -1;
- analysisResult->popAmplitude = 0.0;
-
- result = PaQa_InitializeRecording( &notchOutput, recording->numFrames, frameRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- result = PaQa_InitializeRecording( &hipassOutput, recording->numFrames, frameRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- // Use notch filter to remove test tone.
- BiquadFilter_SetupNotch( &notchFilter, testTone->frequency / frameRate, 0.5 );
- PaQa_FilterRecording( recording, &notchOutput, &notchFilter );
- //result = PaQa_SaveRecordingToWaveFile( &notchOutput, "notch_output.wav" );
- //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result );
-
- // Apply fade-in window.
- PaQa_FadeInRecording( &notchOutput, (int) analysisResult->latency, 500 );
-
- // Use high pass to accentuate the edges of a pop. At higher frequency!
- BiquadFilter_SetupHighPass( &hipassFilter, 2.0 * testTone->frequency / frameRate, 0.5 );
- PaQa_FilterRecording( &notchOutput, &hipassOutput, &hipassFilter );
- //result = PaQa_SaveRecordingToWaveFile( &hipassOutput, "hipass_output.wav" );
- //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result );
-
- // Scan remaining signal looking for peak.
- maxAmplitude = 0.0;
- maxPosition = -1;
- for( i=(int) analysisResult->latency; i<hipassOutput.numFrames; i++ )
- {
- float x = hipassOutput.buffer[i];
- float mag = fabs( x );
- if( mag > maxAmplitude )
- {
- maxAmplitude = mag;
- maxPosition = i;
- }
- }
-
- if( maxAmplitude > PAQA_POP_THRESHOLD )
- {
- analysisResult->popPosition = maxPosition;
- analysisResult->popAmplitude = maxAmplitude;
- }
-
- PaQa_TerminateRecording( &notchOutput );
- PaQa_TerminateRecording( &hipassOutput );
- return 0;
-
-error:
- PaQa_TerminateRecording( &notchOutput );
- PaQa_TerminateRecording( &hipassOutput );
- return -1;
-}
-
-/*==========================================================================================*/
-int PaQa_DetectPhaseError( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult )
-{
- int i;
- double period = testTone->sampleRate / testTone->frequency;
- int cycleSize = (int) (period + 0.5);
-
- double maxAddedFrames = 0.0;
- double maxDroppedFrames = 0.0;
-
- double previousPhase = 0.0;
- double previousFrameError = 0;
- int loopCount = 0;
- int skip = cycleSize;
- int windowSize = cycleSize;
-
- // Scan recording starting with first cycle, looking for phase errors.
- analysisResult->numDroppedFrames = 0.0;
- analysisResult->numAddedFrames = 0.0;
- analysisResult->droppedFramesPosition = -1.0;
- analysisResult->addedFramesPosition = -1.0;
-
- for( i=analysisResult->latency; i<(recording->numFrames - windowSize); i += skip )
- {
- double expectedPhase = previousPhase + (skip * MATH_TWO_PI / period);
- double expectedPhaseIncrement = PaQa_ComputePhaseDifference( expectedPhase, previousPhase );
-
- double phase = 666.0;
- double mag = PaQa_CorrelateSine( recording, testTone->frequency, testTone->sampleRate, i, windowSize, &phase );
- if( (loopCount > 1) && (mag > 0.0) )
- {
- double phaseDelta = PaQa_ComputePhaseDifference( phase, previousPhase );
- double phaseError = PaQa_ComputePhaseDifference( phaseDelta, expectedPhaseIncrement );
- // Convert phaseError to equivalent number of frames.
- double frameError = period * phaseError / MATH_TWO_PI;
- double consecutiveFrameError = frameError + previousFrameError;
-// if( fabs(frameError) > 0.01 )
-// {
-// printf("FFFFFFFFFFFFF frameError = %f, at %d\n", frameError, i );
-// }
- if( consecutiveFrameError > 0.8 )
- {
- double droppedFrames = consecutiveFrameError;
- if (droppedFrames > (maxDroppedFrames * 1.001))
- {
- analysisResult->numDroppedFrames = droppedFrames;
- analysisResult->droppedFramesPosition = i + (windowSize/2);
- maxDroppedFrames = droppedFrames;
- }
- }
- else if( consecutiveFrameError < -0.8 )
- {
- double addedFrames = 0 - consecutiveFrameError;
- if (addedFrames > (maxAddedFrames * 1.001))
- {
- analysisResult->numAddedFrames = addedFrames;
- analysisResult->addedFramesPosition = i + (windowSize/2);
- maxAddedFrames = addedFrames;
- }
- }
- previousFrameError = frameError;
-
-
- //if( i<8000 )
- //{
- // printf("%d: phase = %8f, expected = %8f, delta = %8f, frameError = %8f\n", i, phase, expectedPhaseIncrement, phaseDelta, frameError );
- //}
- }
- previousPhase = phase;
- loopCount += 1;
- }
- return 0;
-}
-
-/*==========================================================================================*/
-int PaQa_AnalyseRecording( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult )
-{
- int result = 0;
-
- memset( analysisResult, 0, sizeof(PaQaAnalysisResult) );
- result = PaQa_MeasureLatency( recording, testTone, analysisResult );
- QA_ASSERT_EQUALS( "latency measurement", 0, result );
-
- if( (analysisResult->latency >= 0) && (analysisResult->amplitudeRatio > 0.1) )
- {
- analysisResult->valid = (1);
-
- result = PaQa_DetectPop( recording, testTone, analysisResult );
- QA_ASSERT_EQUALS( "detect pop", 0, result );
-
- result = PaQa_DetectPhaseError( recording, testTone, analysisResult );
- QA_ASSERT_EQUALS( "detect phase error", 0, result );
- }
- return 0;
-error:
- return -1;
-}
diff --git a/portaudio/qa/loopback/src/audio_analyzer.h b/portaudio/qa/loopback/src/audio_analyzer.h
deleted file mode 100644
index 8d9f1ee..0000000
--- a/portaudio/qa/loopback/src/audio_analyzer.h
+++ /dev/null
@@ -1,187 +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.
- */
-
-#ifndef _AUDIO_ANALYZER_H
-#define _AUDIO_ANALYZER_H
-
-#include "biquad_filter.h"
-
-#define MATH_PI (3.141592653589793238462643)
-#define MATH_TWO_PI (2.0 * MATH_PI)
-
-typedef struct PaQaSineGenerator_s
-{
- double phase;
- double phaseIncrement;
- double frequency;
- double amplitude;
-} PaQaSineGenerator;
-
-/** Container for a monophonic audio sample in memory. */
-typedef struct PaQaRecording_s
-{
- /** Maximum number of frames that can fit in the allocated buffer. */
- int maxFrames;
- float *buffer;
- /** Actual number of valid frames in the buffer. */
- int numFrames;
- int sampleRate;
-} PaQaRecording;
-
-typedef struct PaQaTestTone_s
-{
- int samplesPerFrame;
- int startDelay;
- double sampleRate;
- double frequency;
- double amplitude;
-} PaQaTestTone;
-
-typedef struct PaQaAnalysisResult_s
-{
- int valid;
- /** Latency in samples from output to input. */
- double latency;
- double amplitudeRatio;
- double popAmplitude;
- double popPosition;
- double numDroppedFrames;
- double droppedFramesPosition;
- double numAddedFrames;
- double addedFramesPosition;
-} PaQaAnalysisResult;
-
-
-/*================================================================*/
-/*================= General DSP Tools ============================*/
-/*================================================================*/
-/**
- * Calculate Nth frequency of a series for use in testing multiple channels.
- * Series should avoid harmonic overlap between channels.
- */
-double PaQa_GetNthFrequency( double baseFrequency, int index );
-
-void PaQa_EraseBuffer( float *buffer, int numFrames, int samplesPerFrame );
-
-void PaQa_MixSine( PaQaSineGenerator *generator, float *buffer, int numSamples, int stride );
-
-void PaQa_WriteSine( float *buffer, int numSamples, int stride,
- double frequency, double amplitude );
-
-/**
- * Generate a signal with a sharp edge in the middle that can be recognized despite some phase shift.
- */
-void PaQa_GenerateCrack( float *buffer, int numSamples, int stride );
-
-double PaQa_ComputePhaseDifference( double phase1, double phase2 );
-
-/**
- * Measure the area under the curve by summing absolute value of each value.
- */
-double PaQa_MeasureArea( float *buffer, int numFrames, int stride );
-
-/**
- * Measure slope of the positive zero crossings.
- */
-double PaQa_MeasureCrossingSlope( float *buffer, int numFrames );
-
-
-/**
- * Prepare an oscillator that can generate a sine tone for testing.
- */
-void PaQa_SetupSineGenerator( PaQaSineGenerator *generator, double frequency, double amplitude, double frameRate );
-
-/*================================================================*/
-/*================= Recordings ===================================*/
-/*================================================================*/
-/**
- * Allocate memory for containing a mono audio signal. Set up recording for writing.
- */
- int PaQa_InitializeRecording( PaQaRecording *recording, int maxSamples, int sampleRate );
-
-/**
-* Free memory allocated by PaQa_InitializeRecording.
- */
- void PaQa_TerminateRecording( PaQaRecording *recording );
-
-/**
- * Apply a biquad filter to the audio from the input recording and write it to the output recording.
- */
-void PaQa_FilterRecording( PaQaRecording *input, PaQaRecording *output, BiquadFilter *filter );
-
-
-int PaQa_SaveRecordingToWaveFile( PaQaRecording *recording, const char *filename );
-
-/**
- * @param stride is the spacing of samples to skip in the input buffer. To use every samples pass 1. To use every other sample pass 2.
- */
-int PaQa_WriteRecording( PaQaRecording *recording, float *buffer, int numSamples, int stride );
-
-/** Write zeros into a recording. */
-int PaQa_WriteSilence( PaQaRecording *recording, int numSamples );
-
-int PaQa_RecordFreeze( PaQaRecording *recording, int numSamples );
-
-double PaQa_CorrelateSine( PaQaRecording *recording, double frequency, double frameRate,
- int startFrame, int numSamples, double *phasePtr );
-
-double PaQa_FindFirstMatch( PaQaRecording *recording, float *buffer, int numSamples, double tolerance );
-
-/**
- * Estimate the original amplitude of a clipped sine wave by measuring
- * its average slope at the zero crossings.
- */
-double PaQa_MeasureSineAmplitudeBySlope( PaQaRecording *recording,
- double frequency, double frameRate,
- int startFrame, int numFrames );
-
-double PaQa_MeasureRootMeanSquare( float *buffer, int numFrames );
-
-/**
- * Compare the amplitudes of these two signals.
- * Return ratio of recorded signal over buffer signal.
- */
-double PaQa_CompareAmplitudes( PaQaRecording *recording, int startAt, float *buffer, int numSamples );
-
-/**
- * Analyse a recording of a sine wave.
- * Measure latency and look for dropped frames, etc.
- */
-int PaQa_AnalyseRecording( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult );
-
-#endif /* _AUDIO_ANALYZER_H */
diff --git a/portaudio/qa/loopback/src/biquad_filter.c b/portaudio/qa/loopback/src/biquad_filter.c
deleted file mode 100755
index 1715fa3..0000000
--- a/portaudio/qa/loopback/src/biquad_filter.c
+++ /dev/null
@@ -1,123 +0,0 @@
-#include <math.h>
-#include <string.h>
-
-#include "biquad_filter.h"
-
-/**
- * Unit_BiquadFilter implements a second order IIR filter.
- *
- * Here is the equation that we use for this filter:
- * y(n) = a0*x(n) + a1*x(n-1) + a2*x(n-2) - b1*y(n-1) - b2*y(n-2)
- *
- * @author (C) 2002 Phil Burk, SoftSynth.com, All Rights Reserved
- */
-
-#define FILTER_PI (3.141592653589793238462643)
-/***********************************************************
-** Calculate coefficients common to many parametric biquad filters.
-*/
-static void BiquadFilter_CalculateCommon( BiquadFilter *filter, double ratio, double Q )
-{
- double omega;
-
- memset( filter, 0, sizeof(BiquadFilter) );
-
-/* Don't let frequency get too close to Nyquist or filter will blow up. */
- if( ratio >= 0.499 ) ratio = 0.499;
- omega = 2.0 * (double)FILTER_PI * ratio;
-
- filter->cos_omega = (double) cos( omega );
- filter->sin_omega = (double) sin( omega );
- filter->alpha = filter->sin_omega / (2.0 * Q);
-}
-
-/*********************************************************************************
- ** Calculate coefficients for Highpass filter.
- */
-void BiquadFilter_SetupHighPass( BiquadFilter *filter, double ratio, double Q )
-{
- double scalar, opc;
-
- if( ratio < BIQUAD_MIN_RATIO ) ratio = BIQUAD_MIN_RATIO;
- if( Q < BIQUAD_MIN_Q ) Q = BIQUAD_MIN_Q;
-
- BiquadFilter_CalculateCommon( filter, ratio, Q );
-
- scalar = 1.0 / (1.0 + filter->alpha);
- opc = (1.0 + filter->cos_omega);
-
- filter->a0 = opc * 0.5 * scalar;
- filter->a1 = - opc * scalar;
- filter->a2 = filter->a0;
- filter->b1 = -2.0 * filter->cos_omega * scalar;
- filter->b2 = (1.0 - filter->alpha) * scalar;
-}
-
-
-/*********************************************************************************
- ** Calculate coefficients for Notch filter.
- */
-void BiquadFilter_SetupNotch( BiquadFilter *filter, double ratio, double Q )
-{
- double scalar, opc;
-
- if( ratio < BIQUAD_MIN_RATIO ) ratio = BIQUAD_MIN_RATIO;
- if( Q < BIQUAD_MIN_Q ) Q = BIQUAD_MIN_Q;
-
- BiquadFilter_CalculateCommon( filter, ratio, Q );
-
- scalar = 1.0 / (1.0 + filter->alpha);
- opc = (1.0 + filter->cos_omega);
-
- filter->a0 = scalar;
- filter->a1 = -2.0 * filter->cos_omega * scalar;
- filter->a2 = filter->a0;
- filter->b1 = filter->a1;
- filter->b2 = (1.0 - filter->alpha) * scalar;
-}
-
-/*****************************************************************
-** Perform core IIR filter calculation without permutation.
-*/
-void BiquadFilter_Filter( BiquadFilter *filter, float *inputs, float *outputs, int numSamples )
-{
- int i;
- double xn, yn;
- // Pull values from structure to speed up the calculation.
- double a0 = filter->a0;
- double a1 = filter->a1;
- double a2 = filter->a2;
- double b1 = filter->b1;
- double b2 = filter->b2;
- double xn1 = filter->xn1;
- double xn2 = filter->xn2;
- double yn1 = filter->yn1;
- double yn2 = filter->yn2;
-
- for( i=0; i<numSamples; i++)
- {
- // Generate outputs by filtering inputs.
- xn = inputs[i];
- yn = (a0 * xn) + (a1 * xn1) + (a2 * xn2) - (b1 * yn1) - (b2 * yn2);
- outputs[i] = yn;
-
- // Delay input and output values.
- xn2 = xn1;
- xn1 = xn;
- yn2 = yn1;
- yn1 = yn;
-
- if( (i & 7) == 0 )
- {
- // Apply a small bipolar impulse to filter to prevent arithmetic underflow.
- // Underflows can cause the FPU to interrupt the CPU.
- yn1 += (double) 1.0E-26;
- yn2 -= (double) 1.0E-26;
- }
- }
-
- filter->xn1 = xn1;
- filter->xn2 = xn2;
- filter->yn1 = yn1;
- filter->yn2 = yn2;
-}
diff --git a/portaudio/qa/loopback/src/biquad_filter.h b/portaudio/qa/loopback/src/biquad_filter.h
deleted file mode 100755
index 0895aba..0000000
--- a/portaudio/qa/loopback/src/biquad_filter.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _BIQUADFILTER_H
-#define _BIQUADFILTER_H
-
-
-/**
- * Unit_BiquadFilter implements a second order IIR filter.
- *
- * @author (C) 2002 Phil Burk, SoftSynth.com, All Rights Reserved
- */
-
-#define BIQUAD_MIN_RATIO (0.000001)
-#define BIQUAD_MIN_Q (0.00001)
-
-typedef struct BiquadFilter_s
-{
- double xn1; // storage for delayed signals
- double xn2;
- double yn1;
- double yn2;
-
- double a0; // coefficients
- double a1;
- double a2;
-
- double b1;
- double b2;
-
- double cos_omega;
- double sin_omega;
- double alpha;
-} BiquadFilter;
-
-void BiquadFilter_SetupHighPass( BiquadFilter *filter, double ratio, double Q );
-void BiquadFilter_SetupNotch( BiquadFilter *filter, double ratio, double Q );
-
-void BiquadFilter_Filter( BiquadFilter *filter, float *inputs, float *outputs, int numSamples );
-
-#endif
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;
- }
-}
diff --git a/portaudio/qa/loopback/src/paqa_tools.c b/portaudio/qa/loopback/src/paqa_tools.c
deleted file mode 100644
index 2e44c63..0000000
--- a/portaudio/qa/loopback/src/paqa_tools.c
+++ /dev/null
@@ -1,171 +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 "paqa_tools.h"
-
-
-/*******************************************************************/
-void PaQa_ListAudioDevices(void)
-{
- int i, numDevices;
- const PaDeviceInfo *deviceInfo;
- numDevices = Pa_GetDeviceCount();
- for( i=0; i<numDevices; i++ )
- {
- deviceInfo = Pa_GetDeviceInfo( i );
- printf( "#%d: ", i );
- printf( "%2d in", deviceInfo->maxInputChannels );
- printf( ", %2d out", deviceInfo->maxOutputChannels );
- printf( ", %s", deviceInfo->name );
- printf( ", on %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name );
- }
-}
-
-/*******************************************************************/
-void PaQa_ConvertToFloat( const void *input, int numSamples, PaSampleFormat inFormat, float *output )
-{
- int i;
- switch( inFormat )
- {
- case paUInt8:
- {
- unsigned char *data = (unsigned char *)input;
- for( i=0; i<numSamples; i++ )
- {
- int value = *data++;
- value -= 128;
- *output++ = value / 128.0f;
- }
- }
- break;
-
- case paInt8:
- {
- char *data = (char *)input;
- for( i=0; i<numSamples; i++ )
- {
- int value = *data++;
- *output++ = value / 128.0f;
- }
- }
- break;
-
- case paInt16:
- {
- short *data = (short *)input;
- for( i=0; i<numSamples; i++ )
- {
- *output++ = *data++ / 32768.0f;
- }
- }
- break;
-
- case paInt32:
- {
- int *data = (int *)input;
- for( i=0; i<numSamples; i++ )
- {
- int value = (*data++) >> 8;
- float fval = (float) (value / ((double) 0x00800000));
- *output++ = fval;
- }
- }
- break;
- }
-
-}
-
-/*******************************************************************/
-void PaQa_ConvertFromFloat( const float *input, int numSamples, PaSampleFormat outFormat, void *output )
-{
- int i;
- switch( outFormat )
- {
- case paUInt8:
- {
- unsigned char *data = (unsigned char *)output;
- for( i=0; i<numSamples; i++ )
- {
- float value = *input++;
- int byte = ((int) (value * 127)) + 128;
- *data++ = (unsigned char) byte;
- }
- }
- break;
-
- case paInt8:
- {
- char *data = (char *)output;
- for( i=0; i<numSamples; i++ )
- {
- float value = *input++;
- int byte = (int) (value * 127);
- *data++ = (char) byte;
- }
- }
- break;
-
- case paInt16:
- {
- short *data = (short *)output;
- for( i=0; i<numSamples; i++ )
- {
- float value = *input++;
- // Use asymmetric conversion to avoid clipping.
- short sval = value * 32767.0;
- *data++ = sval;
- }
- }
- break;
-
- case paInt32:
- {
- int *data = (int *)output;
- for( i=0; i<numSamples; i++ )
- {
- float value = *input++;
- // Use asymmetric conversion to avoid clipping.
- int ival = value * ((double) 0x007FFFF0);
- ival = ival << 8;
- *data++ = ival;
- }
- }
- break;
- }
-
-}
diff --git a/portaudio/qa/loopback/src/paqa_tools.h b/portaudio/qa/loopback/src/paqa_tools.h
deleted file mode 100644
index 77f6a25..0000000
--- a/portaudio/qa/loopback/src/paqa_tools.h
+++ /dev/null
@@ -1,52 +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.
- */
-
-#ifndef _PAQA_TOOLS_H
-#define _PAQA_TOOLS_H
-
-
-#include <stdio.h>
-#include "portaudio.h"
-
-void PaQa_ListAudioDevices(void);
-
-void PaQa_ConvertToFloat( const void *input, int numSamples, PaSampleFormat inFormat, float *output );
-
-void PaQa_ConvertFromFloat( const float *input, int numSamples, PaSampleFormat outFormat, void *output );
-
-#endif /* _PAQA_TOOLS_H */
diff --git a/portaudio/qa/loopback/src/qa_tools.h b/portaudio/qa/loopback/src/qa_tools.h
deleted file mode 100755
index 9b2debd..0000000
--- a/portaudio/qa/loopback/src/qa_tools.h
+++ /dev/null
@@ -1,83 +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.
- */
-
-#ifndef _QA_TOOLS_H
-#define _QA_TOOLS_H
-
-extern int g_testsPassed;
-extern int g_testsFailed;
-
-#define QA_ASSERT_TRUE( message, flag ) \
- if( !(flag) ) \
- { \
- printf( "%s:%d - ERROR - %s\n", __FILE__, __LINE__, message ); \
- g_testsFailed++; \
- goto error; \
- } \
- else g_testsPassed++;
-
-
-#define QA_ASSERT_EQUALS( message, expected, actual ) \
- if( ((expected) != (actual)) ) \
- { \
- printf( "%s:%d - ERROR - %s, expected %d, got %d\n", __FILE__, __LINE__, message, expected, actual ); \
- g_testsFailed++; \
- goto error; \
- } \
- else g_testsPassed++;
-
-#define QA_ASSERT_CLOSE( message, expected, actual, tolerance ) \
- if (fabs((expected)-(actual))>(tolerance)) \
- { \
- printf( "%s:%d - ERROR - %s, expected %f, got %f, tol=%f\n", __FILE__, __LINE__, message, ((double)(expected)), ((double)(actual)), ((double)(tolerance)) ); \
- g_testsFailed++; \
- goto error; \
- } \
- else g_testsPassed++;
-
-#define QA_ASSERT_CLOSE_INT( message, expected, actual, tolerance ) \
- if (abs((expected)-(actual))>(tolerance)) \
- { \
- printf( "%s:%d - ERROR - %s, expected %d, got %d, tol=%d\n", __FILE__, __LINE__, message, ((int)(expected)), ((int)(actual)), ((int)(tolerance)) ); \
- g_testsFailed++; \
- goto error; \
- } \
- else g_testsPassed++;
-
-
-#endif
diff --git a/portaudio/qa/loopback/src/test_audio_analyzer.c b/portaudio/qa/loopback/src/test_audio_analyzer.c
deleted file mode 100644
index 82fa859..0000000
--- a/portaudio/qa/loopback/src/test_audio_analyzer.c
+++ /dev/null
@@ -1,718 +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 <math.h>
-#include "qa_tools.h"
-#include "audio_analyzer.h"
-#include "test_audio_analyzer.h"
-#include "write_wav.h"
-#include "biquad_filter.h"
-
-#define FRAMES_PER_BLOCK (64)
-#define PRINT_REPORTS 0
-
-#define TEST_SAVED_WAVE (0)
-
-/*==========================================================================================*/
-/**
- * Detect a single tone.
- */
-static int TestSingleMonoTone( void )
-{
- int result = 0;
- PaQaSineGenerator generator;
- PaQaRecording recording;
- float buffer[FRAMES_PER_BLOCK];
- double sampleRate = 44100.0;
- int maxFrames = ((int)sampleRate) * 1;
- int samplesPerFrame = 1;
- int stride = 1;
- int done = 0;
-
- double freq = 234.5;
- double amp = 0.5;
-
- double mag1, mag2;
-
- // Setup a sine oscillator.
- PaQa_SetupSineGenerator( &generator, freq, amp, sampleRate );
-
- result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- done = 0;
- while (!done)
- {
- PaQa_EraseBuffer( buffer, FRAMES_PER_BLOCK, samplesPerFrame );
- PaQa_MixSine( &generator, buffer, FRAMES_PER_BLOCK, stride );
- done = PaQa_WriteRecording( &recording, buffer, FRAMES_PER_BLOCK, samplesPerFrame );
- }
-
- mag1 = PaQa_CorrelateSine( &recording, freq, sampleRate, 0, recording.numFrames, NULL );
- QA_ASSERT_CLOSE( "exact frequency match", amp, mag1, 0.01 );
-
- mag2 = PaQa_CorrelateSine( &recording, freq * 1.23, sampleRate, 0, recording.numFrames, NULL );
- QA_ASSERT_CLOSE( "wrong frequency", 0.0, mag2, 0.01 );
-
- PaQa_TerminateRecording( &recording );
- return 0;
-
-error:
- PaQa_TerminateRecording( &recording);
- return 1;
-
-}
-
-/*==========================================================================================*/
-/**
- * Mix multiple tones and then detect them.
- */
-
-static int TestMixedMonoTones( void )
-{
- int i;
- int result = 0;
-#define NUM_TONES (5)
- PaQaSineGenerator generators[NUM_TONES];
- PaQaRecording recording;
- float buffer[FRAMES_PER_BLOCK];
- double sampleRate = 44100.0;
- int maxFrames = ((int)sampleRate) * 1;
- int samplesPerFrame = 1;
-
- double baseFreq = 234.5;
- double amp = 0.1;
-
- double mag2;
-
- int stride = samplesPerFrame;
- int done = 0;
-
- // Setup a sine oscillator.
- for( i=0; i<NUM_TONES; i++ )
- {
- PaQa_SetupSineGenerator( &generators[i], PaQa_GetNthFrequency( baseFreq, i ), amp, sampleRate );
- }
-
- result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- done = 0;
- while (!done)
- {
- PaQa_EraseBuffer( buffer, FRAMES_PER_BLOCK, samplesPerFrame );
- for( i=0; i<NUM_TONES; i++ )
- {
- PaQa_MixSine( &generators[i], buffer, FRAMES_PER_BLOCK, stride );
- }
- done = PaQa_WriteRecording( &recording, buffer, FRAMES_PER_BLOCK, samplesPerFrame );
- }
-
- for( i=0; i<NUM_TONES; i++ )
- {
- double mag = PaQa_CorrelateSine( &recording, PaQa_GetNthFrequency( baseFreq, i), sampleRate, 0, recording.numFrames, NULL );
- QA_ASSERT_CLOSE( "exact frequency match", amp, mag, 0.01 );
- }
-
- mag2 = PaQa_CorrelateSine( &recording, baseFreq * 0.87, sampleRate, 0, recording.numFrames, NULL );
- QA_ASSERT_CLOSE( "wrong frequency", 0.0, mag2, 0.01 );
-
- PaQa_TerminateRecording( &recording );
- return 0;
-
-error:
- PaQa_TerminateRecording( &recording);
- return 1;
-
-}
-
-
-/*==========================================================================================*/
-/**
- * Generate a recording with added or dropped frames.
- */
-
-static void MakeRecordingWithAddedFrames( PaQaRecording *recording, PaQaTestTone *testTone, int glitchPosition, int framesToAdd )
-{
- PaQaSineGenerator generator;
-#define BUFFER_SIZE 512
- float buffer[BUFFER_SIZE];
-
- int frameCounter = testTone->startDelay;
-
- int stride = 1;
- // Record some initial silence.
- int done = PaQa_WriteSilence( recording, testTone->startDelay );
-
- // Setup a sine oscillator.
- PaQa_SetupSineGenerator( &generator, testTone->frequency, testTone->amplitude, testTone->sampleRate );
-
- while (!done)
- {
- int framesThisLoop = BUFFER_SIZE;
-
- if( frameCounter == glitchPosition )
- {
- if( framesToAdd > 0 )
- {
- // Record some frozen data without advancing the sine generator.
- done = PaQa_RecordFreeze( recording, framesToAdd );
- frameCounter += framesToAdd;
- }
- else if( framesToAdd < 0 )
- {
- // Advance sine generator a few frames.
- PaQa_MixSine( &generator, buffer, 0 - framesToAdd, stride );
- }
-
- }
- else if( (frameCounter < glitchPosition) && ((frameCounter + framesThisLoop) > glitchPosition) )
- {
- // Go right up to the glitchPosition.
- framesThisLoop = glitchPosition - frameCounter;
- }
-
- if( framesThisLoop > 0 )
- {
- PaQa_EraseBuffer( buffer, framesThisLoop, testTone->samplesPerFrame );
- PaQa_MixSine( &generator, buffer, framesThisLoop, stride );
- done = PaQa_WriteRecording( recording, buffer, framesThisLoop, testTone->samplesPerFrame );
- }
- frameCounter += framesThisLoop;
- }
-}
-
-
-/*==========================================================================================*/
-/**
- * Generate a clean recording.
- */
-
-static void MakeCleanRecording( PaQaRecording *recording, PaQaTestTone *testTone )
-{
- PaQaSineGenerator generator;
-#define BUFFER_SIZE 512
- float buffer[BUFFER_SIZE];
-
- int stride = 1;
- // Record some initial silence.
- int done = PaQa_WriteSilence( recording, testTone->startDelay );
-
- // Setup a sine oscillator.
- PaQa_SetupSineGenerator( &generator, testTone->frequency, testTone->amplitude, testTone->sampleRate );
-
- // Generate recording with good phase.
- while (!done)
- {
- PaQa_EraseBuffer( buffer, BUFFER_SIZE, testTone->samplesPerFrame );
- PaQa_MixSine( &generator, buffer, BUFFER_SIZE, stride );
- done = PaQa_WriteRecording( recording, buffer, BUFFER_SIZE, testTone->samplesPerFrame );
- }
-}
-
-/*==========================================================================================*/
-/**
- * Generate a recording with pop.
- */
-
-static void MakeRecordingWithPop( PaQaRecording *recording, PaQaTestTone *testTone, int popPosition, int popWidth, double popAmplitude )
-{
- int i;
-
- MakeCleanRecording( recording, testTone );
-
- // Apply glitch to good recording.
- if( (popPosition + popWidth) >= recording->numFrames )
- {
- popWidth = (recording->numFrames - popPosition) - 1;
- }
-
- for( i=0; i<popWidth; i++ )
- {
- float good = recording->buffer[i+popPosition];
- float bad = (good > 0.0) ? (good - popAmplitude) : (good + popAmplitude);
- recording->buffer[i+popPosition] = bad;
- }
-}
-
-/*==========================================================================================*/
-/**
- * Detect one phase error in a recording.
- */
-static int TestDetectSinglePhaseError( double sampleRate, int cycleSize, int latencyFrames, int glitchPosition, int framesAdded )
-{
- int result = 0;
- PaQaRecording recording;
- PaQaTestTone testTone;
- PaQaAnalysisResult analysisResult = { 0.0 };
- int framesDropped = 0;
- int maxFrames = ((int)sampleRate) * 2;
-
- testTone.samplesPerFrame = 1;
- testTone.sampleRate = sampleRate;
- testTone.frequency = sampleRate / cycleSize;
- testTone.amplitude = 0.5;
- testTone.startDelay = latencyFrames;
-
- result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- MakeRecordingWithAddedFrames( &recording, &testTone, glitchPosition, framesAdded );
-
- PaQa_AnalyseRecording( &recording, &testTone, &analysisResult );
-
- if( framesAdded < 0 )
- {
- framesDropped = -framesAdded;
- framesAdded = 0;
- }
-
-#if PRINT_REPORTS
- printf("\n=== Dropped Frame Analysis ===================\n");
- printf(" expected actual\n");
- printf(" latency: %10.3f %10.3f\n", (double)latencyFrames, analysisResult.latency );
- printf(" num added frames: %10.3f %10.3f\n", (double)framesAdded, analysisResult.numAddedFrames );
- printf(" added frames at: %10.3f %10.3f\n", (double)glitchPosition, analysisResult.addedFramesPosition );
- printf(" num dropped frames: %10.3f %10.3f\n", (double)framesDropped, analysisResult.numDroppedFrames );
- printf(" dropped frames at: %10.3f %10.3f\n", (double)glitchPosition, analysisResult.droppedFramesPosition );
-#endif
-
- QA_ASSERT_CLOSE( "PaQa_AnalyseRecording latency", latencyFrames, analysisResult.latency, 0.5 );
- QA_ASSERT_CLOSE( "PaQa_AnalyseRecording framesAdded", framesAdded, analysisResult.numAddedFrames, 1.0 );
- QA_ASSERT_CLOSE( "PaQa_AnalyseRecording framesDropped", framesDropped, analysisResult.numDroppedFrames, 1.0 );
-// QA_ASSERT_CLOSE( "PaQa_AnalyseRecording glitchPosition", glitchPosition, analysisResult.glitchPosition, cycleSize );
-
- PaQa_TerminateRecording( &recording );
- return 0;
-
-error:
- PaQa_TerminateRecording( &recording);
- return 1;
-}
-
-/*==========================================================================================*/
-/**
- * Test various dropped sample scenarios.
- */
-static int TestDetectPhaseErrors( void )
-{
- int result;
-
- result = TestDetectSinglePhaseError( 44100, 200, 477, -1, 0 );
- if( result < 0 ) return result;
-/*
- result = TestDetectSinglePhaseError( 44100, 200, 77, -1, 0 );
- if( result < 0 ) return result;
-
- result = TestDetectSinglePhaseError( 44100, 200, 83, 3712, 9 );
- if( result < 0 ) return result;
-
- result = TestDetectSinglePhaseError( 44100, 280, 83, 3712, 27 );
- if( result < 0 ) return result;
-
- result = TestDetectSinglePhaseError( 44100, 200, 234, 3712, -9 );
- if( result < 0 ) return result;
-
- result = TestDetectSinglePhaseError( 44100, 200, 2091, 8923, -2 );
- if( result < 0 ) return result;
-
- result = TestDetectSinglePhaseError( 44100, 120, 1782, 5772, -18 );
- if( result < 0 ) return result;
-
- // Note that if the frequency is too high then it is hard to detect single dropped frames.
- result = TestDetectSinglePhaseError( 44100, 200, 500, 4251, -1 );
- if( result < 0 ) return result;
-*/
- return 0;
-}
-
-/*==========================================================================================*/
-/**
- * Detect one pop in a recording.
- */
-static int TestDetectSinglePop( double sampleRate, int cycleSize, int latencyFrames, int popPosition, int popWidth, double popAmplitude )
-{
- int result = 0;
- PaQaRecording recording;
- PaQaTestTone testTone;
- PaQaAnalysisResult analysisResult = { 0.0 };
- int maxFrames = ((int)sampleRate) * 2;
-
- testTone.samplesPerFrame = 1;
- testTone.sampleRate = sampleRate;
- testTone.frequency = sampleRate / cycleSize;
- testTone.amplitude = 0.5;
- testTone.startDelay = latencyFrames;
-
- result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- MakeRecordingWithPop( &recording, &testTone, popPosition, popWidth, popAmplitude );
-
- PaQa_AnalyseRecording( &recording, &testTone, &analysisResult );
-
-#if PRINT_REPORTS
- printf("\n=== Pop Analysis ===================\n");
- printf(" expected actual\n");
- printf(" latency: %10.3f %10.3f\n", (double)latencyFrames, analysisResult.latency );
- printf(" popPosition: %10.3f %10.3f\n", (double)popPosition, analysisResult.popPosition );
- printf(" popAmplitude: %10.3f %10.3f\n", popAmplitude, analysisResult.popAmplitude );
- printf(" cycleSize: %6d\n", cycleSize );
- printf(" num added frames: %10.3f\n", analysisResult.numAddedFrames );
- printf(" added frames at: %10.3f\n", analysisResult.addedFramesPosition );
- printf(" num dropped frames: %10.3f\n", analysisResult.numDroppedFrames );
- printf(" dropped frames at: %10.3f\n", analysisResult.droppedFramesPosition );
-#endif
-
- QA_ASSERT_CLOSE( "PaQa_AnalyseRecording latency", latencyFrames, analysisResult.latency, 0.5 );
- QA_ASSERT_CLOSE( "PaQa_AnalyseRecording popPosition", popPosition, analysisResult.popPosition, 10 );
- if( popWidth > 0 )
- {
- QA_ASSERT_CLOSE( "PaQa_AnalyseRecording popAmplitude", popAmplitude, analysisResult.popAmplitude, 0.1 * popAmplitude );
- }
-
- PaQa_TerminateRecording( &recording );
- return 0;
-
-error:
- PaQa_SaveRecordingToWaveFile( &recording, "bad_recording.wav" );
- PaQa_TerminateRecording( &recording);
- return 1;
-}
-
-/*==========================================================================================*/
-/**
- * Analyse recording with a DC offset.
- */
-static int TestSingleInitialSpike( double sampleRate, int stepPosition, int cycleSize, int latencyFrames, double stepAmplitude )
-{
- int i;
- int result = 0;
- // Account for highpass filter offset.
- int expectedLatency = latencyFrames + 1;
- PaQaRecording recording;
-
- PaQaRecording hipassOutput = { 0 };
- BiquadFilter hipassFilter;
-
- PaQaTestTone testTone;
- PaQaAnalysisResult analysisResult = { 0.0 };
- int maxFrames = ((int)sampleRate) * 2;
-
- testTone.samplesPerFrame = 1;
- testTone.sampleRate = sampleRate;
- testTone.frequency = sampleRate / cycleSize;
- testTone.amplitude = -0.5;
- testTone.startDelay = latencyFrames;
-
- result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- result = PaQa_InitializeRecording( &hipassOutput, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- MakeCleanRecording( &recording, &testTone );
-
- // Apply DC step.
- for( i=stepPosition; i<recording.numFrames; i++ )
- {
- recording.buffer[i] += stepAmplitude;
- }
-
- // Use high pass as a DC blocker!
- BiquadFilter_SetupHighPass( &hipassFilter, 10.0 / sampleRate, 0.5 );
- PaQa_FilterRecording( &recording, &hipassOutput, &hipassFilter );
-
- testTone.amplitude = 0.5;
- PaQa_AnalyseRecording( &hipassOutput, &testTone, &analysisResult );
-
-#if PRINT_REPORTS
- printf("\n=== InitialSpike Analysis ===================\n");
- printf(" expected actual\n");
- printf(" latency: %10.3f %10.3f\n", (double)expectedLatency, analysisResult.latency );
- printf(" popPosition: %10.3f\n", analysisResult.popPosition );
- printf(" popAmplitude: %10.3f\n", analysisResult.popAmplitude );
- printf(" amplitudeRatio: %10.3f\n", analysisResult.amplitudeRatio );
- printf(" cycleSize: %6d\n", cycleSize );
- printf(" num added frames: %10.3f\n", analysisResult.numAddedFrames );
- printf(" added frames at: %10.3f\n", analysisResult.addedFramesPosition );
- printf(" num dropped frames: %10.3f\n", analysisResult.numDroppedFrames );
- printf(" dropped frames at: %10.3f\n", analysisResult.droppedFramesPosition );
-#endif
-
- QA_ASSERT_CLOSE( "PaQa_AnalyseRecording latency", expectedLatency, analysisResult.latency, 4.0 );
- QA_ASSERT_EQUALS( "PaQa_AnalyseRecording no pop from step", -1, (int) analysisResult.popPosition );
- PaQa_TerminateRecording( &recording );
- PaQa_TerminateRecording( &hipassOutput );
- return 0;
-
-error:
- PaQa_SaveRecordingToWaveFile( &recording, "bad_step_original.wav" );
- PaQa_SaveRecordingToWaveFile( &hipassOutput, "bad_step_hipass.wav" );
- PaQa_TerminateRecording( &recording);
- PaQa_TerminateRecording( &hipassOutput );
- return 1;
-}
-
-/*==========================================================================================*/
-/**
- * Test various dropped sample scenarios.
- */
-static int TestDetectPops( void )
-{
- int result;
-
- // No pop.
- result = TestDetectSinglePop( 44100, 200, 477, -1, 0, 0.0 );
- if( result < 0 ) return result;
-
- // short pop
- result = TestDetectSinglePop( 44100, 300, 810, 3987, 1, 0.5 );
- if( result < 0 ) return result;
-
- // medium long pop
- result = TestDetectSinglePop( 44100, 300, 810, 9876, 5, 0.5 );
- if( result < 0 ) return result;
-
- // short tiny pop
- result = TestDetectSinglePop( 44100, 250, 810, 5672, 1, 0.05 );
- if( result < 0 ) return result;
-
-
- return 0;
-}
-
-/*==========================================================================================*/
-/**
- * Test analysis when there is a DC offset step before the sine signal.
- */
-static int TestInitialSpike( void )
-{
- int result;
-
-//( double sampleRate, int stepPosition, int cycleSize, int latencyFrames, double stepAmplitude )
- // No spike.
- result = TestSingleInitialSpike( 44100, 32, 100, 537, 0.0 );
- if( result < 0 ) return result;
-
- // Small spike.
- result = TestSingleInitialSpike( 44100, 32, 100, 537, 0.1 );
- if( result < 0 ) return result;
-
- // short pop like Ross's error.
- result = TestSingleInitialSpike( 8000, 32, 42, 2000, 0.1 );
- if( result < 0 ) return result;
-
- // Medium spike.
- result = TestSingleInitialSpike( 44100, 40, 190, 3000, 0.5 );
- if( result < 0 ) return result;
-
- // Spike near sine.
- //result = TestSingleInitialSpike( 44100, 2900, 140, 3000, 0.1 );
- if( result < 0 ) return result;
-
-
- return 0;
-}
-
-
-#if TEST_SAVED_WAVE
-/*==========================================================================================*/
-/**
- * Simple test that writes a sawtooth waveform to a file.
- */
-static int TestSavedWave()
-{
- int i,j;
- WAV_Writer writer;
- int result = 0;
-#define NUM_SAMPLES (200)
- short data[NUM_SAMPLES];
- short saw = 0;
-
-
- result = Audio_WAV_OpenWriter( &writer, "test_sawtooth.wav", 44100, 1 );
- if( result < 0 ) goto error;
-
- for( i=0; i<15; i++ )
- {
- for( j=0; j<NUM_SAMPLES; j++ )
- {
- data[j] = saw;
- saw += 293;
- }
- result = Audio_WAV_WriteShorts( &writer, data, NUM_SAMPLES );
- if( result < 0 ) goto error;
- }
-
- result = Audio_WAV_CloseWriter( &writer );
- if( result < 0 ) goto error;
-
-
- return 0;
-
-error:
- printf("ERROR: result = %d\n", result );
- return result;
-}
-#endif /* TEST_SAVED_WAVE */
-
-/*==========================================================================================*/
-/**
- * Easy way to generate a sine tone recording.
- */
-void PaQa_FillWithSine( PaQaRecording *recording, double sampleRate, double freq, double amp )
-{
- PaQaSineGenerator generator;
- float buffer[FRAMES_PER_BLOCK];
- int samplesPerFrame = 1;
- int stride = 1;
- int done = 0;
-
- // Setup a sine oscillator.
- PaQa_SetupSineGenerator( &generator, freq, amp, sampleRate );
-
- done = 0;
- while (!done)
- {
- PaQa_EraseBuffer( buffer, FRAMES_PER_BLOCK, samplesPerFrame );
- PaQa_MixSine( &generator, buffer, FRAMES_PER_BLOCK, stride );
- done = PaQa_WriteRecording( recording, buffer, FRAMES_PER_BLOCK, samplesPerFrame );
- }
-
-}
-
-/*==========================================================================================*/
-/**
- * Generate a tone then knock it out using a filter.
- * Also check using filter slightly off tune to see if some energy gets through.
- */
-static int TestNotchFilter( void )
-{
- int result = 0;
- PaQaRecording original = { 0 };
- PaQaRecording filtered = { 0 };
- BiquadFilter notchFilter;
- double sampleRate = 44100.0;
- int maxFrames = ((int)sampleRate) * 1;
-
- double freq = 234.5;
- double amp = 0.5;
-
- double mag1, mag2, mag3;
-
- result = PaQa_InitializeRecording( &original, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- PaQa_FillWithSine( &original, sampleRate, freq, amp );
-
- //result = PaQa_SaveRecordingToWaveFile( &original, "original.wav" );
- //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result );
-
- mag1 = PaQa_CorrelateSine( &original, freq, sampleRate, 0, original.numFrames, NULL );
- QA_ASSERT_CLOSE( "exact frequency match", amp, mag1, 0.01 );
-
- // Filter with exact frequency.
- result = PaQa_InitializeRecording( &filtered, maxFrames, (int) sampleRate );
- QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result );
-
- BiquadFilter_SetupNotch( &notchFilter, freq / sampleRate, 0.5 );
- PaQa_FilterRecording( &original, &filtered, &notchFilter );
- result = PaQa_SaveRecordingToWaveFile( &filtered, "filtered1.wav" );
- QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result );
-
- mag2 = PaQa_CorrelateSine( &filtered, freq, sampleRate, 0, filtered.numFrames, NULL );
- QA_ASSERT_CLOSE( "should eliminate tone", 0.0, mag2, 0.01 );
-
- // Filter with mismatched frequency.
- BiquadFilter_SetupNotch( &notchFilter, 1.07 * freq / sampleRate, 2.0 );
- PaQa_FilterRecording( &original, &filtered, &notchFilter );
-
- //result = PaQa_SaveRecordingToWaveFile( &filtered, "badfiltered.wav" );
- //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result );
-
- mag3 = PaQa_CorrelateSine( &filtered, freq, sampleRate, 0, filtered.numFrames, NULL );
- QA_ASSERT_CLOSE( "should eliminate tone", amp*0.26, mag3, 0.01 );
-
-
- PaQa_TerminateRecording( &original );
- PaQa_TerminateRecording( &filtered );
- return 0;
-
-error:
- PaQa_TerminateRecording( &original);
- PaQa_TerminateRecording( &filtered );
- return 1;
-
-}
-
-/*==========================================================================================*/
-/**
- */
-int PaQa_TestAnalyzer( void )
-{
- int result;
-
-#if TEST_SAVED_WAVE
- // Write a simple wave file.
- if ((result = TestSavedWave()) != 0) return result;
-#endif /* TEST_SAVED_WAVE */
-
- // Generate single tone and verify presence.
- if ((result = TestSingleMonoTone()) != 0) return result;
-
- // Generate prime series of tones and verify presence.
- if ((result = TestMixedMonoTones()) != 0) return result;
-
- // Detect dropped or added samples in a sine wave recording.
- if ((result = TestDetectPhaseErrors()) != 0) return result;
-
- // Test to see if notch filter can knock out the test tone.
- if ((result = TestNotchFilter()) != 0) return result;
-
- // Detect pops that get back in phase.
- if ((result = TestDetectPops()) != 0) return result;
-
- // Test to see if the latency detector can be tricked like it was on Ross' Windows machine.
- if ((result = TestInitialSpike()) != 0) return result;
-
-
- return 0;
-}
diff --git a/portaudio/qa/loopback/src/test_audio_analyzer.h b/portaudio/qa/loopback/src/test_audio_analyzer.h
deleted file mode 100644
index bfe073f..0000000
--- a/portaudio/qa/loopback/src/test_audio_analyzer.h
+++ /dev/null
@@ -1,46 +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.
- */
-
-#ifndef _TEST_AUDIO_ANALYZER_H
-#define _TEST_AUDIO_ANALYZER_H
-
-/** Test the audio analyzer by itself without any PortAudio calls. */
-int PaQa_TestAnalyzer( void );
-
-
-#endif /* _TEST_AUDIO_ANALYZER_H */
diff --git a/portaudio/qa/loopback/src/write_wav.c b/portaudio/qa/loopback/src/write_wav.c
deleted file mode 100755
index aa5ee21..0000000
--- a/portaudio/qa/loopback/src/write_wav.c
+++ /dev/null
@@ -1,242 +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.
- */
-
-/**
- * Very simple WAV file writer for saving captured audio.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "write_wav.h"
-
-
-/* Write long word data to a little endian format byte array. */
-static void WriteLongLE( unsigned char **addrPtr, unsigned long data )
-{
- unsigned char *addr = *addrPtr;
- *addr++ = (unsigned char) data;
- *addr++ = (unsigned char) (data>>8);
- *addr++ = (unsigned char) (data>>16);
- *addr++ = (unsigned char) (data>>24);
- *addrPtr = addr;
-}
-
-/* Write short word data to a little endian format byte array. */
-static void WriteShortLE( unsigned char **addrPtr, unsigned short data )
-{
- unsigned char *addr = *addrPtr;
- *addr++ = (unsigned char) data;
- *addr++ = (unsigned char) (data>>8);
- *addrPtr = addr;
-}
-
-/* Write IFF ChunkType data to a byte array. */
-static void WriteChunkType( unsigned char **addrPtr, unsigned long cktyp )
-{
- unsigned char *addr = *addrPtr;
- *addr++ = (unsigned char) (cktyp>>24);
- *addr++ = (unsigned char) (cktyp>>16);
- *addr++ = (unsigned char) (cktyp>>8);
- *addr++ = (unsigned char) cktyp;
- *addrPtr = addr;
-}
-
-#define WAV_HEADER_SIZE (4 + 4 + 4 + /* RIFF+size+WAVE */ \
- 4 + 4 + 16 + /* fmt chunk */ \
- 4 + 4 ) /* data chunk */
-
-
-/*********************************************************************************
- * Open named file and write WAV header to the file.
- * The header includes the DATA chunk type and size.
- * Returns number of bytes written to file or negative error code.
- */
-long Audio_WAV_OpenWriter( WAV_Writer *writer, const char *fileName, int frameRate, int samplesPerFrame )
-{
- unsigned int bytesPerSecond;
- unsigned char header[ WAV_HEADER_SIZE ];
- unsigned char *addr = header;
- int numWritten;
-
- writer->dataSize = 0;
- writer->dataSizeOffset = 0;
-
- writer->fid = fopen( fileName, "wb" );
- if( writer->fid == NULL )
- {
- return -1;
- }
-
-/* Write RIFF header. */
- WriteChunkType( &addr, RIFF_ID );
-
-/* Write RIFF size as zero for now. Will patch later. */
- WriteLongLE( &addr, 0 );
-
-/* Write WAVE form ID. */
- WriteChunkType( &addr, WAVE_ID );
-
-/* Write format chunk based on AudioSample structure. */
- WriteChunkType( &addr, FMT_ID );
- WriteLongLE( &addr, 16 );
- WriteShortLE( &addr, WAVE_FORMAT_PCM );
- bytesPerSecond = frameRate * samplesPerFrame * sizeof( short);
- WriteShortLE( &addr, (short) samplesPerFrame );
- WriteLongLE( &addr, frameRate );
- WriteLongLE( &addr, bytesPerSecond );
- WriteShortLE( &addr, (short) (samplesPerFrame * sizeof( short)) ); /* bytesPerBlock */
- WriteShortLE( &addr, (short) 16 ); /* bits per sample */
-
-/* Write ID and size for 'data' chunk. */
- WriteChunkType( &addr, DATA_ID );
-/* Save offset so we can patch it later. */
- writer->dataSizeOffset = (int) (addr - header);
- WriteLongLE( &addr, 0 );
-
- numWritten = fwrite( header, 1, sizeof(header), writer->fid );
- if( numWritten != sizeof(header) ) return -1;
-
- return (int) numWritten;
-}
-
-/*********************************************************************************
- * Write to the data chunk portion of a WAV file.
- * Returns bytes written or negative error code.
- */
-long Audio_WAV_WriteShorts( WAV_Writer *writer,
- short *samples,
- int numSamples
- )
-{
- unsigned char buffer[2];
- unsigned char *bufferPtr;
- int i;
- short *p = samples;
- int numWritten;
- int bytesWritten;
- if( numSamples <= 0 )
- {
- return -1;
- }
-
- for( i=0; i<numSamples; i++ )
- {
- bufferPtr = buffer;
- WriteShortLE( &bufferPtr, *p++ );
- numWritten = fwrite( buffer, 1, sizeof( buffer), writer->fid );
- if( numWritten != sizeof(buffer) ) return -1;
- }
- bytesWritten = numSamples * sizeof(short);
- writer->dataSize += bytesWritten;
- return (int) bytesWritten;
-}
-
-/*********************************************************************************
- * Close WAV file.
- * Update chunk sizes so it can be read by audio applications.
- */
-long Audio_WAV_CloseWriter( WAV_Writer *writer )
-{
- unsigned char buffer[4];
- unsigned char *bufferPtr;
- int numWritten;
- int riffSize;
-
- /* Go back to beginning of file and update DATA size */
- int result = fseek( writer->fid, writer->dataSizeOffset, SEEK_SET );
- if( result < 0 ) return result;
-
- bufferPtr = buffer;
- WriteLongLE( &bufferPtr, writer->dataSize );
- numWritten = fwrite( buffer, 1, sizeof( buffer), writer->fid );
- if( numWritten != sizeof(buffer) ) return -1;
-
- /* Update RIFF size */
- result = fseek( writer->fid, 4, SEEK_SET );
- if( result < 0 ) return result;
-
- riffSize = writer->dataSize + (WAV_HEADER_SIZE - 8);
- bufferPtr = buffer;
- WriteLongLE( &bufferPtr, riffSize );
- numWritten = fwrite( buffer, 1, sizeof( buffer), writer->fid );
- if( numWritten != sizeof(buffer) ) return -1;
-
- fclose( writer->fid );
- writer->fid = NULL;
- return writer->dataSize;
-}
-
-/*********************************************************************************
- * Simple test that write a sawtooth waveform to a file.
- */
-#if 0
-int main( void )
-{
- int i;
- WAV_Writer writer;
- int result;
-#define NUM_SAMPLES (200)
- short data[NUM_SAMPLES];
- short saw = 0;
-
- for( i=0; i<NUM_SAMPLES; i++ )
- {
- data[i] = saw;
- saw += 293;
- }
-
-
- result = Audio_WAV_OpenWriter( &writer, "rendered_midi.wav", 44100, 1 );
- if( result < 0 ) goto error;
-
- for( i=0; i<15; i++ )
- {
- result = Audio_WAV_WriteShorts( &writer, data, NUM_SAMPLES );
- if( result < 0 ) goto error;
- }
-
- result = Audio_WAV_CloseWriter( &writer );
- if( result < 0 ) goto error;
-
-
- return 0;
-
-error:
- printf("ERROR: result = %d\n", result );
- return result;
-}
-#endif
diff --git a/portaudio/qa/loopback/src/write_wav.h b/portaudio/qa/loopback/src/write_wav.h
deleted file mode 100755
index 3560055..0000000
--- a/portaudio/qa/loopback/src/write_wav.h
+++ /dev/null
@@ -1,103 +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.
- */
-#ifndef _WAV_WRITER_H
-#define _WAV_WRITER_H
-
-/*
- * WAV file writer.
- *
- * Author: Phil Burk
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Define WAV Chunk and FORM types as 4 byte integers. */
-#define RIFF_ID (('R'<<24) | ('I'<<16) | ('F'<<8) | 'F')
-#define WAVE_ID (('W'<<24) | ('A'<<16) | ('V'<<8) | 'E')
-#define FMT_ID (('f'<<24) | ('m'<<16) | ('t'<<8) | ' ')
-#define DATA_ID (('d'<<24) | ('a'<<16) | ('t'<<8) | 'a')
-#define FACT_ID (('f'<<24) | ('a'<<16) | ('c'<<8) | 't')
-
-/* Errors returned by Audio_ParseSampleImage_WAV */
-#define WAV_ERR_CHUNK_SIZE (-1) /* Chunk size is illegal or past file size. */
-#define WAV_ERR_FILE_TYPE (-2) /* Not a WAV file. */
-#define WAV_ERR_ILLEGAL_VALUE (-3) /* Illegal or unsupported value. Eg. 927 bits/sample */
-#define WAV_ERR_FORMAT_TYPE (-4) /* Unsupported format, eg. compressed. */
-#define WAV_ERR_TRUNCATED (-5) /* End of file missing. */
-
-/* WAV PCM data format ID */
-#define WAVE_FORMAT_PCM (1)
-#define WAVE_FORMAT_IMA_ADPCM (0x0011)
-
-
-typedef struct WAV_Writer_s
-{
- FILE *fid;
- /* Offset in file for data size. */
- int dataSizeOffset;
- int dataSize;
-} WAV_Writer;
-
-/*********************************************************************************
- * Open named file and write WAV header to the file.
- * The header includes the DATA chunk type and size.
- * Returns number of bytes written to file or negative error code.
- */
-long Audio_WAV_OpenWriter( WAV_Writer *writer, const char *fileName, int frameRate, int samplesPerFrame );
-
-/*********************************************************************************
- * Write to the data chunk portion of a WAV file.
- * Returns bytes written or negative error code.
- */
-long Audio_WAV_WriteShorts( WAV_Writer *writer,
- short *samples,
- int numSamples
- );
-
-/*********************************************************************************
- * Close WAV file.
- * Update chunk sizes so it can be read by audio applications.
- */
-long Audio_WAV_CloseWriter( WAV_Writer *writer );
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif /* _WAV_WRITER_H */
diff --git a/portaudio/qa/paqa_devs.c b/portaudio/qa/paqa_devs.c
deleted file mode 100644
index 858ed78..0000000
--- a/portaudio/qa/paqa_devs.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/** @file paqa_devs.c
- @ingroup qa_src
- @brief Self Testing Quality Assurance app for PortAudio
- Try to open devices and run through all possible configurations.
- By default, open only the default devices. Command line options support
- opening every device, or all input devices, or all output devices.
- This test does not verify that the configuration works well.
- It just verifies that it does not crash. It requires a human to
- listen to the sine wave outputs.
-
- @author Phil Burk http://www.softsynth.com
-
- Pieter adapted to V19 API. Test now relies heavily on
- Pa_IsFormatSupported(). Uses same 'standard' sample rates
- as in test pa_devs.c.
-*/
-/*
- * $Id$
- *
- * This program uses the PortAudio Portable Audio Library.
- * For more information see: http://www.portaudio.com
- * 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.
- *
- * 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 <string.h>
-#include <math.h>
-#include "portaudio.h"
-#include "pa_trace.h"
-
-/****************************************** Definitions ***********/
-#define MODE_INPUT (0)
-#define MODE_OUTPUT (1)
-#define MAX_TEST_CHANNELS (4)
-#define LOWEST_FREQUENCY (300.0)
-#define LOWEST_SAMPLE_RATE (8000.0)
-#define PHASE_INCREMENT (2.0 * M_PI * LOWEST_FREQUENCY / LOWEST_SAMPLE_RATE)
-#define SINE_AMPLITUDE (0.2)
-
-typedef struct PaQaData
-{
- unsigned long framesLeft;
- int numChannels;
- int bytesPerSample;
- int mode;
- float phase;
- PaSampleFormat format;
-}
-PaQaData;
-
-/****************************************** Prototypes ***********/
-static void TestDevices( int mode, int allDevices );
-static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate,
- int numChannels );
-static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
- int numChannels, PaSampleFormat format );
-static int QaCallback( const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData );
-
-/****************************************** Globals ***********/
-static int gNumPassed = 0;
-static int gNumFailed = 0;
-
-/****************************************** Macros ***********/
-/* Print ERROR if it fails. Tally success or failure. */
-/* Odd do-while wrapper seems to be needed for some compilers. */
-#define EXPECT(_exp) \
- do \
- { \
- if ((_exp)) {\
- /* printf("SUCCESS for %s\n", #_exp ); */ \
- gNumPassed++; \
- } \
- else { \
- printf("ERROR - 0x%x - %s for %s\n", result, \
- ((result == 0) ? "-" : Pa_GetErrorText(result)), \
- #_exp ); \
- gNumFailed++; \
- goto error; \
- } \
- } while(0)
-
-static float NextSineSample( PaQaData *data )
-{
- float phase = data->phase + PHASE_INCREMENT;
- if( phase > M_PI ) phase -= 2.0 * M_PI;
- data->phase = phase;
- return sinf(phase) * SINE_AMPLITUDE;
-}
-
-/*******************************************************************/
-/* This routine will be called by the PortAudio engine when audio is needed.
-** It may be called at interrupt level on some machines so don't do anything
-** that could mess up the system like calling malloc() or free().
-*/
-static int QaCallback( const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
-{
- unsigned long frameIndex;
- unsigned long channelIndex;
- float sample;
- PaQaData *data = (PaQaData *) userData;
- (void) inputBuffer;
-
- /* Play simple sine wave. */
- if( data->mode == MODE_OUTPUT )
- {
- switch( data->format )
- {
- case paFloat32:
- {
- float *out = (float *) outputBuffer;
- for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
- {
- sample = NextSineSample( data );
- for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
- {
- *out++ = sample;
- }
- }
- }
- break;
-
- case paInt32:
- {
- int *out = (int *) outputBuffer;
- for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
- {
- sample = NextSineSample( data );
- for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
- {
- *out++ = ((int)(sample * 0x00800000)) << 8;
- }
- }
- }
- break;
-
- case paInt16:
- {
- short *out = (short *) outputBuffer;
- for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ )
- {
- sample = NextSineSample( data );
- for( channelIndex = 0; channelIndex < data->numChannels; channelIndex++ )
- {
- *out++ = (short)(sample * 32767);
- }
- }
- }
- break;
-
- default:
- {
- unsigned char *out = (unsigned char *) outputBuffer;
- unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
- memset(out, 0, numBytes);
- }
- break;
- }
- }
- /* Are we through yet? */
- if( data->framesLeft > framesPerBuffer )
- {
- PaUtil_AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft );
- data->framesLeft -= framesPerBuffer;
- return 0;
- }
- else
- {
- PaUtil_AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft );
- data->framesLeft = 0;
- return 1;
- }
-}
-
-/*******************************************************************/
-static void usage( const char *name )
-{
- printf("%s [-a]\n", name);
- printf(" -a - Test ALL devices, otherwise just the default devices.\n");
- printf(" -i - Test INPUT only.\n");
- printf(" -o - Test OUTPUT only.\n");
- printf(" -? - Help\n");
-}
-
-/*******************************************************************/
-int main( int argc, char **argv );
-int main( int argc, char **argv )
-{
- int i;
- PaError result;
- int allDevices = 0;
- int testOutput = 1;
- int testInput = 1;
- char *executableName = argv[0];
-
- /* Parse command line parameters. */
- i = 1;
- while( i<argc )
- {
- char *arg = argv[i];
- if( arg[0] == '-' )
- {
- switch(arg[1])
- {
- case 'a':
- allDevices = 1;
- break;
- case 'i':
- testOutput = 0;
- break;
- case 'o':
- testInput = 0;
- break;
-
- default:
- printf("Illegal option: %s\n", arg);
- case '?':
- usage( executableName );
- exit(1);
- break;
- }
- }
- else
- {
- printf("Illegal argument: %s\n", arg);
- usage( executableName );
- return 1;
-
- }
- i += 1;
- }
-
- EXPECT(sizeof(short) == 2); /* The callback assumes we have 16-bit shorts. */
- EXPECT(sizeof(int) == 4); /* The callback assumes we have 32-bit ints. */
- EXPECT( ((result=Pa_Initialize()) == 0) );
-
- if( testOutput )
- {
- printf("\n---- Test OUTPUT ---------------\n");
- TestDevices( MODE_OUTPUT, allDevices );
- }
- if( testInput )
- {
- printf("\n---- Test INPUT ---------------\n");
- TestDevices( MODE_INPUT, allDevices );
- }
-
-error:
- Pa_Terminate();
- printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed );
- return (gNumFailed > 0) ? 1 : 0;
-}
-
-/*******************************************************************
-* Try each output device, through its full range of capabilities. */
-static void TestDevices( int mode, int allDevices )
-{
- int id, jc, i;
- int maxChannels;
- int isDefault;
- const PaDeviceInfo *pdi;
- static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0,
- 16000.0, 22050.0, 24000.0,
- 32000.0, 44100.0, 48000.0,
- 88200.0, 96000.0,
- -1.0 }; /* Negative terminated list. */
- int numDevices = Pa_GetDeviceCount();
- for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */
- {
- pdi = Pa_GetDeviceInfo( id );
-
- if( mode == MODE_INPUT ) {
- maxChannels = pdi->maxInputChannels;
- isDefault = ( id == Pa_GetDefaultInputDevice());
- } else {
- maxChannels = pdi->maxOutputChannels;
- isDefault = ( id == Pa_GetDefaultOutputDevice());
- }
- if( maxChannels > MAX_TEST_CHANNELS )
- maxChannels = MAX_TEST_CHANNELS;
-
- if (!allDevices && !isDefault) continue; // skip this device
-
- for( jc=1; jc<=maxChannels; jc++ )
- {
- printf("\n===========================================================\n");
- printf(" Device = %s\n", pdi->name );
- printf("===========================================================\n");
- /* Try each standard sample rate. */
- for( i=0; standardSampleRates[i] > 0; i++ )
- {
- TestFormats( mode, (PaDeviceIndex)id, standardSampleRates[i], jc );
- }
- }
- }
-}
-
-/*******************************************************************/
-static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate,
- int numChannels )
-{
- TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 );
- TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 );
- TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 );
- /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */
-}
-
-/*******************************************************************/
-static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
- int numChannels, PaSampleFormat format )
-{
- PaStreamParameters inputParameters, outputParameters, *ipp, *opp;
- PaStream *stream = NULL;
- PaError result = paNoError;
- PaQaData myData;
- #define FRAMES_PER_BUFFER (64)
- const int kNumSeconds = 100;
-
- /* Setup data for synthesis thread. */
- myData.framesLeft = (unsigned long) (sampleRate * kNumSeconds);
- myData.numChannels = numChannels;
- myData.mode = mode;
- myData.format = format;
- switch( format )
- {
- case paFloat32:
- case paInt32:
- case paInt24:
- myData.bytesPerSample = 4;
- break;
-/* case paPackedInt24:
- myData.bytesPerSample = 3;
- break; */
- default:
- myData.bytesPerSample = 2;
- break;
- }
-
- if( mode == MODE_INPUT )
- {
- inputParameters.device = deviceID;
- inputParameters.channelCount = numChannels;
- inputParameters.sampleFormat = format;
- inputParameters.suggestedLatency =
- Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
- inputParameters.hostApiSpecificStreamInfo = NULL;
- ipp = &inputParameters;
- }
- else
- {
- ipp = NULL;
- }
-
- if( mode == MODE_OUTPUT )
- {
- outputParameters.device = deviceID;
- outputParameters.channelCount = numChannels;
- outputParameters.sampleFormat = format;
- outputParameters.suggestedLatency =
- Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
- outputParameters.hostApiSpecificStreamInfo = NULL;
- opp = &outputParameters;
- }
- else
- {
- opp = NULL;
- }
-
- if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, sampleRate ))
- {
- printf("------ TestAdvance: %s, device = %d, rate = %g"
- ", numChannels = %d, format = %lu -------\n",
- ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT",
- deviceID, sampleRate, numChannels, (unsigned long)format);
- EXPECT( ((result = Pa_OpenStream( &stream,
- ipp,
- opp,
- sampleRate,
- FRAMES_PER_BUFFER,
- paClipOff, /* we won't output out of range samples so don't bother clipping them */
- QaCallback,
- &myData ) ) == 0) );
- if( stream )
- {
- PaTime oldStamp, newStamp;
- unsigned long oldFrames;
- int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400;
- /* Was:
- int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
- int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate);
- */
- int msec = (int)( 3.0 *
- (( mode == MODE_INPUT ) ? inputParameters.suggestedLatency : outputParameters.suggestedLatency ));
- if( msec < minDelay ) msec = minDelay;
- printf("msec = %d\n", msec); /**/
- EXPECT( ((result=Pa_StartStream( stream )) == 0) );
- /* Check to make sure PortAudio is advancing timeStamp. */
- oldStamp = Pa_GetStreamTime(stream);
- Pa_Sleep(msec);
- newStamp = Pa_GetStreamTime(stream);
- printf("oldStamp = %9.6f, newStamp = %9.6f\n", oldStamp, newStamp ); /**/
- EXPECT( (oldStamp < newStamp) );
- /* Check to make sure callback is decrementing framesLeft. */
- oldFrames = myData.framesLeft;
- Pa_Sleep(msec);
- printf("oldFrames = %lu, myData.framesLeft = %lu\n", oldFrames, myData.framesLeft ); /**/
- EXPECT( (oldFrames > myData.framesLeft) );
- EXPECT( ((result=Pa_CloseStream( stream )) == 0) );
- stream = NULL;
- }
- }
- return 0;
-error:
- if( stream != NULL ) Pa_CloseStream( stream );
- return -1;
-}
diff --git a/portaudio/qa/paqa_errs.c b/portaudio/qa/paqa_errs.c
deleted file mode 100644
index 8d4094f..0000000
--- a/portaudio/qa/paqa_errs.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/** @file paqa_errs.c
- @ingroup qa_src
- @brief Self Testing Quality Assurance app for PortAudio
- Do lots of bad things to test error reporting.
- @author Phil Burk http://www.softsynth.com
- Pieter Suurmond adapted to V19 API.
-*/
-/*
- * $Id$
- *
- * This program uses the PortAudio Portable Audio Library.
- * For more information see: http://www.portaudio.com
- * 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.
- *
- * 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 <math.h>
-
-#include "portaudio.h"
-
-/*--------- Definitions ---------*/
-#define MODE_INPUT (0)
-#define MODE_OUTPUT (1)
-#define FRAMES_PER_BUFFER (64)
-#define SAMPLE_RATE (44100.0)
-
-typedef struct PaQaData
-{
- unsigned long framesLeft;
- int numChannels;
- int bytesPerSample;
- int mode;
-}
-PaQaData;
-
-static int gNumPassed = 0; /* Two globals */
-static int gNumFailed = 0;
-
-/*------------------- Macros ------------------------------*/
-/* Print ERROR if it fails. Tally success or failure. Odd */
-/* do-while wrapper seems to be needed for some compilers. */
-
-#define EXPECT(_exp) \
- do \
- { \
- if ((_exp)) {\
- gNumPassed++; \
- } \
- else { \
- printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \
- gNumFailed++; \
- goto error; \
- } \
- } while(0)
-
-#define HOPEFOR(_exp) \
- do \
- { \
- if ((_exp)) {\
- gNumPassed++; \
- } \
- else { \
- printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \
- gNumFailed++; \
- } \
- } while(0)
-
-/*-------------------------------------------------------------------------*/
-/* This routine will be called by the PortAudio engine when audio is needed.
- It may be called at interrupt level on some machines so don't do anything
- that could mess up the system like calling malloc() or free().
-*/
-static int QaCallback( const void* inputBuffer,
- void* outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void* userData )
-{
- unsigned long i;
- unsigned char* out = (unsigned char *) outputBuffer;
- PaQaData* data = (PaQaData *) userData;
-
- (void)inputBuffer; /* Prevent "unused variable" warnings. */
-
- /* Zero out buffer so we don't hear terrible noise. */
- if( data->mode == MODE_OUTPUT )
- {
- unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
- for( i=0; i<numBytes; i++ )
- {
- *out++ = 0;
- }
- }
- /* Are we through yet? */
- if( data->framesLeft > framesPerBuffer )
- {
- data->framesLeft -= framesPerBuffer;
- return 0;
- }
- else
- {
- data->framesLeft = 0;
- return 1;
- }
-}
-
-static PaDeviceIndex FindInputOnlyDevice(void)
-{
- PaDeviceIndex result = Pa_GetDefaultInputDevice();
- if( result != paNoDevice && Pa_GetDeviceInfo(result)->maxOutputChannels == 0 )
- return result;
-
- for( result = 0; result < Pa_GetDeviceCount(); ++result )
- {
- if( Pa_GetDeviceInfo(result)->maxOutputChannels == 0 )
- return result;
- }
-
- return paNoDevice;
-}
-
-static PaDeviceIndex FindOutputOnlyDevice(void)
-{
- PaDeviceIndex result = Pa_GetDefaultOutputDevice();
- if( result != paNoDevice && Pa_GetDeviceInfo(result)->maxInputChannels == 0 )
- return result;
-
- for( result = 0; result < Pa_GetDeviceCount(); ++result )
- {
- if( Pa_GetDeviceInfo(result)->maxInputChannels == 0 )
- return result;
- }
-
- return paNoDevice;
-}
-
-/*-------------------------------------------------------------------------------------------------*/
-static int TestBadOpens( void )
-{
- PaStream* stream = NULL;
- PaError result;
- PaQaData myData;
- PaStreamParameters ipp, opp;
- const PaDeviceInfo* info = NULL;
-
-
- /* Setup data for synthesis thread. */
- myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */
- myData.numChannels = 1;
- myData.mode = MODE_OUTPUT;
-
- /*----------------------------- No devices specified: */
- ipp.device = opp.device = paNoDevice;
- ipp.channelCount = opp.channelCount = 0; /* Also no channels. */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- /* Take the low latency of the default device for all subsequent tests. */
- info = Pa_GetDeviceInfo(Pa_GetDefaultInputDevice());
- ipp.suggestedLatency = info ? info->defaultLowInputLatency : 0.100;
- info = Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice());
- opp.suggestedLatency = info ? info->defaultLowOutputLatency : 0.100;
- HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidDevice));
-
- /*----------------------------- No devices specified #2: */
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, NULL,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidDevice));
-
- /*----------------------------- Out of range input device specified: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = Pa_GetDeviceCount(); /* And no output device, and no channels. */
- opp.channelCount = 0; opp.device = paNoDevice;
- HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, NULL,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidDevice));
-
- /*----------------------------- Out of range output device specified: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice; /* And no input device, and no channels. */
- opp.channelCount = 0; opp.device = Pa_GetDeviceCount();
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidDevice));
-
- if (Pa_GetDefaultInputDevice() != paNoDevice) {
- /*----------------------------- Zero input channels: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = Pa_GetDefaultInputDevice();
- opp.channelCount = 0; opp.device = paNoDevice; /* And no output device, and no output channels. */
- HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, NULL,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidChannelCount));
- }
-
- if (Pa_GetDefaultOutputDevice() != paNoDevice) {
- /*----------------------------- Zero output channels: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice; /* And no input device, and no input channels. */
- opp.channelCount = 0; opp.device = Pa_GetDefaultOutputDevice();
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidChannelCount));
- }
- /*----------------------------- Nonzero input and output channels but no output device: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 2; ipp.device = Pa_GetDefaultInputDevice(); /* Both stereo. */
- opp.channelCount = 2; opp.device = paNoDevice;
- HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidDevice));
-
- /*----------------------------- Nonzero input and output channels but no input device: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 2; ipp.device = paNoDevice;
- opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice();
- HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidDevice));
-
- if (Pa_GetDefaultOutputDevice() != paNoDevice) {
- /*----------------------------- NULL stream pointer: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice; /* Output is more likely than input. */
- opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice(); /* Only 2 output channels. */
- HOPEFOR(((result = Pa_OpenStream(NULL, &ipp, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paBadStreamPtr));
-
- /*----------------------------- Low sample rate: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice;
- opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice();
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp,
- 1.0, FRAMES_PER_BUFFER, /* 1 cycle per second (1 Hz) is too low. */
- paClipOff, QaCallback, &myData )) == paInvalidSampleRate));
-
- /*----------------------------- High sample rate: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice;
- opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice();
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp,
- 10000000.0, FRAMES_PER_BUFFER, /* 10^6 cycles per second (10 MHz) is too high. */
- paClipOff, QaCallback, &myData )) == paInvalidSampleRate));
-
- /*----------------------------- NULL callback: */
- /* NULL callback is valid in V19 -- it means use blocking read/write stream
-
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice;
- opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice();
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff,
- NULL,
- &myData )) == paNullCallback));
- */
-
- /*----------------------------- Bad flag: */
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice;
- opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice();
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- 255, /* Is 8 maybe legal V19 API? */
- QaCallback, &myData )) == paInvalidFlag));
- }
-
- /*----------------------------- using input device as output device: */
- if( FindInputOnlyDevice() != paNoDevice )
- {
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 0; ipp.device = paNoDevice; /* And no input device, and no channels. */
- opp.channelCount = 2; opp.device = FindInputOnlyDevice();
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidChannelCount));
- }
-
- /*----------------------------- using output device as input device: */
- if( FindOutputOnlyDevice() != paNoDevice )
- {
- ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL;
- ipp.sampleFormat = opp.sampleFormat = paFloat32;
- ipp.channelCount = 2; ipp.device = FindOutputOnlyDevice();
- opp.channelCount = 0; opp.device = paNoDevice; /* And no output device, and no channels. */
- HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, NULL,
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paInvalidChannelCount));
-
- }
-
- if( stream != NULL ) Pa_CloseStream( stream );
- return result;
-}
-
-/*-----------------------------------------------------------------------------------------*/
-static int TestBadActions( void )
-{
- PaStream* stream = NULL;
- const PaDeviceInfo* deviceInfo = NULL;
- PaError result = 0;
- PaQaData myData;
- PaStreamParameters opp;
- const PaDeviceInfo* info = NULL;
-
- /* Setup data for synthesis thread. */
- myData.framesLeft = (unsigned long)(SAMPLE_RATE * 100); /* 100 seconds */
- myData.numChannels = 1;
- myData.mode = MODE_OUTPUT;
-
- opp.device = Pa_GetDefaultOutputDevice(); /* Default output. */
- opp.channelCount = 2; /* Stereo output. */
- opp.hostApiSpecificStreamInfo = NULL;
- opp.sampleFormat = paFloat32;
- info = Pa_GetDeviceInfo(opp.device);
- opp.suggestedLatency = info ? info->defaultLowOutputLatency : 0.100;
-
- if (opp.device != paNoDevice) {
- HOPEFOR(((result = Pa_OpenStream(&stream, NULL, /* Take NULL as input parame- */
- &opp, /* ters, meaning try only output. */
- SAMPLE_RATE, FRAMES_PER_BUFFER,
- paClipOff, QaCallback, &myData )) == paNoError));
- }
-
- HOPEFOR(((deviceInfo = Pa_GetDeviceInfo(paNoDevice)) == NULL));
- HOPEFOR(((deviceInfo = Pa_GetDeviceInfo(87654)) == NULL));
- HOPEFOR(((result = Pa_StartStream(NULL)) == paBadStreamPtr));
- HOPEFOR(((result = Pa_StopStream(NULL)) == paBadStreamPtr));
- HOPEFOR(((result = Pa_IsStreamStopped(NULL)) == paBadStreamPtr));
- HOPEFOR(((result = Pa_IsStreamActive(NULL)) == paBadStreamPtr));
- HOPEFOR(((result = Pa_CloseStream(NULL)) == paBadStreamPtr));
- HOPEFOR(((result = Pa_SetStreamFinishedCallback(NULL, NULL)) == paBadStreamPtr));
- HOPEFOR(((result = !Pa_GetStreamInfo(NULL))));
- HOPEFOR(((result = Pa_GetStreamTime(NULL)) == 0.0));
- HOPEFOR(((result = Pa_GetStreamCpuLoad(NULL)) == 0.0));
- HOPEFOR(((result = Pa_ReadStream(NULL, NULL, 0)) == paBadStreamPtr));
- HOPEFOR(((result = Pa_WriteStream(NULL, NULL, 0)) == paBadStreamPtr));
-
- /** @todo test Pa_GetStreamReadAvailable and Pa_GetStreamWriteAvailable */
-
- if (stream != NULL) Pa_CloseStream(stream);
- return result;
-}
-
-/*---------------------------------------------------------------------*/
-int main(void);
-int main(void)
-{
- PaError result;
-
- EXPECT(((result = Pa_Initialize()) == paNoError));
- TestBadOpens();
- TestBadActions();
-error:
- Pa_Terminate();
- printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed);
- return 0;
-}
diff --git a/portaudio/qa/paqa_latency.c b/portaudio/qa/paqa_latency.c
deleted file mode 100644
index a70807b..0000000
--- a/portaudio/qa/paqa_latency.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/** @file paqa_latency.c
- @ingroup qa_src
- @brief Test latency estimates.
- @author Ross Bencina <rossb@audiomulch.com>
- @author Phil Burk <philburk@softsynth.com>
-*/
-/*
- * $Id: patest_sine.c 1368 2008-03-01 00:38:27Z rossb $
- *
- * This program uses the PortAudio Portable Audio Library.
- * For more information see: http://www.portaudio.com/
- * 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.
- *
- * 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 <math.h>
-#include "portaudio.h"
-#include "loopback/src/qa_tools.h"
-
-#define NUM_SECONDS (5)
-#define SAMPLE_RATE (44100)
-#define FRAMES_PER_BUFFER (64)
-
-#ifndef M_PI
-#define M_PI (3.14159265)
-#endif
-
-#define TABLE_SIZE (200)
-typedef struct
-{
- float sine[TABLE_SIZE];
- int left_phase;
- int right_phase;
- char message[20];
- int minFramesPerBuffer;
- int maxFramesPerBuffer;
- int callbackCount;
- PaTime minDeltaDacTime;
- PaTime maxDeltaDacTime;
- PaStreamCallbackTimeInfo previousTimeInfo;
-}
-paTestData;
-
-/* Used to tally the results of the QA tests. */
-int g_testsPassed = 0;
-int g_testsFailed = 0;
-
-/* This routine will be called by the PortAudio engine when audio is needed.
-** It may called at interrupt level on some machines so don't do anything
-** that could mess up the system like calling malloc() or free().
-*/
-static int patestCallback( const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
-{
- paTestData *data = (paTestData*)userData;
- float *out = (float*)outputBuffer;
- unsigned long i;
-
- (void) timeInfo; /* Prevent unused variable warnings. */
- (void) statusFlags;
- (void) inputBuffer;
-
- if( data->minFramesPerBuffer > framesPerBuffer )
- {
- data->minFramesPerBuffer = framesPerBuffer;
- }
- if( data->maxFramesPerBuffer < framesPerBuffer )
- {
- data->maxFramesPerBuffer = framesPerBuffer;
- }
-
- /* Measure min and max output time stamp delta. */
- if( data->callbackCount > 0 )
- {
- PaTime delta = timeInfo->outputBufferDacTime - data->previousTimeInfo.outputBufferDacTime;
- if( data->minDeltaDacTime > delta )
- {
- data->minDeltaDacTime = delta;
- }
- if( data->maxDeltaDacTime < delta )
- {
- data->maxDeltaDacTime = delta;
- }
- }
- data->previousTimeInfo = *timeInfo;
-
- for( i=0; i<framesPerBuffer; i++ )
- {
- *out++ = data->sine[data->left_phase]; /* left */
- *out++ = data->sine[data->right_phase]; /* right */
- data->left_phase += 1;
- if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
- data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
- if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
- }
-
- data->callbackCount += 1;
- return paContinue;
-}
-
-PaError paqaCheckLatency( PaStreamParameters *outputParamsPtr,
- paTestData *dataPtr, double sampleRate, unsigned long framesPerBuffer )
-{
- PaError err;
- PaStream *stream;
- const PaStreamInfo* streamInfo;
-
- dataPtr->minFramesPerBuffer = 9999999;
- dataPtr->maxFramesPerBuffer = 0;
- dataPtr->minDeltaDacTime = 9999999.0;
- dataPtr->maxDeltaDacTime = 0.0;
- dataPtr->callbackCount = 0;
-
- printf("Stream parameter: suggestedOutputLatency = %g\n", outputParamsPtr->suggestedLatency );
- if( framesPerBuffer == paFramesPerBufferUnspecified ){
- printf("Stream parameter: user framesPerBuffer = paFramesPerBufferUnspecified\n" );
- }else{
- printf("Stream parameter: user framesPerBuffer = %lu\n", framesPerBuffer );
- }
- err = Pa_OpenStream(
- &stream,
- NULL, /* no input */
- outputParamsPtr,
- sampleRate,
- framesPerBuffer,
- paClipOff, /* we won't output out of range samples so don't bother clipping them */
- patestCallback,
- dataPtr );
- if( err != paNoError ) goto error1;
-
- streamInfo = Pa_GetStreamInfo( stream );
- printf("Stream info: inputLatency = %g\n", streamInfo->inputLatency );
- printf("Stream info: outputLatency = %g\n", streamInfo->outputLatency );
-
- err = Pa_StartStream( stream );
- if( err != paNoError ) goto error2;
-
- printf("Play for %d seconds.\n", NUM_SECONDS );
- Pa_Sleep( NUM_SECONDS * 1000 );
-
- printf(" minFramesPerBuffer = %4d\n", dataPtr->minFramesPerBuffer );
- printf(" maxFramesPerBuffer = %4d\n", dataPtr->maxFramesPerBuffer );
- printf(" minDeltaDacTime = %f\n", dataPtr->minDeltaDacTime );
- printf(" maxDeltaDacTime = %f\n", dataPtr->maxDeltaDacTime );
-
- err = Pa_StopStream( stream );
- if( err != paNoError ) goto error2;
-
- err = Pa_CloseStream( stream );
- Pa_Sleep( 1 * 1000 );
-
-
- printf("-------------------------------------\n");
- return err;
-error2:
- Pa_CloseStream( stream );
-error1:
- printf("-------------------------------------\n");
- return err;
-}
-
-
-/*******************************************************************/
-static int paqaNoopCallback( const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
-{
- (void)inputBuffer;
- (void)outputBuffer;
- (void)framesPerBuffer;
- (void)timeInfo;
- (void)statusFlags;
- (void)userData;
- return paContinue;
-}
-
-/*******************************************************************/
-static int paqaCheckMultipleSuggested( PaDeviceIndex deviceIndex, int isInput )
-{
- int i;
- int numLoops = 10;
- PaError err;
- PaStream *stream;
- PaStreamParameters streamParameters;
- const PaStreamInfo* streamInfo;
- double lowLatency;
- double highLatency;
- double finalLatency;
- double sampleRate = SAMPLE_RATE;
- const PaDeviceInfo *pdi = Pa_GetDeviceInfo( deviceIndex );
- double previousLatency = 0.0;
- int numChannels = 1;
- float toleranceRatio = 1.0;
-
- printf("------------------------ paqaCheckMultipleSuggested - %s\n",
- (isInput ? "INPUT" : "OUTPUT") );
- if( isInput )
- {
- lowLatency = pdi->defaultLowInputLatency;
- highLatency = pdi->defaultHighInputLatency;
- numChannels = (pdi->maxInputChannels < 2) ? 1 : 2;
- }
- else
- {
- lowLatency = pdi->defaultLowOutputLatency;
- highLatency = pdi->defaultHighOutputLatency;
- numChannels = (pdi->maxOutputChannels < 2) ? 1 : 2;
- }
- streamParameters.channelCount = numChannels;
- streamParameters.device = deviceIndex;
- streamParameters.hostApiSpecificStreamInfo = NULL;
- streamParameters.sampleFormat = paFloat32;
- sampleRate = pdi->defaultSampleRate;
-
- printf(" lowLatency = %g\n", lowLatency );
- printf(" highLatency = %g\n", highLatency );
- printf(" numChannels = %d\n", numChannels );
- printf(" sampleRate = %g\n", sampleRate );
-
- if( (highLatency - lowLatency) < 0.001 )
- {
- numLoops = 1;
- }
-
- for( i=0; i<numLoops; i++ )
- {
- if( numLoops == 1 )
- streamParameters.suggestedLatency = lowLatency;
- else
- streamParameters.suggestedLatency = lowLatency + ((highLatency - lowLatency) * i /(numLoops - 1));
-
- printf(" suggestedLatency[%d] = %6.4f\n", i, streamParameters.suggestedLatency );
-
- err = Pa_OpenStream(
- &stream,
- (isInput ? &streamParameters : NULL),
- (isInput ? NULL : &streamParameters),
- sampleRate,
- paFramesPerBufferUnspecified,
- paClipOff, /* we won't output out of range samples so don't bother clipping them */
- paqaNoopCallback,
- NULL );
- if( err != paNoError ) goto error;
-
- streamInfo = Pa_GetStreamInfo( stream );
-
- err = Pa_CloseStream( stream );
-
- if( isInput )
- {
- finalLatency = streamInfo->inputLatency;
- }
- else
- {
- finalLatency = streamInfo->outputLatency;
- }
- printf(" finalLatency = %6.4f\n", finalLatency );
- /* For the default low & high latency values, expect quite close; for other requested
- * values, at worst the next power-of-2 may result (eg 513 -> 1024) */
- toleranceRatio = ( (i == 0) || (i == ( numLoops - 1 )) ) ? 0.1 : 1.0;
- QA_ASSERT_CLOSE( "final latency should be close to suggested latency",
- streamParameters.suggestedLatency, finalLatency, (streamParameters.suggestedLatency * toleranceRatio) );
- if( i == 0 )
- {
- previousLatency = finalLatency;
- }
- }
-
- if( numLoops > 1 )
- {
- QA_ASSERT_TRUE( " final latency should increase with suggested latency", (finalLatency > previousLatency) );
- }
-
- return 0;
-error:
- return -1;
-}
-
-/*******************************************************************/
-static int paqaVerifySuggestedLatency( void )
-{
- PaDeviceIndex id;
- int result = 0;
- const PaDeviceInfo *pdi;
- int numDevices = Pa_GetDeviceCount();
-
- printf("\n ------------------------ paqaVerifySuggestedLatency\n");
- for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */
- {
- pdi = Pa_GetDeviceInfo( id );
- printf("\nUsing device #%d: '%s' (%s)\n", id, pdi->name, Pa_GetHostApiInfo(pdi->hostApi)->name);
- if( pdi->maxOutputChannels > 0 )
- {
- if( paqaCheckMultipleSuggested( id, 0 ) < 0 )
- {
- printf("OUTPUT CHECK FAILED !!! #%d: '%s'\n", id, pdi->name);
- result -= 1;
- }
- }
- if( pdi->maxInputChannels > 0 )
- {
- if( paqaCheckMultipleSuggested( id, 1 ) < 0 )
- {
- printf("INPUT CHECK FAILED !!! #%d: '%s'\n", id, pdi->name);
- result -= 1;
- }
- }
- }
- return result;
-}
-
-/*******************************************************************/
-static int paqaVerifyDeviceInfoLatency( void )
-{
- PaDeviceIndex id;
- const PaDeviceInfo *pdi;
- int numDevices = Pa_GetDeviceCount();
-
- printf("\n ------------------------ paqaVerifyDeviceInfoLatency\n");
- for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */
- {
- pdi = Pa_GetDeviceInfo( id );
- printf("Using device #%d: '%s' (%s)\n", id, pdi->name, Pa_GetHostApiInfo(pdi->hostApi)->name);
- if( pdi->maxOutputChannels > 0 )
- {
- printf(" Output defaultLowOutputLatency = %f seconds\n", pdi->defaultLowOutputLatency);
- printf(" Output defaultHighOutputLatency = %f seconds\n", pdi->defaultHighOutputLatency);
- QA_ASSERT_TRUE( "defaultLowOutputLatency should be > 0", (pdi->defaultLowOutputLatency > 0.0) );
- QA_ASSERT_TRUE( "defaultHighOutputLatency should be > 0", (pdi->defaultHighOutputLatency > 0.0) );
- QA_ASSERT_TRUE( "defaultHighOutputLatency should be >= Low", (pdi->defaultHighOutputLatency >= pdi->defaultLowOutputLatency) );
- }
- if( pdi->maxInputChannels > 0 )
- {
- printf(" Input defaultLowInputLatency = %f seconds\n", pdi->defaultLowInputLatency);
- printf(" Input defaultHighInputLatency = %f seconds\n", pdi->defaultHighInputLatency);
- QA_ASSERT_TRUE( "defaultLowInputLatency should be > 0", (pdi->defaultLowInputLatency > 0.0) );
- QA_ASSERT_TRUE( "defaultHighInputLatency should be > 0", (pdi->defaultHighInputLatency > 0.0) );
- QA_ASSERT_TRUE( "defaultHighInputLatency should be >= Low", (pdi->defaultHighInputLatency >= pdi->defaultLowInputLatency) );
- }
- }
- return 0;
-error:
- return -1;
-}
-
-
-
-/*******************************************************************/
-int main(void);
-int main(void)
-{
- PaStreamParameters outputParameters;
- PaError err;
- paTestData data;
- const PaDeviceInfo *deviceInfo;
- int i;
- int framesPerBuffer;
- double sampleRate = SAMPLE_RATE;
-
- printf("\nPortAudio QA: investigate output latency.\n");
-
- /* initialise sinusoidal wavetable */
- for( i=0; i<TABLE_SIZE; i++ )
- {
- data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
- }
- data.left_phase = data.right_phase = 0;
-
- err = Pa_Initialize();
- if( err != paNoError ) goto error;
-
- /* Run self tests. */
- if( paqaVerifyDeviceInfoLatency() < 0 ) goto error;
-
- if( paqaVerifySuggestedLatency() < 0 ) goto error;
-
- outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
- if (outputParameters.device == paNoDevice) {
- fprintf(stderr,"Error: No default output device.\n");
- goto error;
- }
-
- printf("\n\nNow running Audio Output Tests...\n");
- printf("-------------------------------------\n");
-
- outputParameters.channelCount = 2; /* stereo output */
- outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
- deviceInfo = Pa_GetDeviceInfo( outputParameters.device );
- printf("Using device #%d: '%s' (%s)\n", outputParameters.device, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name);
- printf("Device info: defaultLowOutputLatency = %f seconds\n", deviceInfo->defaultLowOutputLatency);
- printf("Device info: defaultHighOutputLatency = %f seconds\n", deviceInfo->defaultHighOutputLatency);
- sampleRate = deviceInfo->defaultSampleRate;
- printf("Sample Rate for following tests: %g\n", sampleRate);
- outputParameters.hostApiSpecificStreamInfo = NULL;
- printf("-------------------------------------\n");
-
- // Try to use a small buffer that is smaller than we think the device can handle.
- // Try to force combining multiple user buffers into a host buffer.
- printf("------------- Try a very small buffer.\n");
- framesPerBuffer = 9;
- outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency;
- err = paqaCheckLatency( &outputParameters, &data, sampleRate, framesPerBuffer );
- if( err != paNoError ) goto error;
-
- printf("------------- 64 frame buffer with 1.1 * defaultLow latency.\n");
- framesPerBuffer = 64;
- outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency * 1.1;
- err = paqaCheckLatency( &outputParameters, &data, sampleRate, framesPerBuffer );
- if( err != paNoError ) goto error;
-
- // Try to create a huge buffer that is bigger than the allowed device maximum.
- printf("------------- Try a huge buffer.\n");
- framesPerBuffer = 16*1024;
- outputParameters.suggestedLatency = ((double)framesPerBuffer) / sampleRate; // approximate
- err = paqaCheckLatency( &outputParameters, &data, sampleRate, framesPerBuffer );
- if( err != paNoError ) goto error;
-
- printf("------------- Try suggestedLatency = 0.0\n");
- outputParameters.suggestedLatency = 0.0;
- err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified );
- if( err != paNoError ) goto error;
-
- printf("------------- Try suggestedLatency = defaultLowOutputLatency\n");
- outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency;
- err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified );
- if( err != paNoError ) goto error;
-
- printf("------------- Try suggestedLatency = defaultHighOutputLatency\n");
- outputParameters.suggestedLatency = deviceInfo->defaultHighOutputLatency;
- err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified );
- if( err != paNoError ) goto error;
-
- printf("------------- Try suggestedLatency = defaultHighOutputLatency * 4\n");
- outputParameters.suggestedLatency = deviceInfo->defaultHighOutputLatency * 4;
- err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified );
- if( err != paNoError ) goto error;
-
- Pa_Terminate();
- printf("SUCCESS - test finished.\n");
- return err;
-
-error:
- Pa_Terminate();
- fprintf( stderr, "ERROR - test failed.\n" );
- fprintf( stderr, "Error number: %d\n", err );
- fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
- return err;
-}