diff options
Diffstat (limited to '3rdparty/portaudio/qa/loopback')
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/CMakeLists.txt | 19 | ||||
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/src/audio_analyzer.c | 901 | ||||
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/src/audio_analyzer.h | 80 | ||||
-rwxr-xr-x | 3rdparty/portaudio/qa/loopback/src/biquad_filter.c | 147 | ||||
-rwxr-xr-x | 3rdparty/portaudio/qa/loopback/src/biquad_filter.h | 24 | ||||
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/src/paqa.c | 2509 | ||||
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/src/paqa_tools.c | 222 | ||||
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/src/paqa_tools.h | 6 | ||||
-rwxr-xr-x | 3rdparty/portaudio/qa/loopback/src/qa_tools.h | 48 | ||||
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.c | 982 | ||||
-rw-r--r-- | 3rdparty/portaudio/qa/loopback/src/test_audio_analyzer.h | 6 | ||||
-rwxr-xr-x | 3rdparty/portaudio/qa/loopback/src/write_wav.c | 104 | ||||
-rwxr-xr-x | 3rdparty/portaudio/qa/loopback/src/write_wav.h | 14 |
13 files changed, 2536 insertions, 2526 deletions
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. |