summaryrefslogtreecommitdiff
path: root/test/analysis/AnalyzeFile.c
blob: 11e020ffa7946654386e90589523bf625fb5ce68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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 = &currentFrame;
    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;
}