tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

convolution-testing.js (5871B)


      1 var sampleRate = 44100.0;
      2 
      3 var renderLengthSeconds = 8;
      4 var pulseLengthSeconds = 1;
      5 var pulseLengthFrames = pulseLengthSeconds * sampleRate;
      6 
      7 function createSquarePulseBuffer(context, sampleFrameLength) {
      8    var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate);
      9 
     10    var n = audioBuffer.length;
     11    var data = audioBuffer.getChannelData(0);
     12 
     13    for (var i = 0; i < n; ++i)
     14        data[i] = 1;
     15 
     16    return audioBuffer;
     17 }
     18 
     19 // The triangle buffer holds the expected result of the convolution.
     20 // It linearly ramps up from 0 to its maximum value (at the center)
     21 // then linearly ramps down to 0.  The center value corresponds to the
     22 // point where the two square pulses overlap the most.
     23 function createTrianglePulseBuffer(context, sampleFrameLength) {
     24    var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate);
     25 
     26    var n = audioBuffer.length;
     27    var halfLength = n / 2;
     28    var data = audioBuffer.getChannelData(0);
     29    
     30    for (var i = 0; i < halfLength; ++i)
     31        data[i] = i + 1;
     32 
     33    for (var i = halfLength; i < n; ++i)
     34        data[i] = n - i - 1;
     35 
     36    return audioBuffer;
     37 }
     38 
     39 function log10(x) {
     40  return Math.log(x)/Math.LN10;
     41 }
     42 
     43 function linearToDecibel(x) {
     44  return 20*log10(x);
     45 }
     46 
     47 // Verify that the rendered result is very close to the reference
     48 // triangular pulse.
     49 function checkTriangularPulse(rendered, reference) {
     50    var match = true;
     51    var maxDelta = 0;
     52    var valueAtMaxDelta = 0;
     53    var maxDeltaIndex = 0;
     54 
     55    for (var i = 0; i < reference.length; ++i) {
     56        var diff = rendered[i] - reference[i];
     57        var x = Math.abs(diff);
     58        if (x > maxDelta) {
     59            maxDelta = x;
     60            valueAtMaxDelta = reference[i];
     61            maxDeltaIndex = i;
     62        }
     63    }
     64 
     65    // allowedDeviationFraction was determined experimentally.  It
     66    // is the threshold of the relative error at the maximum
     67    // difference between the true triangular pulse and the
     68    // rendered pulse.
     69    var allowedDeviationDecibels = -129.4;
     70    var maxDeviationDecibels = linearToDecibel(maxDelta / valueAtMaxDelta);
     71 
     72    if (maxDeviationDecibels <= allowedDeviationDecibels) {
     73        testPassed("Triangular portion of convolution is correct.");
     74    } else {
     75        testFailed("Triangular portion of convolution is not correct.  Max deviation = " + maxDeviationDecibels + " dB at " + maxDeltaIndex);
     76        match = false;
     77    }
     78 
     79    return match;
     80 }        
     81 
     82 // Verify that the rendered data is close to zero for the first part
     83 // of the tail.
     84 function checkTail1(data, reference, breakpoint) {
     85    var isZero = true;
     86    var tail1Max = 0;
     87 
     88    for (var i = reference.length; i < reference.length + breakpoint; ++i) {
     89        var mag = Math.abs(data[i]);
     90        if (mag > tail1Max) {
     91            tail1Max = mag;
     92        }
     93    }
     94 
     95    // Let's find the peak of the reference (even though we know a
     96    // priori what it is).
     97    var refMax = 0;
     98    for (var i = 0; i < reference.length; ++i) {
     99      refMax = Math.max(refMax, Math.abs(reference[i]));
    100    }
    101 
    102    // This threshold is experimentally determined by examining the
    103    // value of tail1MaxDecibels.
    104    var threshold1 = -129.7;
    105 
    106    var tail1MaxDecibels = linearToDecibel(tail1Max/refMax);
    107    if (tail1MaxDecibels <= threshold1) {
    108        testPassed("First part of tail of convolution is sufficiently small.");
    109    } else {
    110        testFailed("First part of tail of convolution is not sufficiently small: " + tail1MaxDecibels + " dB");
    111        isZero = false;
    112    }
    113 
    114    return isZero;
    115 }
    116 
    117 // Verify that the second part of the tail of the convolution is
    118 // exactly zero.
    119 function checkTail2(data, reference, breakpoint) {
    120    var isZero = true;
    121    var tail2Max = 0;
    122    // For the second part of the tail, the maximum value should be
    123    // exactly zero.
    124    var threshold2 = 0;
    125    for (var i = reference.length + breakpoint; i < data.length; ++i) {
    126        if (Math.abs(data[i]) > 0) {
    127            isZero = false; 
    128            break;
    129        }
    130    }
    131 
    132    if (isZero) {
    133        testPassed("Rendered signal after tail of convolution is silent.");
    134    } else {
    135        testFailed("Rendered signal after tail of convolution should be silent.");
    136    }
    137 
    138    return isZero;
    139 }
    140 
    141 function checkConvolvedResult(trianglePulse) {
    142    return function(event) {
    143        var renderedBuffer = event.renderedBuffer;
    144 
    145        var referenceData = trianglePulse.getChannelData(0);
    146        var renderedData = renderedBuffer.getChannelData(0);
    147    
    148        var success = true;
    149    
    150        // Verify the triangular pulse is actually triangular.
    151 
    152        success = success && checkTriangularPulse(renderedData, referenceData);
    153        
    154        // Make sure that portion after convolved portion is totally
    155        // silent.  But round-off prevents this from being completely
    156        // true.  At the end of the triangle, it should be close to
    157        // zero.  If we go farther out, it should be even closer and
    158        // eventually zero.
    159 
    160        // For the tail of the convolution (where the result would be
    161        // theoretically zero), we partition the tail into two
    162        // parts.  The first is the at the beginning of the tail,
    163        // where we tolerate a small but non-zero value.  The second part is
    164        // farther along the tail where the result should be zero.
    165        
    166        // breakpoint is the point dividing the first two tail parts
    167        // we're looking at.  Experimentally determined.
    168        var breakpoint = 12800;
    169 
    170        success = success && checkTail1(renderedData, referenceData, breakpoint);
    171        
    172        success = success && checkTail2(renderedData, referenceData, breakpoint);
    173        
    174        if (success) {
    175            testPassed("Test signal was correctly convolved.");
    176        } else {
    177            testFailed("Test signal was not correctly convolved.");
    178        }
    179 
    180        finishJSTest();
    181    }
    182 }