diff options
| author | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
|---|---|---|
| committer | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
| commit | d53fa8a169832563c62262078b8d2ffe5cab8473 (patch) | |
| tree | b911d06d357d009c976709780f10e92ce915228a /test/analysis | |
first
Diffstat (limited to 'test/analysis')
| -rw-r--r-- | test/analysis/AnalysisClipping.c | 25 | ||||
| -rw-r--r-- | test/analysis/AnalysisClipping.h | 3 | ||||
| -rw-r--r-- | test/analysis/AnalysisClippingTest.c | 37 | ||||
| -rw-r--r-- | test/analysis/AnalysisDistortion.c | 33 | ||||
| -rw-r--r-- | test/analysis/AnalysisDistortion.h | 3 | ||||
| -rw-r--r-- | test/analysis/AnalysisDistortionTest.c | 37 | ||||
| -rw-r--r-- | test/analysis/AnalysisSilence.c | 25 | ||||
| -rw-r--r-- | test/analysis/AnalysisSilence.h | 3 | ||||
| -rw-r--r-- | test/analysis/AnalysisSilenceTest.c | 57 | ||||
| -rw-r--r-- | test/analysis/AnalyzeFile.c | 123 | ||||
| -rw-r--r-- | test/analysis/AnalyzeFile.h | 37 |
11 files changed, 383 insertions, 0 deletions
diff --git a/test/analysis/AnalysisClipping.c b/test/analysis/AnalysisClipping.c new file mode 100644 index 0000000..55229ae --- /dev/null +++ b/test/analysis/AnalysisClipping.c @@ -0,0 +1,25 @@ +#include <math.h> +#include "AnalysisClipping.h" + +boolByte analysisClipping(const SampleBuffer sampleBuffer, AnalysisFunctionData data) +{ + for (ChannelCount i = 0; i < sampleBuffer->numChannels; i++) { + for (SampleCount j = 0; j < sampleBuffer->blocksize; j++) { + if (fabs(sampleBuffer->samples[i][j]) >= 1.0f) { + if (data->consecutiveFailCounter > data->failTolerance) { + data->failedChannel = i; + data->failedSample = j; + return false; + } else { + data->consecutiveFailCounter++; + } + } else { + if (data->consecutiveFailCounter > 0) { + data->consecutiveFailCounter--; + } + } + } + } + + return true; +} diff --git a/test/analysis/AnalysisClipping.h b/test/analysis/AnalysisClipping.h new file mode 100644 index 0000000..6dc56ef --- /dev/null +++ b/test/analysis/AnalysisClipping.h @@ -0,0 +1,3 @@ +#include "AnalyzeFile.h" + +boolByte analysisClipping(const SampleBuffer sampleBuffer, AnalysisFunctionData data); diff --git a/test/analysis/AnalysisClippingTest.c b/test/analysis/AnalysisClippingTest.c new file mode 100644 index 0000000..bd062a3 --- /dev/null +++ b/test/analysis/AnalysisClippingTest.c @@ -0,0 +1,37 @@ +#include "unit/TestRunner.h" +#include "AnalysisClipping.h" + +static int _testAnalysisClipping(void) +{ + SampleBuffer s = newSampleBuffer(1, 128); + AnalysisFunctionData d = newAnalysisFunctionData(); + unsigned long i; + + for (i = 0; i < s->blocksize; i++) { + s->samples[0][i] = 1.0f; + } + + assertFalse(analysisClipping(s, d)); + freeAnalysisFunctionData(d); + freeSampleBuffer(s); + return 0; +} + +static int _testAnalysisNotClipping(void) +{ + SampleBuffer s = newSampleBuffer(1, 8); + AnalysisFunctionData d = newAnalysisFunctionData(); + assert(analysisClipping(s, d)); + freeAnalysisFunctionData(d); + freeSampleBuffer(s); + return 0; +} + +TestSuite addAnalysisClippingTests(void); +TestSuite addAnalysisClippingTests(void) +{ + TestSuite testSuite = newTestSuite("AnalysisClipping", NULL, NULL); + addTest(testSuite, "AnalysisClipping", _testAnalysisClipping); + addTest(testSuite, "AnalysisNotClipping", _testAnalysisNotClipping); + return testSuite; +} diff --git a/test/analysis/AnalysisDistortion.c b/test/analysis/AnalysisDistortion.c new file mode 100644 index 0000000..27b8492 --- /dev/null +++ b/test/analysis/AnalysisDistortion.c @@ -0,0 +1,33 @@ +#include <stdlib.h> +#include "AnalysisDistortion.h" + +// If two samples differ by more than this amount, then we call it distortion +static const Sample kAnalysisDistortionTolerance = 0.5f; + +boolByte analysisDistortion(const SampleBuffer sampleBuffer, AnalysisFunctionData data) +{ + Sample difference; + + for (ChannelCount channelIndex = 0; channelIndex < sampleBuffer->numChannels; channelIndex++) { + for (SampleCount sampleIndex = 0; sampleIndex < sampleBuffer->blocksize; sampleIndex++) { + if (sampleBuffer->samples[channelIndex][sampleIndex] > data->lastSample[channelIndex]) { + difference = sampleBuffer->samples[channelIndex][sampleIndex] - data->lastSample[channelIndex]; + } else { + difference = data->lastSample[channelIndex] - sampleBuffer->samples[channelIndex][sampleIndex]; + } + + if (difference >= kAnalysisDistortionTolerance) { + // In this test, we don't care about the consecutive sample count. That is because + // we also want to detect harsh clicks which occur by a jump in the amplitude, which + // is a common error in many plugins. + data->failedChannel = channelIndex; + data->failedSample = sampleIndex; + return false; + } + + data->lastSample[channelIndex] = sampleBuffer->samples[channelIndex][sampleIndex]; + } + } + + return true; +} diff --git a/test/analysis/AnalysisDistortion.h b/test/analysis/AnalysisDistortion.h new file mode 100644 index 0000000..a517777 --- /dev/null +++ b/test/analysis/AnalysisDistortion.h @@ -0,0 +1,3 @@ +#include "AnalyzeFile.h" + +boolByte analysisDistortion(const SampleBuffer sampleBuffer, AnalysisFunctionData data); diff --git a/test/analysis/AnalysisDistortionTest.c b/test/analysis/AnalysisDistortionTest.c new file mode 100644 index 0000000..cb9441c --- /dev/null +++ b/test/analysis/AnalysisDistortionTest.c @@ -0,0 +1,37 @@ +#include "AnalysisDistortion.h" +#include "unit/TestRunner.h" + +static int _testAnalysisDistortion(void) +{ + SampleBuffer s = newSampleBuffer(1, 8); + AnalysisFunctionData d = newAnalysisFunctionData(); + unsigned int i; + + for (i = 0; i < s->blocksize; i++) { + s->samples[0][i] = 0.9f * (i % 2 ? 1.0f : -1.0f); + } + + assertFalse(analysisDistortion(s, d)); + freeAnalysisFunctionData(d); + freeSampleBuffer(s); + return 0; +} + +static int _testAnalysisNotDistortion(void) +{ + SampleBuffer s = newSampleBuffer(1, 8); + AnalysisFunctionData d = newAnalysisFunctionData(); + assert(analysisDistortion(s, d)); + freeAnalysisFunctionData(d); + freeSampleBuffer(s); + return 0; +} + +TestSuite addAnalysisDistortionTests(void); +TestSuite addAnalysisDistortionTests(void) +{ + TestSuite testSuite = newTestSuite("AnalysisDistortion", NULL, NULL); + addTest(testSuite, "AnalysisDistortion", _testAnalysisDistortion); + addTest(testSuite, "AnalysisNotDistortion", _testAnalysisNotDistortion); + return testSuite; +} diff --git a/test/analysis/AnalysisSilence.c b/test/analysis/AnalysisSilence.c new file mode 100644 index 0000000..0876245 --- /dev/null +++ b/test/analysis/AnalysisSilence.c @@ -0,0 +1,25 @@ +#include "AnalysisSilence.h" +#include "AnalyzeFile.h" + +boolByte analysisSilence(const SampleBuffer sampleBuffer, AnalysisFunctionData data) +{ + for (ChannelCount i = 0; i < sampleBuffer->numChannels; ++i) { + for (SampleCount j = 0; j < sampleBuffer->blocksize; ++j) { + if (sampleBuffer->samples[i][j] == 0.0f) { + data->consecutiveFailCounter++; + + if (data->consecutiveFailCounter > data->failTolerance) { + data->failedChannel = i; + data->failedSample = j; + return false; + } + } else { + if (data->consecutiveFailCounter > 0) { + data->consecutiveFailCounter = 0; + } + } + } + } + + return true; +} diff --git a/test/analysis/AnalysisSilence.h b/test/analysis/AnalysisSilence.h new file mode 100644 index 0000000..4e56c6c --- /dev/null +++ b/test/analysis/AnalysisSilence.h @@ -0,0 +1,3 @@ +#include "AnalyzeFile.h" + +boolByte analysisSilence(const SampleBuffer sampleBuffer, AnalysisFunctionData data); diff --git a/test/analysis/AnalysisSilenceTest.c b/test/analysis/AnalysisSilenceTest.c new file mode 100644 index 0000000..968bc37 --- /dev/null +++ b/test/analysis/AnalysisSilenceTest.c @@ -0,0 +1,57 @@ +#include "AnalysisSilence.h" +#include "unit/TestRunner.h" + +static int _testAnalysisSilence(void) +{ + SampleBuffer s = newSampleBuffer(1, 64); + AnalysisFunctionData d = newAnalysisFunctionData(); + assertFalse(analysisSilence(s, d)); + freeAnalysisFunctionData(d); + freeSampleBuffer(s); + return 0; +} + +static int _testAnalysisNotSilence(void) +{ + SampleBuffer s = newSampleBuffer(2, 64); + AnalysisFunctionData d = newAnalysisFunctionData(); + unsigned long i; + unsigned int j; + + for (i = 0; i < s->blocksize; i++) { + for (j = 0; j < s->numChannels; j++) { + s->samples[j][i] = 32767.0; + } + } + + assert(analysisSilence(s, d)); + freeAnalysisFunctionData(d); + freeSampleBuffer(s); + return 0; +} + +static int _testAnalysisNotSilenceInOneChannel(void) +{ + SampleBuffer s = newSampleBuffer(1, 64); + AnalysisFunctionData d = newAnalysisFunctionData(); + unsigned long i; + + for (i = 0; i < s->blocksize; i++) { + s->samples[0][i] = 32767.0; + } + + assert(analysisSilence(s, d)); + freeAnalysisFunctionData(d); + freeSampleBuffer(s); + return 0; +} + +TestSuite addAnalysisSilenceTests(void); +TestSuite addAnalysisSilenceTests(void) +{ + TestSuite testSuite = newTestSuite("AnalysisSilence", NULL, NULL); + addTest(testSuite, "AnalysisSilence", _testAnalysisSilence); + addTest(testSuite, "AnalysisNotSilence", _testAnalysisNotSilence); + addTest(testSuite, "AnalysisNotSilenceInOneChannel", _testAnalysisNotSilenceInOneChannel); + return testSuite; +} diff --git a/test/analysis/AnalyzeFile.c b/test/analysis/AnalyzeFile.c new file mode 100644 index 0000000..11e020f --- /dev/null +++ b/test/analysis/AnalyzeFile.c @@ -0,0 +1,123 @@ +#include <stdlib.h> +#include "audio/AudioSettings.h" +#include "io/SampleSource.h" +#include "AnalysisClipping.h" +#include "AnalysisDistortion.h" +#include "AnalysisSilence.h" + +// Number of consecutive samples which need to fail in order for the test to fail +static const int kAnalysisDefaultFailTolerance = 16; +// Use a blocksize of the default * 2 in order to avoid false positives of the +// silence detection algorithm, since the last block is likely to be silent. +static const int kAnalysisBlocksize = DEFAULT_BLOCKSIZE * 2; + +static LinkedList _getAnalysisFunctions(void) +{ + AnalysisFunctionData data; + LinkedList functionsList = newLinkedList(); + + data = newAnalysisFunctionData(); + data->analysisName = "clipping"; + data->functionPtr = (void *)analysisClipping; + linkedListAppend(functionsList, data); + + data = newAnalysisFunctionData(); + data->analysisName = "distortion"; + data->functionPtr = (void *)analysisDistortion; + linkedListAppend(functionsList, data); + + data = newAnalysisFunctionData(); + data->analysisName = "silence"; + data->functionPtr = (void *)analysisSilence; + data->failTolerance = kAnalysisBlocksize; + linkedListAppend(functionsList, data); + + return functionsList; +} + +static void _runAnalysisFunction(void *item, void *userData) +{ + AnalysisFunctionData functionData = (AnalysisFunctionData)item; + AnalysisFuncPtr analysisFuncPtr = (AnalysisFuncPtr)(functionData->functionPtr); + AnalysisData analysisData = (AnalysisData)userData; + + if (!analysisFuncPtr(analysisData->sampleBuffer, functionData)) { + charStringCopyCString(analysisData->failedAnalysisFunctionName, functionData->analysisName); + *(analysisData->failedAnalysisFrame) = *(analysisData->currentFrame) + functionData->failedSample; + *(analysisData->failedAnalysisChannel) = functionData->failedChannel; + *(analysisData->result) = false; + } +} + +boolByte analyzeFile(const char *filename, CharString failedAnalysisFunctionName, + ChannelCount *failedAnalysisChannel, SampleCount *failedAnalysisFrame) +{ + boolByte result; + CharString analysisFilename; + SampleSource sampleSource; + LinkedList analysisFunctions; + AnalysisData analysisData = (AnalysisData)malloc(sizeof(AnalysisDataMembers)); + SampleCount currentFrame = 0; + + // Needed to initialize new sample sources + initAudioSettings(); + analysisFunctions = _getAnalysisFunctions(); + analysisFilename = newCharStringWithCString(filename); + sampleSource = sampleSourceFactory(analysisFilename); + + if (sampleSource == NULL) { + freeCharString(analysisFilename); + free(analysisData); + freeAudioSettings(); + return false; + } + + result = sampleSource->openSampleSource(sampleSource, SAMPLE_SOURCE_OPEN_READ); + + if (!result) { + free(analysisData); + return result; + } + + analysisData->failedAnalysisFunctionName = failedAnalysisFunctionName; + analysisData->failedAnalysisChannel = failedAnalysisChannel; + analysisData->failedAnalysisFrame = failedAnalysisFrame; + analysisData->sampleBuffer = newSampleBuffer(DEFAULT_NUM_CHANNELS, kAnalysisBlocksize); + analysisData->currentFrame = ¤tFrame; + analysisData->result = &result; + + while (sampleSource->readSampleBlock(sampleSource, analysisData->sampleBuffer) && result) { + linkedListForeach(analysisFunctions, _runAnalysisFunction, analysisData); + currentFrame += kAnalysisBlocksize; + } + + freeSampleSource(sampleSource); + freeCharString(analysisFilename); + freeAudioSettings(); + freeSampleBuffer(analysisData->sampleBuffer); + freeLinkedListAndItems(analysisFunctions, (LinkedListFreeItemFunc)freeAnalysisFunctionData); + free(analysisData); + return result; +} + +void freeAnalysisFunctionData(AnalysisFunctionData self) +{ + free(self->lastSample); + free(self); +} + +AnalysisFunctionData newAnalysisFunctionData(void) +{ + AnalysisFunctionData result = (AnalysisFunctionData)malloc(sizeof(AnalysisFunctionDataMembers)); + result->analysisName = NULL; + result->consecutiveFailCounter = 0; + result->failedSample = 0; + result->functionPtr = NULL; + // TODO: Should use max channels, when we get that + result->lastSample = (Sample*)malloc(sizeof(Sample) * 2); + result->lastSample[0] = 0.0f; + result->lastSample[1] = 0.0f; + result->failTolerance = kAnalysisDefaultFailTolerance; + return result; +} + diff --git a/test/analysis/AnalyzeFile.h b/test/analysis/AnalyzeFile.h new file mode 100644 index 0000000..d47b3ba --- /dev/null +++ b/test/analysis/AnalyzeFile.h @@ -0,0 +1,37 @@ +#include <stdio.h> +#include "base/Types.h" +#include "audio/SampleBuffer.h" +#include "base/CharString.h" + +#ifndef MrsWatson_AnalyzeFile_h +#define MrsWatson_AnalyzeFile_h + +typedef struct { + const char *analysisName; + void *functionPtr; + int consecutiveFailCounter; + Sample *lastSample; + SampleCount failedSample; + ChannelCount failedChannel; + int failTolerance; +} AnalysisFunctionDataMembers; +typedef AnalysisFunctionDataMembers *AnalysisFunctionData; +typedef boolByte (*AnalysisFuncPtr)(const SampleBuffer sampleBuffer, AnalysisFunctionData data); + +typedef struct { + CharString failedAnalysisFunctionName; + SampleCount *failedAnalysisFrame; + ChannelCount *failedAnalysisChannel; + SampleCount *currentFrame; + boolByte *result; + SampleBuffer sampleBuffer; + AnalysisFunctionData functionData; +} AnalysisDataMembers; +typedef AnalysisDataMembers *AnalysisData; + +AnalysisFunctionData newAnalysisFunctionData(void); +boolByte analyzeFile(const char *filename, CharString failedAnalysisFunctionName, + ChannelCount *failedAnalysisChannel, SampleCount *failedAnalysisFrame); +void freeAnalysisFunctionData(AnalysisFunctionData self); + +#endif |
