diff options
Diffstat (limited to '3rdparty/portaudio/qa')
18 files changed, 3371 insertions, 2837 deletions
diff --git a/3rdparty/portaudio/qa/CMakeLists.txt b/3rdparty/portaudio/qa/CMakeLists.txt new file mode 100644 index 00000000000..6577c980c55 --- /dev/null +++ b/3rdparty/portaudio/qa/CMakeLists.txt @@ -0,0 +1,5 @@ +add_test(paqa_devs) +add_test(paqa_errs) +add_test(paqa_latency) + +subdirs(loopback) diff --git a/3rdparty/portaudio/qa/loopback/CMakeLists.txt b/3rdparty/portaudio/qa/loopback/CMakeLists.txt new file mode 100644 index 00000000000..ca6408a9f29 --- /dev/null +++ b/3rdparty/portaudio/qa/loopback/CMakeLists.txt @@ -0,0 +1,19 @@ +add_executable(paloopback + src/audio_analyzer.c + src/audio_analyzer.h + src/biquad_filter.c + src/biquad_filter.h + src/paqa.c + src/paqa_tools.c + src/paqa_tools.h + src/qa_tools.h + src/test_audio_analyzer.c + src/test_audio_analyzer.h + src/write_wav.c + src/write_wav.h +) +target_include_directories(paloopback PRIVATE ..) +target_link_libraries(paloopback PortAudio) +if(UNIX) + target_link_libraries(paloopback m) +endif() diff --git a/3rdparty/portaudio/qa/loopback/src/audio_analyzer.c b/3rdparty/portaudio/qa/loopback/src/audio_analyzer.c index 0a3dbdf9232..fbdd6318205 100644 --- a/3rdparty/portaudio/qa/loopback/src/audio_analyzer.c +++ b/3rdparty/portaudio/qa/loopback/src/audio_analyzer.c @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -50,153 +50,153 @@ /*==========================================================================================*/ 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 ); + // 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; - } + 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; + 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; - } - } + 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 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; + 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; + return 1; } /*==========================================================================================*/ void PaQa_TerminateRecording( PaQaRecording *recording ) -{ - if (recording->buffer != NULL) - { - free( recording->buffer ); - recording->buffer = NULL; - } - recording->maxFrames = 0; +{ + 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; + 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); + 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; + 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); + 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; + 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); + 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); } /*==========================================================================================*/ @@ -209,37 +209,37 @@ int PaQa_SaveRecordingToWaveFile( PaQaRecording *recording, const char *filename int result = 0; #define NUM_SAMPLES (200) short data[NUM_SAMPLES]; - const int samplesPerFrame = 1; + const int samplesPerFrame = 1; int numLeft = recording->numFrames; - float *buffer = &recording->buffer[0]; + float *buffer = &recording->buffer[0]; result = Audio_WAV_OpenWriter( &writer, filename, recording->sampleRate, samplesPerFrame ); if( result < 0 ) goto error; - - while( numLeft > 0 ) + + while( numLeft > 0 ) { - int i; + 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 ); + // 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; + numLeft -= numToSave; } - + result = Audio_WAV_CloseWriter( &writer ); if( result < 0 ) goto error; - + return 0; - + error: printf("ERROR: result = %d\n", result ); return result; @@ -250,29 +250,29 @@ error: 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; + 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; } /*==========================================================================================*/ @@ -285,63 +285,63 @@ double PaQa_MeasureCrossingSlope( float *buffer, int numFrames ) * */ double PaQa_MeasureSineAmplitudeBySlope( PaQaRecording *recording, - double frequency, double frameRate, - int startFrame, int numFrames ) + 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; + 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 ) + int startFrame, int numFrames, double *phasePtr ) { - double magnitude = 0.0; + 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]; + 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; + 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; + 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; + int numToFilter = (input->numFrames > output->maxFrames) ? output->maxFrames : input->numFrames; + BiquadFilter_Filter( filter, &input->buffer[0], &output->buffer[0], numToFilter ); + output->numFrames = numToFilter; } /*==========================================================================================*/ @@ -351,92 +351,92 @@ void PaQa_FilterRecording( PaQaRecording *input, PaQaRecording *output, BiquadFi */ 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; + 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; + 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; + 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; + 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; + 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; } @@ -446,92 +446,92 @@ double PaQa_MeasureRootMeanSquare( float *buffer, int numFrames ) double PaQa_CompareAmplitudes( PaQaRecording *recording, int startAt, float *buffer, int numFrames ) { - QA_ASSERT_TRUE( "startAt+numFrames out of bounds", ((startAt+numFrames) < recording->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; + 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; + 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; + 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; + 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; + 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; + 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; - + 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 ); - + assert( count > 0 ); + /* Zero out initial part of the recording. */ - for( is=0; is<startFrame; is++ ) - { + 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; + 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; - } + } } @@ -539,146 +539,146 @@ void PaQa_FadeInRecording( PaQaRecording *recording, int startFrame, int count ) /** 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; + 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( ¬chOutput, 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( ¬chFilter, testTone->frequency / frameRate, 0.5 ); - PaQa_FilterRecording( recording, ¬chOutput, ¬chFilter ); - //result = PaQa_SaveRecordingToWaveFile( ¬chOutput, "notch_output.wav" ); - //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result ); - - // Apply fade-in window. - PaQa_FadeInRecording( ¬chOutput, (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( ¬chOutput, &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( ¬chOutput ); - PaQa_TerminateRecording( &hipassOutput ); - return 0; - + 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( ¬chOutput, 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( ¬chFilter, testTone->frequency / frameRate, 0.5 ); + PaQa_FilterRecording( recording, ¬chOutput, ¬chFilter ); + //result = PaQa_SaveRecordingToWaveFile( ¬chOutput, "notch_output.wav" ); + //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result ); + + // Apply fade-in window. + PaQa_FadeInRecording( ¬chOutput, (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( ¬chOutput, &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( ¬chOutput ); + PaQa_TerminateRecording( &hipassOutput ); + return 0; + error: - PaQa_TerminateRecording( ¬chOutput ); - PaQa_TerminateRecording( &hipassOutput ); - return -1; + PaQa_TerminateRecording( ¬chOutput ); + 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; +{ + 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; + 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; } /*==========================================================================================*/ @@ -686,22 +686,21 @@ int PaQa_AnalyseRecording( PaQaRecording *recording, PaQaTestTone *testTone, PaQ { int result = 0; - memset( analysisResult, 0, sizeof(PaQaAnalysisResult) ); - result = PaQa_MeasureLatency( recording, testTone, analysisResult ); + 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; + + 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; + return -1; } - diff --git a/3rdparty/portaudio/qa/loopback/src/audio_analyzer.h b/3rdparty/portaudio/qa/loopback/src/audio_analyzer.h index 2a867983ba2..8d9f1ee4f60 100644 --- a/3rdparty/portaudio/qa/loopback/src/audio_analyzer.h +++ b/3rdparty/portaudio/qa/loopback/src/audio_analyzer.h @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -46,44 +46,44 @@ typedef struct PaQaSineGenerator_s { - double phase; - double phaseIncrement; - double frequency; - double amplitude; + double phase; + double phaseIncrement; + double frequency; + double amplitude; } PaQaSineGenerator; -/** Container for a monophonic audio sample in memory. */ +/** 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; + /** 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; + 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; + 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; @@ -101,7 +101,7 @@ 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 ); + double frequency, double amplitude ); /** * Generate a signal with a sharp edge in the middle that can be recognized despite some phase shift. @@ -130,15 +130,15 @@ void PaQa_SetupSineGenerator( PaQaSineGenerator *generator, double frequency, do /*================= Recordings ===================================*/ /*================================================================*/ /** - * Allocate memory for containg a mono audio signal. Set up recording for writing. + * 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. */ @@ -146,29 +146,29 @@ void PaQa_FilterRecording( PaQaRecording *input, PaQaRecording *output, BiquadFi 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 ); + 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 frequency, double frameRate, + int startFrame, int numFrames ); double PaQa_MeasureRootMeanSquare( float *buffer, int numFrames ); diff --git a/3rdparty/portaudio/qa/loopback/src/biquad_filter.c b/3rdparty/portaudio/qa/loopback/src/biquad_filter.c index 1bc4a232ab6..1715fa3c65a 100755 --- a/3rdparty/portaudio/qa/loopback/src/biquad_filter.c +++ b/3rdparty/portaudio/qa/loopback/src/biquad_filter.c @@ -4,9 +4,10 @@ #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) + * 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 */ @@ -17,17 +18,17 @@ */ static void BiquadFilter_CalculateCommon( BiquadFilter *filter, double ratio, double Q ) { - double omega; - - memset( filter, 0, sizeof(BiquadFilter) ); + 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; + 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); + filter->cos_omega = (double) cos( omega ); + filter->sin_omega = (double) sin( omega ); + filter->alpha = filter->sin_omega / (2.0 * Q); } /********************************************************************************* @@ -35,21 +36,21 @@ static void BiquadFilter_CalculateCommon( BiquadFilter *filter, double ratio, do */ 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; + 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; + filter->b1 = -2.0 * filter->cos_omega * scalar; + filter->b2 = (1.0 - filter->alpha) * scalar; } @@ -58,21 +59,21 @@ void BiquadFilter_SetupHighPass( BiquadFilter *filter, double ratio, double Q ) */ 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; + 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; + filter->b1 = filter->a1; + filter->b2 = (1.0 - filter->alpha) * scalar; } /***************************************************************** @@ -80,43 +81,43 @@ void BiquadFilter_SetupNotch( BiquadFilter *filter, double ratio, double Q ) */ void BiquadFilter_Filter( BiquadFilter *filter, float *inputs, float *outputs, int numSamples ) { - int i; + 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. + // 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; + + 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/3rdparty/portaudio/qa/loopback/src/biquad_filter.h b/3rdparty/portaudio/qa/loopback/src/biquad_filter.h index cbac688b6fd..0895abae73e 100755 --- a/3rdparty/portaudio/qa/loopback/src/biquad_filter.h +++ b/3rdparty/portaudio/qa/loopback/src/biquad_filter.h @@ -3,7 +3,7 @@ /** - * Unit_BiquadFilter implements a second order IIR filter. + * Unit_BiquadFilter implements a second order IIR filter. * * @author (C) 2002 Phil Burk, SoftSynth.com, All Rights Reserved */ @@ -14,20 +14,20 @@ typedef struct BiquadFilter_s { double xn1; // storage for delayed signals - double xn2; - double yn1; - double yn2; + double xn2; + double yn1; + double yn2; - double a0; // coefficients - double a1; - double a2; + double a0; // coefficients + double a1; + double a2; - double b1; - double b2; + double b1; + double b2; - double cos_omega; - double sin_omega; - double alpha; + double cos_omega; + double sin_omega; + double alpha; } BiquadFilter; void BiquadFilter_SetupHighPass( BiquadFilter *filter, double ratio, double Q ); diff --git a/3rdparty/portaudio/qa/loopback/src/paqa.c b/3rdparty/portaudio/qa/loopback/src/paqa.c index cb7100d7807..909916b1388 100644 --- a/3rdparty/portaudio/qa/loopback/src/paqa.c +++ b/3rdparty/portaudio/qa/loopback/src/paqa.c @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -69,76 +69,76 @@ int g_testsFailed = 0; const char * s_FlagOnNames[] = { - "Two Streams (Half Duplex)", - "Blocking Read/Write" + "Two Streams (Half Duplex)", + "Blocking Read/Write" }; const char * s_FlagOffNames[] = { - "One Stream (Full Duplex)", - "Callback" + "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; + 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 + 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; - + // 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; + + unsigned long minFramesPerBuffer; + unsigned long 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; + 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) @@ -150,105 +150,105 @@ 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 ) + 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; - } - + 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 ); - } - - } - + * 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 ) { @@ -259,21 +259,21 @@ static int RecordAndPlaySinesCallback( const void *inputBuffer, void *outputBuff loopbackContext->minInputOutputDelta = inputOutputDelta; } } - - return loopbackContext->done ? paComplete : paContinue; + + 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 ); + const PaStreamInfo *inputStreamInfo = Pa_GetStreamInfo( inputStream ); + const PaStreamInfo *outputStreamInfo = Pa_GetStreamInfo( outputStream ); - loopbackContext->streamInfoInputLatency = inputStreamInfo ? inputStreamInfo->inputLatency : -1; - loopbackContext->streamInfoOutputLatency = outputStreamInfo ? outputStreamInfo->outputLatency : -1; + 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. @@ -281,47 +281,47 @@ static void CopyStreamInfoToLoopbackContext( LoopbackContext *loopbackContext, P */ 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; - + 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; + 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. @@ -330,25 +330,25 @@ error: 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; + 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. @@ -356,67 +356,67 @@ int PaQa_WaitForStream( LoopbackContext *loopbackContext ) */ 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; - + 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; + return err; } /*******************************************************************/ -/** +/** * Open one audio streams, just for input. * Record background level. * Then close the stream. @@ -424,120 +424,120 @@ 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; - + 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; + 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; + 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; + 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. @@ -545,73 +545,73 @@ 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; - + 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 ); + Pa_CloseStream( outStream ); error2: - Pa_CloseStream( inStream ); + Pa_CloseStream( inStream ); error1: - return err; + 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. @@ -619,669 +619,659 @@ error1: */ 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; - + 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 ); + Pa_CloseStream( stream ); error1: - return err; + 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; + 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]; + 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; + 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; + 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; + 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] ); - } - } + 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 ); - } - } + 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 ); + 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 ) - { + 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 occured. - printf( " - #errs = %d\n", g_testsFailed ); - - PaQa_TeardownLoopbackContext( &loopbackContext ); - if( numBadChannels > 0 ) - { - g_testsFailed += 1; - } - return numBadChannels; - + printf( "%4lu-%4lu | ", + 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; + PaQa_TeardownLoopbackContext( &loopbackContext ); + printf( "\n" ); + g_testsFailed += 1; + return err; } /*******************************************************************/ -static void PaQa_SetDefaultTestParameters( TestParameters *testParamsPtr, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice ) +static void PaQa_MakeTestParameters( TestParameters *testParamsPtr, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice, const UserOptions *userOptions ) { - 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; + 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) ); + 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; + + // 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 iFlags; + int iRate; + int iSize; + int iFormat; + 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)); - + // 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++ ) - { + printf( " Devices: %s => %s\n", outputDeviceInfo->name, inputDeviceInfo->name); + + PaQa_MakeTestParameters( &testParams, inputDevice, outputDevice, userOptions ); + + // Loop though combinations of audio parameters. + for( iFlags=0; iFlags<numFlagSettings; iFlags++ ) + { + int numRuns = 0; + + TestParameters flagTestParams = testParams; + flagTestParams.flags = flagSettings[iFlags]; + printf( "\n************ Mode = %s ************\n", + (( flagTestParams.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 ) + { + 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++ ) - { + // SAMPLE RATE + TestParameters srTestParams = flagTestParams; + srTestParams.sampleRate = sampleRates[iRate]; + srTestParams.maxFrames = (int) (PAQA_TEST_DURATION * srTestParams.sampleRate); + + numBadChannels = PaQa_SingleLoopBackTest( userOptions, &srTestParams ); + totalBadChannels += numBadChannels; + } + printf( "\n" ); + numRuns += 1; + } + + // Loop through various buffer sizes. + if( userOptions->framesPerBuffer < 0 ) + { + 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; + // BUFFER SIZE + TestParameters bsTestParams = flagTestParams; + bsTestParams.framesPerBuffer = framesPerBuffers[iSize]; + + numBadChannels = PaQa_SingleLoopBackTest( userOptions, &bsTestParams ); + totalBadChannels += numBadChannels; + } + 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, &flagTestParams ); + totalBadChannels += numBadChannels; + } + } + + printf("\nTest Sample Formats using Half Duplex IO -----\n" ); + for( iFlags= 0; iFlags<4; iFlags++ ) { + TestParameters flagTestParams = testParams; + flagTestParams.flags = PAQA_FLAG_TWO_STREAMS; // Cycle through combinations of flags. - testParams.streamFlags = 0; - if( iFlags & 1 ) testParams.streamFlags |= paClipOff; - if( iFlags & 2 ) testParams.streamFlags |= paDitherOff; - + flagTestParams.streamFlags = 0; + if( iFlags & 1 ) flagTestParams.streamFlags |= paClipOff; + if( iFlags & 2 ) flagTestParams.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; + TestParameters formatTestParams = flagTestParams; + formatTestParams.inputParameters.sampleFormat = format; + formatTestParams.outputParameters.sampleFormat = format; + printf("Sample format = %d = %s, PaStreamFlags = 0x%02X\n", (int) format, sampleFormatNames[iFormat], (unsigned int) formatTestParams.streamFlags ); + numBadChannels = PaQa_SingleLoopBackTest( userOptions, &formatTestParams); + totalBadChannels += numBadChannels; } } - printf( "\n" ); - printf( "****************************************\n"); - - return totalBadChannels; + 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 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; + 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; + 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. + 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_MakeTestParameters( &testParams, inputDevice, outputDevice, 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; - + 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; + PaQa_TeardownLoopbackContext( &loopbackContext ); + return err; } /*******************************************************************/ @@ -1289,313 +1279,314 @@ error: * If there is a loopback connection then run the analysis. */ static int CheckLoopbackAndScan( UserOptions *userOptions, - PaDeviceIndex iIn, PaDeviceIndex iOut ) + PaDeviceIndex iIn, PaDeviceIndex iOut ) { - int loopbackConnected = PaQa_CheckForLoopBack( userOptions, iIn, iOut ); - if( loopbackConnected > 0 ) - { - PaQa_AnalyzeLoopbackConnection( userOptions, iIn, iOut ); - return 1; - } - return 0; + 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 overriden using the -i and -o command line options. + * The scan can be overridden using the -i and -o command line options. */ static int ScanForLoopback(UserOptions *userOptions) { - PaDeviceIndex iIn,iOut; - int numLoopbacks = 0; + 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; - + 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; + 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; - + 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 int_minus_2147483648 = (-2147483647 - 1); /*"-2147483648" as a signed integer. See PR #814*/ + const int intInput[] = { 2147483647, 2147483647/2, int_minus_2147483648/2, int_minus_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; + 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"); + 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; + 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(); + 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; - } + + 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/3rdparty/portaudio/qa/loopback/src/paqa_tools.c b/3rdparty/portaudio/qa/loopback/src/paqa_tools.c index 97b5058c855..2e44c63645c 100644 --- a/3rdparty/portaudio/qa/loopback/src/paqa_tools.c +++ b/3rdparty/portaudio/qa/loopback/src/paqa_tools.c @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -43,129 +43,129 @@ void PaQa_ListAudioDevices(void) { int i, numDevices; - const PaDeviceInfo *deviceInfo; - numDevices = Pa_GetDeviceCount(); + 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( ", %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; - } - + 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 assymmetric 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 assymmetric conversion to avoid clipping. - int ival = value * ((double) 0x007FFFF0); - ival = ival << 8; - *data++ = ival; - } - } - break; - } - + 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/3rdparty/portaudio/qa/loopback/src/paqa_tools.h b/3rdparty/portaudio/qa/loopback/src/paqa_tools.h index f6b807f2cff..77f6a2519c3 100644 --- a/3rdparty/portaudio/qa/loopback/src/paqa_tools.h +++ b/3rdparty/portaudio/qa/loopback/src/paqa_tools.h @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * 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/3rdparty/portaudio/qa/loopback/src/qa_tools.h b/3rdparty/portaudio/qa/loopback/src/qa_tools.h index 320236e907f..9b2debd3fbe 100755 --- a/3rdparty/portaudio/qa/loopback/src/qa_tools.h +++ b/3rdparty/portaudio/qa/loopback/src/qa_tools.h @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -43,32 +43,32 @@ 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++; + 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++; + 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++; + 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)) \ diff --git a/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.c b/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.c index add57d495e2..82fa859f5ea 100644 --- a/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.c +++ b/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.c @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -56,48 +56,48 @@ */ 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 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 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; - + // 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; - + PaQa_TerminateRecording( &recording); + return 1; + } /*==========================================================================================*/ @@ -107,60 +107,60 @@ error: static int TestMixedMonoTones( void ) { - int i; - int result = 0; + 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; - + 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; - + 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; - + PaQa_TerminateRecording( &recording); + return 1; + } @@ -171,52 +171,52 @@ error: static void MakeRecordingWithAddedFrames( PaQaRecording *recording, PaQaTestTone *testTone, int glitchPosition, int framesToAdd ) { - PaQaSineGenerator generator; + PaQaSineGenerator generator; #define BUFFER_SIZE 512 - float buffer[BUFFER_SIZE]; - + float buffer[BUFFER_SIZE]; + int frameCounter = testTone->startDelay; - - int stride = 1; - // Record some initial silence. - int done = PaQa_WriteSilence( recording, 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; - } + 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; + } } @@ -227,24 +227,24 @@ static void MakeRecordingWithAddedFrames( PaQaRecording *recording, PaQaTestTone static void MakeCleanRecording( PaQaRecording *recording, PaQaTestTone *testTone ) { - PaQaSineGenerator generator; + 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 ); - } + 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 ); + } } /*==========================================================================================*/ @@ -254,22 +254,22 @@ static void MakeCleanRecording( PaQaRecording *recording, PaQaTestTone *testTone 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; - } + 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; + } } /*==========================================================================================*/ @@ -278,54 +278,54 @@ static void MakeRecordingWithPop( PaQaRecording *recording, PaQaTestTone *testTo */ 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 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; - } - + 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 ); + 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; - + + 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; -} + PaQa_TerminateRecording( &recording); + return 1; +} /*==========================================================================================*/ /** @@ -333,34 +333,34 @@ error: */ static int TestDetectPhaseErrors( void ) { - int result; - - result = TestDetectSinglePhaseError( 44100, 200, 477, -1, 0 ); - if( result < 0 ) return result; + 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; + 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; + return 0; } /*==========================================================================================*/ @@ -369,53 +369,53 @@ static int TestDetectPhaseErrors( void ) */ 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 ); - + 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 ); + 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; - + + 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; -} + PaQa_SaveRecordingToWaveFile( &recording, "bad_recording.wav" ); + PaQa_TerminateRecording( &recording); + return 1; +} /*==========================================================================================*/ /** @@ -423,73 +423,73 @@ error: */ 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 ); - + 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 ); + 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; - + + 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; -} + PaQa_SaveRecordingToWaveFile( &recording, "bad_step_original.wav" ); + PaQa_SaveRecordingToWaveFile( &hipassOutput, "bad_step_hipass.wav" ); + PaQa_TerminateRecording( &recording); + PaQa_TerminateRecording( &hipassOutput ); + return 1; +} /*==========================================================================================*/ /** @@ -497,26 +497,26 @@ error: */ 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; + 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; } /*==========================================================================================*/ @@ -525,31 +525,31 @@ static int TestDetectPops( void ) */ static int TestInitialSpike( void ) { - int result; - + 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; + // 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; } @@ -566,28 +566,28 @@ static int TestSavedWave() #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; - } + 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; @@ -600,23 +600,23 @@ error: */ 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 ); - } - + 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 ); + } + } /*==========================================================================================*/ @@ -626,93 +626,93 @@ void PaQa_FillWithSine( PaQaRecording *recording, double sampleRate, double freq */ 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; - + 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 ); + 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( ¬chFilter, freq / sampleRate, 0.5 ); - PaQa_FilterRecording( &original, &filtered, ¬chFilter ); - 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( ¬chFilter, 1.07 * freq / sampleRate, 2.0 ); - PaQa_FilterRecording( &original, &filtered, ¬chFilter ); - - //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; - + 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( ¬chFilter, freq / sampleRate, 0.5 ); + PaQa_FilterRecording( &original, &filtered, ¬chFilter ); + 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( ¬chFilter, 1.07 * freq / sampleRate, 2.0 ); + PaQa_FilterRecording( &original, &filtered, ¬chFilter ); + + //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; - + PaQa_TerminateRecording( &original); + PaQa_TerminateRecording( &filtered ); + return 1; + } /*==========================================================================================*/ /** - */ + */ int PaQa_TestAnalyzer( void ) { - int result; - + int result; + #if TEST_SAVED_WAVE - // Write a simple wave file. - if ((result = TestSavedWave()) != 0) return result; + // 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; + + // 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/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.h b/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.h index 8191b42cb43..bfe073fc697 100644 --- a/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.h +++ b/3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.h @@ -26,13 +26,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * 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/3rdparty/portaudio/qa/loopback/src/write_wav.c b/3rdparty/portaudio/qa/loopback/src/write_wav.c index d948b346ef1..aa5ee2146af 100755 --- a/3rdparty/portaudio/qa/loopback/src/write_wav.c +++ b/3rdparty/portaudio/qa/loopback/src/write_wav.c @@ -25,13 +25,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ @@ -47,32 +47,32 @@ /* 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; + 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; + 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; + 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 */ \ @@ -87,14 +87,14 @@ static void WriteChunkType( unsigned char **addrPtr, unsigned long cktyp ) */ long Audio_WAV_OpenWriter( WAV_Writer *writer, const char *fileName, int frameRate, int samplesPerFrame ) { - unsigned int bytesPerSecond; + unsigned int bytesPerSecond; unsigned char header[ WAV_HEADER_SIZE ]; - unsigned char *addr = header; + unsigned char *addr = header; int numWritten; - + writer->dataSize = 0; writer->dataSizeOffset = 0; - + writer->fid = fopen( fileName, "wb" ); if( writer->fid == NULL ) { @@ -102,35 +102,35 @@ long Audio_WAV_OpenWriter( WAV_Writer *writer, const char *fileName, int frameRa } /* Write RIFF header. */ - WriteChunkType( &addr, RIFF_ID ); + WriteChunkType( &addr, RIFF_ID ); /* Write RIFF size as zero for now. Will patch later. */ - WriteLongLE( &addr, 0 ); + WriteLongLE( &addr, 0 ); /* Write WAVE form ID. */ - WriteChunkType( &addr, WAVE_ID ); + WriteChunkType( &addr, WAVE_ID ); /* Write format chunk based on AudioSample structure. */ - WriteChunkType( &addr, FMT_ID ); + 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 */ + 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 ); + WriteChunkType( &addr, DATA_ID ); /* Save offset so we can patch it later. */ writer->dataSizeOffset = (int) (addr - header); - WriteLongLE( &addr, 0 ); + WriteLongLE( &addr, 0 ); numWritten = fwrite( header, 1, sizeof(header), writer->fid ); if( numWritten != sizeof(header) ) return -1; - return (int) numWritten; + return (int) numWritten; } /********************************************************************************* @@ -138,31 +138,31 @@ long Audio_WAV_OpenWriter( WAV_Writer *writer, const char *fileName, int frameRa * Returns bytes written or negative error code. */ long Audio_WAV_WriteShorts( WAV_Writer *writer, - short *samples, - int numSamples - ) + short *samples, + int numSamples + ) { - unsigned char buffer[2]; + unsigned char buffer[2]; unsigned char *bufferPtr; - int i; - short *p = samples; + int i; + short *p = samples; int numWritten; int bytesWritten; - if( numSamples <= 0 ) - { - return -1; - } + if( numSamples <= 0 ) + { + return -1; + } for( i=0; i<numSamples; i++ ) - { + { bufferPtr = buffer; - WriteShortLE( &bufferPtr, *p++ ); + 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; + return (int) bytesWritten; } /********************************************************************************* @@ -171,7 +171,7 @@ long Audio_WAV_WriteShorts( WAV_Writer *writer, */ long Audio_WAV_CloseWriter( WAV_Writer *writer ) { - unsigned char buffer[4]; + unsigned char buffer[4]; unsigned char *bufferPtr; int numWritten; int riffSize; @@ -212,7 +212,7 @@ int main( void ) #define NUM_SAMPLES (200) short data[NUM_SAMPLES]; short saw = 0; - + for( i=0; i<NUM_SAMPLES; i++ ) { data[i] = saw; diff --git a/3rdparty/portaudio/qa/loopback/src/write_wav.h b/3rdparty/portaudio/qa/loopback/src/write_wav.h index 5a9c5ab9630..3560055de02 100755 --- a/3rdparty/portaudio/qa/loopback/src/write_wav.h +++ b/3rdparty/portaudio/qa/loopback/src/write_wav.h @@ -25,13 +25,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * 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 @@ -65,7 +65,7 @@ extern "C" { #define WAVE_FORMAT_PCM (1) #define WAVE_FORMAT_IMA_ADPCM (0x0011) - + typedef struct WAV_Writer_s { FILE *fid; @@ -86,9 +86,9 @@ long Audio_WAV_OpenWriter( WAV_Writer *writer, const char *fileName, int frameRa * Returns bytes written or negative error code. */ long Audio_WAV_WriteShorts( WAV_Writer *writer, - short *samples, - int numSamples - ); + short *samples, + int numSamples + ); /********************************************************************************* * Close WAV file. diff --git a/3rdparty/portaudio/qa/paqa_devs.c b/3rdparty/portaudio/qa/paqa_devs.c index 721b07f14fc..1a70e842d89 100644 --- a/3rdparty/portaudio/qa/paqa_devs.c +++ b/3rdparty/portaudio/qa/paqa_devs.c @@ -1,15 +1,16 @@ /** @file paqa_devs.c - @ingroup qa_src + @ingroup qa_src @brief Self Testing Quality Assurance app for PortAudio - Try to open each device and run through all the - possible configurations. 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 outputs. - - @author Phil Burk http://www.softsynth.com - - Pieter adapted to V19 API. Test now relies heavily on + 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. */ @@ -41,104 +42,215 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * 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 <stdint.h> #include <stdio.h> +#include <stdlib.h> /* for EXIT_SUCCESS and EXIT_FAILURE */ +#include <string.h> +#define _USE_MATH_DEFINES #include <math.h> #include "portaudio.h" #include "pa_trace.h" +#include "paqa_macros.h" /****************************************** Definitions ***********/ -#define MODE_INPUT (0) -#define MODE_OUTPUT (1) -#define MAX_TEST_CHANNELS 4 +#define RUN_TIME_SECONDS (1.2) +#define BYPASS_TESTS (0) /* If 1 then skip actual tests and just iterate. */ + +#define MODE_INPUT (0) +#define MODE_OUTPUT (1) +#define MAX_TEST_CHANNELS (4) +#define LOWEST_FREQUENCY (300.0) +#define SINE_AMPLITUDE (0.2) +#define MILLIS_PER_SECOND (1000.0) +#define DEFAULT_FRAMES_PER_BUFFER (128) + +#define TEST_LEVEL_QUICK (0) +#define TEST_LEVEL_NORMAL (1) +#define TEST_LEVEL_EXHAUSTIVE (2) + +PAQA_INSTANTIATE_GLOBALS + +typedef struct PaSineOscillator +{ + float phase; + float phaseIncrement; +} PaSineOscillator; +/* Parameters that cover all options for a test. + */ +typedef struct PaQaTestParameters +{ + PaDeviceIndex deviceID; + PaSampleFormat format; + double sampleRate; + double durationSeconds; + double suggestedLatency; + int framesPerBuffer; + int numInputChannels; + int numOutputChannels; + int mode; + int useCallback; + int useNonInterleaved; /* Test paNonInterleaved flag */ +} PaQaTestParameters; + +PaQaTestParameters kDefaultTestParameters = { + 0, /* deviceId */ + paFloat32, + 44100, + RUN_TIME_SECONDS, + 0.020, + DEFAULT_FRAMES_PER_BUFFER, + 0, /* numInputChannels */ + 1, /* numOutputChannels */ + MODE_OUTPUT, + 1, /* useCallback */ + 0, /* useNonInterleaved */ +}; + +/* Runtime data used during the test. */ typedef struct PaQaData { - unsigned long framesLeft; - int numChannels; - int bytesPerSample; - int mode; - short sawPhase; - PaSampleFormat format; -} -PaQaData; + const PaQaTestParameters *parameters; + // Dynamic state. + int bytesPerSample; + volatile unsigned long frameCounter; + volatile unsigned long framesLeft; + unsigned long framesPerBurst; + unsigned long minFramesPerBuffer; + unsigned long maxFramesPerBuffer; + unsigned long framesDuration; + PaSineOscillator sineOscillators[MAX_TEST_CHANNELS]; + void *audioBuffer; +} PaQaData; /****************************************** Prototypes ***********/ -static void TestDevices( int mode ); -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 TestSingleStreamParameters(PaQaTestParameters parameters); 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 void PaQaSetupData(PaQaData *myData, + const PaQaTestParameters *parameters) +{ + memset(myData, 0, sizeof(PaQaData)); + + myData->parameters = parameters; + myData->frameCounter = 0; + myData->framesLeft = (unsigned long) (parameters->sampleRate * parameters->durationSeconds); + + myData->minFramesPerBuffer = UINT32_MAX; + myData->maxFramesPerBuffer = 0; + + for (int channelIndex = 0; channelIndex < MAX_TEST_CHANNELS; channelIndex++) + { + myData->sineOscillators[channelIndex].phase = 0.0f; + myData->sineOscillators[channelIndex].phaseIncrement = + (2.0 * M_PI * LOWEST_FREQUENCY / parameters->sampleRate); + } + + switch( parameters->format ) + { + case paFloat32: + case paInt32: + case paInt24: + myData->bytesPerSample = 4; + break; + /* case paPackedInt24: + myData->bytesPerSample = 3; + break; */ + default: + myData->bytesPerSample = 2; + break; + } + myData->framesPerBurst = (parameters->framesPerBuffer == 0) ? 128 : parameters->framesPerBuffer; + if (parameters->useCallback == 0) { + /* We need our own buffer for blocking IO. */ + int numChannels = (parameters->mode == MODE_OUTPUT) + ? parameters->numOutputChannels + : parameters->numInputChannels; + myData->audioBuffer = malloc(myData->bytesPerSample * numChannels * myData->framesPerBurst); + } +} + +static void PaQaTeardownData(PaQaData *myData, + const PaQaTestParameters *parameters) +{ + (void) parameters; + free(myData->audioBuffer); +} + +static float NextSineSample( PaSineOscillator *sineOscillator ) +{ + float phase = sineOscillator->phase + sineOscillator->phaseIncrement; + if( phase > (float)M_PI ) phase -= (float)(2.0 * M_PI); + sineOscillator->phase = phase; + return sinf(phase) * SINE_AMPLITUDE; +} + +#define SETUP_BUFFERS(_data_type) \ + _data_type *out; \ + int stride; \ + if (parameters->useNonInterleaved) { \ + /* outputData points to an array of pointers to the buffers. */ \ + void **buffers = (void **)outputData; \ + out = (_data_type *)buffers[channelIndex]; \ + stride = 1; \ + } else { \ + out = &((_data_type *) outputData)[channelIndex]; \ + stride = parameters->numOutputChannels; \ + } /*******************************************************************/ /* 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, +static int QaCallback( const void *inputData, + void *outputData, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { - unsigned long i; - short phase; + unsigned long frameIndex; + int channelIndex; + float sample; PaQaData *data = (PaQaData *) userData; - (void) inputBuffer; + const PaQaTestParameters *parameters = data->parameters; + (void) inputData; + + data->minFramesPerBuffer = (framesPerBuffer < data->minFramesPerBuffer) + ? framesPerBuffer : data->minFramesPerBuffer; + data->maxFramesPerBuffer = (framesPerBuffer > data->maxFramesPerBuffer) + ? framesPerBuffer : data->maxFramesPerBuffer; - /* Play simple sawtooth wave. */ - if( data->mode == MODE_OUTPUT ) + /* Play simple sine wave. */ + if( parameters->mode == MODE_OUTPUT ) { - phase = data->sawPhase; - switch( data->format ) + switch( parameters->format ) { case paFloat32: { - float *out = (float *) outputBuffer; - for( i=0; i<framesPerBuffer; i++ ) + for( channelIndex = 0; channelIndex < parameters->numOutputChannels; channelIndex++ ) { - phase += 0x123; - *out++ = (float) (phase * (1.0 / 32768.0)); - if( data->numChannels == 2 ) + SETUP_BUFFERS(float); + for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ ) { - *out++ = (float) (phase * (1.0 / 32768.0)); + sample = NextSineSample( &data->sineOscillators[channelIndex] ); + *out = sample; + out += stride; } } } @@ -146,29 +258,29 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer, case paInt32: { - int *out = (int *) outputBuffer; - for( i=0; i<framesPerBuffer; i++ ) + for( channelIndex = 0; channelIndex < parameters->numOutputChannels; channelIndex++ ) { - phase += 0x123; - *out++ = ((int) phase ) << 16; - if( data->numChannels == 2 ) + SETUP_BUFFERS(int32_t); + for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ ) { - *out++ = ((int) phase ) << 16; + sample = NextSineSample( &data->sineOscillators[channelIndex] ); + *out = ((int32_t)(sample * 8388607)) << 8; + out += stride; } } } break; - + case paInt16: { - short *out = (short *) outputBuffer; - for( i=0; i<framesPerBuffer; i++ ) + for( channelIndex = 0; channelIndex < parameters->numOutputChannels; channelIndex++ ) { - phase += 0x123; - *out++ = phase; - if( data->numChannels == 2 ) + SETUP_BUFFERS(int16_t); + for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ ) { - *out++ = phase; + sample = NextSineSample( &data->sineOscillators[channelIndex] ); + *out = (int16_t)(sample * 32767); + out += stride; } } } @@ -176,196 +288,556 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer, default: { - unsigned char *out = (unsigned char *) outputBuffer; - unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; - for( i=0; i<numBytes; i++ ) - { - *out++ = 0; - } + unsigned char *out = (unsigned char *) outputData; + unsigned long numBytes = framesPerBuffer * parameters->numOutputChannels * data->bytesPerSample; + memset(out, 0, numBytes); } break; } - data->sawPhase = phase; } + + data->frameCounter += framesPerBuffer; + /* Are we through yet? */ if( data->framesLeft > framesPerBuffer ) { PaUtil_AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft ); data->framesLeft -= framesPerBuffer; - return 0; + return paContinue; } else { PaUtil_AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft ); data->framesLeft = 0; - return 1; + return paComplete; + } +} + +static PaError CheckBlockingIO(PaStream *stream, + PaQaData *data, + int millis) { + PaError result = paNoError; + double elapsedTime = 0.0; + double millisPerBurst = MILLIS_PER_SECOND * data->framesPerBurst / data->parameters->sampleRate; + while (elapsedTime < millis) { + int callbackResult; + if (data->parameters->mode == MODE_OUTPUT) { + callbackResult = QaCallback(NULL /*inputBuffer */, + data->audioBuffer, + data->framesPerBurst, + NULL /* timeInfo */, // TODO + 0, // stream flags + data); + if (callbackResult == 0) { + result = Pa_WriteStream(stream, data->audioBuffer, data->framesPerBurst); + ASSERT_EQ(paNoError, result); + } + } else if (data->parameters->mode == MODE_INPUT) { + result = Pa_ReadStream(stream, data->audioBuffer, data->framesPerBurst); + ASSERT_EQ(paNoError, result); + callbackResult = QaCallback(data->audioBuffer, + NULL /*outputBuffer */, + data->framesPerBurst, + NULL /* timeInfo */, // TODO + 0, // stream flags + data); + } + elapsedTime += millisPerBurst; } +error: + return result; +} + +static void CheckDefaultCallbackRun(PaStream *stream, + PaQaData *data) { + PaError result = paNoError; + PaTime oldStreamTimeMillis = 0.0; + PaTime startStreamTimeMillis = 0.0; + unsigned long oldFramesLeft = INT32_MAX; + + oldStreamTimeMillis = Pa_GetStreamTime(stream) * MILLIS_PER_SECOND; + + ASSERT_EQ(0, Pa_IsStreamActive(stream)); + ASSERT_EQ(1, Pa_IsStreamStopped(stream)); + + ASSERT_EQ(paNoError, result = Pa_StartStream( stream )); + startStreamTimeMillis = Pa_GetStreamTime(stream) * MILLIS_PER_SECOND; + + ASSERT_EQ(1, Pa_IsStreamActive(stream)); + ASSERT_EQ(0, Pa_IsStreamStopped(stream)); + + /* Sleep long enough for the stream callback to have stopped itself. */ + while ((oldStreamTimeMillis - startStreamTimeMillis) < ((RUN_TIME_SECONDS + 0.5) * MILLIS_PER_SECOND) + && (data->framesLeft > 0)) + { + if (data->parameters->useCallback) { + Pa_Sleep(200); + } else { + result = CheckBlockingIO(stream, + data, + 200); + ASSERT_EQ(paNoError, result); + } + + PaTime newStreamTime = Pa_GetStreamTime(stream) * MILLIS_PER_SECOND; + //printf("oldStreamTime = %9.6f, newStreamTime = %9.6f\n", oldStreamTime, newStreamTime ); /**/ + ASSERT_LE(oldStreamTimeMillis, newStreamTime); + + /* Check to make sure callback is decrementing framesLeft. */ + unsigned long newFramesLeft = data->framesLeft; + //printf("oldFrames = %lu, newFrames = %lu\n", oldFramesLeft, newFramesLeft ); + ASSERT_GE(oldFramesLeft, newFramesLeft); + + oldStreamTimeMillis = newStreamTime; + oldFramesLeft = newFramesLeft; + } + + ASSERT_EQ(0, data->framesLeft); + ASSERT_LE((1 * data->parameters->sampleRate), data->frameCounter); + + if (data->parameters->framesPerBuffer > 0) { + ASSERT_EQ(data->parameters->framesPerBuffer, data->minFramesPerBuffer); + ASSERT_EQ(data->parameters->framesPerBuffer, data->maxFramesPerBuffer); + } else { + ASSERT_GT(data->minFramesPerBuffer, 0); + ASSERT_LT(data->maxFramesPerBuffer, data->parameters->sampleRate); + } + + ASSERT_EQ(data->parameters->useCallback ? 0 : 1, Pa_IsStreamActive(stream)); + ASSERT_EQ(0, Pa_IsStreamStopped(stream)); + + ASSERT_EQ(paNoError, result = Pa_StopStream( stream )); + + ASSERT_EQ(0, Pa_IsStreamActive(stream)); + ASSERT_EQ(1, Pa_IsStreamStopped(stream)); + + ASSERT_EQ(paNoError, result = Pa_CloseStream( stream )); + return; + +error: + printf("result = %d = for %s\n", result, Pa_GetErrorText(result)); + Pa_CloseStream(stream); + return; } /*******************************************************************/ -int main(void); -int main(void) +static int TestSingleStreamParameters(PaQaTestParameters testParameters) { - PaError result; - EXPECT( ((result=Pa_Initialize()) == 0) ); - printf("Test OUTPUT ---------------\n"); - TestDevices( MODE_OUTPUT ); - printf("Test INPUT ---------------\n"); - TestDevices( MODE_INPUT ); + PaStreamParameters inputParameters, outputParameters, *ipp, *opp; + PaStream *stream = NULL; + PaQaData myData; + int numChannels = 0; + + if( testParameters.mode == MODE_INPUT ) + { + opp = NULL; + numChannels = testParameters.numInputChannels; + inputParameters.device = testParameters.deviceID; + inputParameters.channelCount = testParameters.numInputChannels; + inputParameters.sampleFormat = testParameters.format + | (testParameters.useNonInterleaved ? paNonInterleaved : 0); + inputParameters.suggestedLatency = testParameters.suggestedLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + ipp = &inputParameters; + } + else if( testParameters.mode == MODE_OUTPUT ) + { + ipp = NULL; + numChannels = testParameters.numOutputChannels; + outputParameters.device = testParameters.deviceID; + outputParameters.channelCount = testParameters.numOutputChannels; + outputParameters.sampleFormat = testParameters.format + | (testParameters.useNonInterleaved ? paNonInterleaved : 0); + outputParameters.suggestedLatency = testParameters.suggestedLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + opp = &outputParameters; + } + + printf("------ Test: %s, device = %d" + ", #ch = %d" + ", rate = %5g" + ", format = %lu" + ", %s, %s\n", + ( testParameters.mode == MODE_INPUT ) ? "INPUT" : "OUTPUT", + testParameters.deviceID, + numChannels, + testParameters.sampleRate, + (unsigned long)testParameters.format, + testParameters.useCallback ? "CALLBACK" : "BLOCKING", + testParameters.useNonInterleaved ? "NON-INT" : "INTER" + ); + + if (BYPASS_TESTS) return 0; + + /* Setup data for callback thread. */ + PaQaSetupData(&myData, &testParameters); + + if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, testParameters.sampleRate )) + { + PaError resultOpen = Pa_OpenStream( &stream, + ipp, + opp, + testParameters.sampleRate, + testParameters.framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + testParameters.useCallback ? QaCallback : NULL, + &myData + ); + + if (resultOpen != paNoError) { + printf("Pa_OpenStream() returned = %d = for %s\n", + resultOpen, Pa_GetErrorText(resultOpen)); + } + ASSERT_EQ(paNoError, resultOpen); + ASSERT_TRUE(stream != NULL); + + { + const PaStreamInfo *streamInfo = Pa_GetStreamInfo(stream); + ASSERT_EQ((int)(testParameters.sampleRate), (int)(streamInfo->sampleRate)); + if (testParameters.mode == MODE_INPUT) { + ASSERT_EQ(0, (int)(streamInfo->outputLatency * 1000)); + } else { + ASSERT_EQ(0, (int)(streamInfo->inputLatency * 1000)); + } + } + CheckDefaultCallbackRun(stream, &myData); + + } else { + printf(" Parameters NOT supported.\n"); + } + PaQaTeardownData(&myData, &testParameters); + return 0; + error: - Pa_Terminate(); - printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); - return (gNumFailed > 0) ? 1 : 0; + if( stream != NULL ) Pa_CloseStream( stream ); + PaQaTeardownData(&myData, &testParameters); + return -1; +} + + +static void RunQuickTest() +{ + PaQaTestParameters parameters = kDefaultTestParameters; + +#if 1 + printf("\n=========== INPUT ==============\n"); + parameters.mode = MODE_INPUT; + parameters.deviceID = Pa_GetDefaultInputDevice(); + parameters.format = paFloat32; + + parameters.sampleRate = 44100; + parameters.numInputChannels = 1; + TestSingleStreamParameters(parameters); + parameters.sampleRate = 22050; + TestSingleStreamParameters(parameters); + + parameters.sampleRate = 44100; + parameters.numInputChannels = 2; + TestSingleStreamParameters(parameters); + + parameters.useCallback = 0; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.useNonInterleaved = 1; + TestSingleStreamParameters(parameters); /* Blocking, NonInterleaved */ + parameters.useCallback = 1; + TestSingleStreamParameters(parameters); /* NonInterleaved */ + parameters.useCallback = 1; +#endif + + printf("\n=========== OUTPUT =============\n"); + parameters = kDefaultTestParameters; + parameters.mode = MODE_OUTPUT; + parameters.deviceID = Pa_GetDefaultOutputDevice(); + parameters.sampleRate = 48000; + parameters.numOutputChannels = 1; + parameters.format = paFloat32; + parameters.useCallback = 0; + TestSingleStreamParameters(parameters); + + /* Interleaved */ + parameters = kDefaultTestParameters; + parameters.deviceID = Pa_GetDefaultOutputDevice(); + parameters.useNonInterleaved = 0; + parameters.numOutputChannels = 1; + parameters.useCallback = 1; + parameters.format = paFloat32; + TestSingleStreamParameters(parameters); + parameters.useCallback = 0; + parameters.format = paFloat32; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.useCallback = 1; + + parameters.sampleRate = 44100; + parameters.numOutputChannels = 2; + parameters.format = paFloat32; + TestSingleStreamParameters(parameters); + + parameters.sampleRate = 22050; + parameters.numOutputChannels = 2; + parameters.format = paInt16; + TestSingleStreamParameters(parameters); + + /* Non-Interleaved */ + parameters = kDefaultTestParameters; + parameters.deviceID = Pa_GetDefaultOutputDevice(); + parameters.useNonInterleaved = 1; + parameters.numOutputChannels = 2; + parameters.format = paFloat32; + parameters.useCallback = 0; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.useCallback = 1; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.format = paInt16; + TestSingleStreamParameters(parameters); + parameters.format = paInt32; + TestSingleStreamParameters(parameters); +} + +static const double constStandardSampleRates_[] = { + 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. */ + +static const PaSampleFormat constFormatsToTest_[] = { + paFloat32, paInt32, paInt16, 0 +}; /* Zero terminated list. */ + +/** + * Iterate through each option with other options set to default. + */ +static void TestNormal( int mode, int allDevices ) +{ + PaQaTestParameters parameters = kDefaultTestParameters; + int id, jc, i; + int maxChannels; + int isDefault; + const PaDeviceInfo *pdi; + int numDevices = Pa_GetDeviceCount(); + parameters.mode = mode; + + for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */ + { + parameters.deviceID = id; + + 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 (maxChannels == 0) continue; // skip this device, wrong direction + + if (!allDevices && !isDefault) continue; // skip this device + + printf("\n===========================================================\n"); + printf(" Device = %s\n", pdi->name ); + printf("===========================================================\n"); + for( jc=1; jc<=maxChannels; jc++ ) + { + if (mode == MODE_INPUT) { + parameters.numInputChannels = jc; + } else { + parameters.numOutputChannels = jc; + } + TestSingleStreamParameters(parameters); + } + + /* Try each standard sample rate. */ + for( i=0; constStandardSampleRates_[i] > 0; i++ ) + { + parameters.sampleRate = constStandardSampleRates_[i]; + TestSingleStreamParameters(parameters); + } + parameters.sampleRate = pdi->defaultSampleRate; + + if (mode == MODE_INPUT) { + parameters.suggestedLatency = pdi->defaultHighInputLatency; + TestSingleStreamParameters(parameters); + parameters.suggestedLatency = pdi->defaultLowInputLatency; + TestSingleStreamParameters(parameters); + } else { + parameters.suggestedLatency = pdi->defaultHighOutputLatency; + TestSingleStreamParameters(parameters); + parameters.suggestedLatency = pdi->defaultLowOutputLatency; + TestSingleStreamParameters(parameters); + } + + for (int callback = 0; callback < 2; callback++) { + parameters.useCallback = callback; + for (int nonInterleaved = 0; nonInterleaved < 2; nonInterleaved++) { + parameters.useNonInterleaved = nonInterleaved; + TestSingleStreamParameters(parameters); + } + } + parameters.useCallback = 1; + parameters.useNonInterleaved = 0; + + for (int jf = 0; constFormatsToTest_[jf] > 0; jf++) { + parameters.format = constFormatsToTest_[jf]; + TestSingleStreamParameters(parameters); + } + } } /******************************************************************* -* Try each output device, through its full range of capabilities. */ -static void TestDevices( int mode ) +* Test each output device, through its full range of capabilities. */ +static void TestExhaustive( int mode, int allDevices ) { + PaQaTestParameters parameters = kDefaultTestParameters; 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(); + parameters.mode = mode; + for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */ { + parameters.deviceID = id; + pdi = Pa_GetDeviceInfo( id ); - /* Try 1 to maxChannels on each device. */ - maxChannels = (( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels); + + 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 (maxChannels == 0) continue; // skip this device, wrong direction + + if (!allDevices && !isDefault) continue; // skip this device + + printf("\n===========================================================\n"); + printf(" Device = %s\n", pdi->name ); + printf("===========================================================\n"); for( jc=1; jc<=maxChannels; jc++ ) { - printf("\n========================================================================\n"); - printf(" Device = %s\n", pdi->name ); - printf("========================================================================\n"); + printf("\n---------------------- NumChannels = %d ------------\n", jc ); + if (mode == MODE_INPUT) { + parameters.numInputChannels = jc; + } else { + parameters.numOutputChannels = jc; + } /* Try each standard sample rate. */ - for( i=0; standardSampleRates[i] > 0; i++ ) + for( i=0; constStandardSampleRates_[i] > 0; i++ ) { - TestFormats( mode, (PaDeviceIndex)id, standardSampleRates[i], jc ); + parameters.sampleRate = constStandardSampleRates_[i]; + for (int callback = 0; callback < 2; callback++) { + parameters.useCallback = callback; + for (int nonInterleaved = 0; nonInterleaved < 2; nonInterleaved++) { + parameters.useNonInterleaved = nonInterleaved; + for (int jf = 0; constFormatsToTest_[jf] > 0; jf++) { + parameters.format = constFormatsToTest_[jf]; + TestSingleStreamParameters(parameters); + } + } + } } } } } /*******************************************************************/ -static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, - int numChannels ) +static void usage( const char *name ) { - TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); - TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); - TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); - /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */ + printf("%s [-a] {-tN}\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(" -t - Test level, 0=Quick, 1=Normal, 2=Exhaustive\n"); + printf(" -? - Help\n"); } /*******************************************************************/ -static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate, - int numChannels, PaSampleFormat format ) +int main( int argc, char **argv ); +int main( int argc, char **argv ) { - 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; - } + int i; + PaError result; + int allDevices = 0; + int testOutput = 1; + int testInput = 1; + int testLevel = TEST_LEVEL_NORMAL; + char *executableName = argv[0]; - 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 + /* Parse command line parameters. */ + i = 1; + while( i<argc ) { - 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; + 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; + case 't': + testLevel = atoi(&arg[2]); + 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; } - 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 ) + + ASSERT_EQ(2, sizeof(short)); /* The callback assumes we have 16-bit shorts. */ + ASSERT_EQ(4, sizeof(int)); /* The callback assumes we have 32-bit ints. */ + ASSERT_EQ(paNoError, (result=Pa_Initialize())); + + if (testLevel == TEST_LEVEL_QUICK) { + printf("\n---- Quick Test ---------------\n"); + RunQuickTest(); + } else { + if( testInput ) + { + printf("\n---- Test INPUT ---------------\n"); + if (testLevel == TEST_LEVEL_NORMAL) { + TestNormal( MODE_INPUT, allDevices ); + } else { + TestExhaustive( MODE_INPUT, allDevices ); + } + } + if( testOutput ) { - 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; + printf("\n---- Test OUTPUT ---------------\n"); + if (testLevel == TEST_LEVEL_NORMAL) { + TestNormal( MODE_OUTPUT, allDevices ); + } else { + TestExhaustive( MODE_OUTPUT, allDevices ); + } } } - return 0; + error: - if( stream != NULL ) Pa_CloseStream( stream ); - return -1; + ASSERT_EQ(paNoError, Pa_Terminate()); + + PAQA_PRINT_RESULT; + return PAQA_EXIT_RESULT; } diff --git a/3rdparty/portaudio/qa/paqa_errs.c b/3rdparty/portaudio/qa/paqa_errs.c index 8c1d06d96ed..3c66f2c5813 100644 --- a/3rdparty/portaudio/qa/paqa_errs.c +++ b/3rdparty/portaudio/qa/paqa_errs.c @@ -1,8 +1,8 @@ /** @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 + @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. */ /* @@ -33,20 +33,23 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * 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 <stdint.h> #include <stdio.h> +#include <stdlib.h> /* for EXIT_SUCCESS and EXIT_FAILURE */ #include <math.h> #include "portaudio.h" +#include "paqa_macros.h" /*--------- Definitions ---------*/ #define MODE_INPUT (0) @@ -54,6 +57,8 @@ #define FRAMES_PER_BUFFER (64) #define SAMPLE_RATE (44100.0) +PAQA_INSTANTIATE_GLOBALS + typedef struct PaQaData { unsigned long framesLeft; @@ -63,38 +68,6 @@ typedef struct PaQaData } 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 @@ -103,14 +76,14 @@ static int gNumFailed = 0; static int QaCallback( const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, + 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. */ @@ -174,7 +147,7 @@ static int TestBadOpens( void ) PaStreamParameters ipp, opp; const PaDeviceInfo* info = NULL; - + /* Setup data for synthesis thread. */ myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */ myData.numChannels = 1; @@ -222,7 +195,7 @@ static int TestBadOpens( void ) 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. */ + 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)); @@ -274,7 +247,7 @@ static int TestBadOpens( void ) 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; @@ -286,7 +259,7 @@ static int TestBadOpens( void ) /*----------------------------- 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; @@ -366,7 +339,7 @@ static int TestBadActions( void ) 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)); @@ -392,12 +365,15 @@ int main(void); int main(void) { PaError result; - - EXPECT(((result = Pa_Initialize()) == paNoError)); + + printf("-----------------------------\n"); + printf("paqa_errs - PortAudio QA test\n"); + ASSERT_EQ(paNoError, (result = Pa_Initialize())); TestBadOpens(); TestBadActions(); error: Pa_Terminate(); - printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed); - return 0; + + PAQA_PRINT_RESULT; + return PAQA_EXIT_RESULT; } diff --git a/3rdparty/portaudio/qa/paqa_latency.c b/3rdparty/portaudio/qa/paqa_latency.c index 389c065687b..9f468bf53ac 100644 --- a/3rdparty/portaudio/qa/paqa_latency.c +++ b/3rdparty/portaudio/qa/paqa_latency.c @@ -1,7 +1,7 @@ /** @file paqa_latency.c - @ingroup qa_src - @brief Test latency estimates. - @author Ross Bencina <rossb@audiomulch.com> + @ingroup qa_src + @brief Test latency estimates. + @author Ross Bencina <rossb@audiomulch.com> @author Phil Burk <philburk@softsynth.com> */ /* @@ -32,13 +32,13 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * 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 + * 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> @@ -61,8 +61,8 @@ typedef struct int left_phase; int right_phase; char message[20]; - int minFramesPerBuffer; - int maxFramesPerBuffer; + unsigned long minFramesPerBuffer; + unsigned long maxFramesPerBuffer; int callbackCount; PaTime minDeltaDacTime; PaTime maxDeltaDacTime; @@ -91,7 +91,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer, (void) timeInfo; /* Prevent unused variable warnings. */ (void) statusFlags; (void) inputBuffer; - + if( data->minFramesPerBuffer > framesPerBuffer ) { data->minFramesPerBuffer = framesPerBuffer; @@ -100,7 +100,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer, { data->maxFramesPerBuffer = framesPerBuffer; } - + /* Measure min and max output time stamp delta. */ if( data->callbackCount > 0 ) { @@ -115,7 +115,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer, } } data->previousTimeInfo = *timeInfo; - + for( i=0; i<framesPerBuffer; i++ ) { *out++ = data->sine[data->left_phase]; /* left */ @@ -125,12 +125,12 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer, 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, +PaError paqaCheckLatency( PaStreamParameters *outputParamsPtr, paTestData *dataPtr, double sampleRate, unsigned long framesPerBuffer ) { PaError err; @@ -142,7 +142,7 @@ PaError paqaCheckLatency( PaStreamParameters *outputParamsPtr, 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" ); @@ -159,7 +159,7 @@ PaError paqaCheckLatency( PaStreamParameters *outputParamsPtr, 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 ); @@ -169,9 +169,9 @@ PaError paqaCheckLatency( PaStreamParameters *outputParamsPtr, 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(" minFramesPerBuffer = %4lu\n", dataPtr->minFramesPerBuffer ); + printf(" maxFramesPerBuffer = %4lu\n", dataPtr->maxFramesPerBuffer ); printf(" minDeltaDacTime = %f\n", dataPtr->minDeltaDacTime ); printf(" maxDeltaDacTime = %f\n", dataPtr->maxDeltaDacTime ); @@ -181,7 +181,7 @@ PaError paqaCheckLatency( PaStreamParameters *outputParamsPtr, err = Pa_CloseStream( stream ); Pa_Sleep( 1 * 1000 ); - + printf("-------------------------------------\n"); return err; error2: @@ -245,26 +245,26 @@ static int paqaCheckMultipleSuggested( PaDeviceIndex deviceIndex, int isInput ) 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), @@ -275,11 +275,11 @@ static int paqaCheckMultipleSuggested( PaDeviceIndex deviceIndex, int isInput ) paqaNoopCallback, NULL ); if( err != paNoError ) goto error; - + streamInfo = Pa_GetStreamInfo( stream ); - + err = Pa_CloseStream( stream ); - + if( isInput ) { finalLatency = streamInfo->inputLatency; @@ -317,7 +317,7 @@ static int paqaVerifySuggestedLatency( void ) int result = 0; const PaDeviceInfo *pdi; int numDevices = Pa_GetDeviceCount(); - + printf("\n ------------------------ paqaVerifySuggestedLatency\n"); for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */ { @@ -349,7 +349,7 @@ 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. */ { @@ -390,7 +390,7 @@ int main(void) int i; int framesPerBuffer; double sampleRate = SAMPLE_RATE; - + printf("\nPortAudio QA: investigate output latency.\n"); /* initialise sinusoidal wavetable */ @@ -399,19 +399,19 @@ int main(void) 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; + fprintf(stderr,"Error: No default output device.\n"); + goto error; } printf("\n\nNow running Audio Output Tests...\n"); @@ -435,44 +435,44 @@ int main(void) 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" ); diff --git a/3rdparty/portaudio/qa/paqa_macros.h b/3rdparty/portaudio/qa/paqa_macros.h new file mode 100644 index 00000000000..5de07585b3e --- /dev/null +++ b/3rdparty/portaudio/qa/paqa_macros.h @@ -0,0 +1,71 @@ + +#ifndef PORTAUDIO_QA_PAQA_MACROS_H +#define PORTAUDIO_QA_PAQA_MACROS_H + +extern int paQaNumPassed; +extern int paQaNumFailed; + +/* You must use this macro exactly once in each test program. */ +#define PAQA_INSTANTIATE_GLOBALS\ + int paQaNumPassed = 0;\ + int paQaNumFailed = 0; + +/*------------------- Macros ------------------------------*/ +/* Print ERROR if it fails. Tally success or failure. Odd */ +/* do-while wrapper seems to be needed for some compilers. */ +#define ASSERT_TRUE(_exp) \ + do \ + { \ + if (_exp) {\ + paQaNumPassed++; \ + } \ + else { \ + printf("ERROR at %s:%d, (%s) not true\n", \ + __FILE__, __LINE__, #_exp ); \ + paQaNumFailed++; \ + goto error; \ + } \ + } while(0) + +#define ASSERT_AB(_a, _b, _op, _opn) \ + do \ + { \ + int mA = (int)(_a); \ + int mB = (int)(_b); \ + if (mA _op mB) {\ + paQaNumPassed++; \ + } \ + else { \ + printf("ERROR at %s:%d, (%s) %s (%s), %d %s %d\n", \ + __FILE__, __LINE__, #_a, #_opn, #_b, mA, #_opn, mB ); \ + paQaNumFailed++; \ + goto error; \ + } \ + } while(0) + +#define ASSERT_EQ(_a, _b) ASSERT_AB(_a, _b, ==, !=) +#define ASSERT_NE(_a, _b) ASSERT_AB(_a, _b, !=, ==) +#define ASSERT_GT(_a, _b) ASSERT_AB(_a, _b, >, <=) +#define ASSERT_GE(_a, _b) ASSERT_AB(_a, _b, >=, <) +#define ASSERT_LT(_a, _b) ASSERT_AB(_a, _b, <, >=) +#define ASSERT_LE(_a, _b) ASSERT_AB(_a, _b, <=, >) + +#define HOPEFOR(_exp) \ + do \ + { \ + if ((_exp)) {\ + paQaNumPassed++; \ + } \ + else { \ + printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \ + paQaNumFailed++; \ + } \ + } while(0) + +#define PAQA_PRINT_RESULT \ + printf("QA Report: %d passed, %d failed.\n", paQaNumPassed, paQaNumFailed ) + +#define PAQA_EXIT_RESULT \ + (((paQaNumFailed > 0) || (paQaNumPassed == 0)) ? EXIT_FAILURE : EXIT_SUCCESS) + +#endif /* PORTAUDIO_QA_PAQA_MACROS_H */ |