1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17 /* This assumes an input signal that has at least a few hundred
18 milliseconds of high-amplitude sinusoidal signal. The signal is
19 expected to be a relatively low-frequency sinusoid (200-400 Hz).
20 If the signal is linearly reproduced or clipped, There will be no
21 large step changes in value from one sample to the next. On the
22 other hand, if the signal contains numerical overflow
23 (wrap-around), very large excursions will be produced.
24
25 This program first searches for the high-amplitude recorded
26 segment, then examines just that part of the signal for "large
27 excursions", and returns the results of the search as four
28 integers:
29
30 n_wraps signal_size sine_start sine_end
31
32 where n_wraps is the number of anomolous value jumps found,
33 signal_size is the number of lin16 samples found in the file,
34 sine_start and sine_end are the limits of the region searched for
35 anomolous jumps. */
36
37 #include <stdlib.h>
38 #include <math.h>
39
40 // MAX_ALLOWED_STEP is the largest sample-to-sample change that will
41 // be considered "normal" for 250 Hz signals sampled at 8kHz. This is
42 // calibrated by the largest sample-to-sample change that is naturally
43 // present in a 250 Hz sine wave with amplitude of 40000 (which is
44 // actually 7804).
45 #define MAX_ALLOWED_STEP 16000
46
47 // This is the RMS value that is expected to be exceded by a sinusoid
48 // with a peak amplitude of 32767 (actually 23169).
49 #define SIGNAL_ON_RMS 12000.0
50
findEndpoints(short * data,int n,int step,int * start,int * end)51 static void findEndpoints(short* data, int n, int step, int* start, int* end) {
52 int size = step;
53 *start = *end = 0;
54 int last_frame = n - size;
55 for (int frame = 0; frame < last_frame; frame += step) {
56 double sum = 0.0;
57 for (int i=0; i < size; ++i) {
58 float val = data[i + frame];
59 sum += (val * val);
60 }
61 float rms = sqrt(sum / size);
62 if (! *start) {
63 if (rms >= SIGNAL_ON_RMS) {
64 *start = frame + size;
65 }
66 continue;
67 } else {
68 if (rms < SIGNAL_ON_RMS) {
69 *end = frame - size;
70 return;
71 }
72 }
73 }
74 if ((*start > 0) && (! *end)) {
75 *end = n - size - 1;
76 }
77 }
78
checkExcursions(short * data,int start,int end,int * numJumps,int * maxPeak,int * minPeak)79 static void checkExcursions(short* data, int start, int end, int* numJumps,
80 int* maxPeak, int* minPeak) {
81 *numJumps = 0;
82 int endm = end - 1;
83 if ((endm - start) < 3) {
84 *numJumps = -1;
85 return;
86 }
87 *maxPeak = *minPeak = data[start];
88 for (int i = start; i < endm; ++i) {
89 int v1 = data[i];
90 int v2 = data[i+1];
91 if (v1 > *maxPeak)
92 *maxPeak = v1;
93 if (v1 < *minPeak)
94 *minPeak = v1;
95 int diff = v2 - v1;
96 if (diff < 0)
97 diff = -diff;
98 if (diff > MAX_ALLOWED_STEP)
99 (*numJumps) += 1;
100 }
101 return;
102 }
103
overflowCheck(short * pcm,int numSamples,float sampleRate,float * duration,int * numDeltas,int * onset,int * offset,int * maxPeak,int * minPeak)104 int overflowCheck(short* pcm, int numSamples, float sampleRate,
105 float* duration, int* numDeltas, int* onset, int* offset,
106 int* maxPeak, int* minPeak) {
107 float windSize = 0.020;
108 int minBuff = int(2.0 * sampleRate); // must have 2 sec of data at least.
109
110 if(pcm && (numSamples >= minBuff)) {
111 int step = int(0.5 + (windSize * sampleRate));
112 *onset = 0;
113 *offset = 0;
114
115 findEndpoints(pcm, numSamples, step, onset, offset);
116 *numDeltas = -1;
117 checkExcursions(pcm, *onset, *offset, numDeltas, maxPeak, minPeak);
118 *duration = (*offset - *onset) / sampleRate;
119 return 1; // true/success
120 }
121 return 0; // failure
122 }
123