Home | History | Annotate | Download | only in audioquality
      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 
     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 
     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 
    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