tor-browser

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

note-grain-on-testing.js (6904B)


      1 // Use a power of two to eliminate round-off converting from frames to time.
      2 let sampleRate = 32768;
      3 
      4 // How many grains to play.
      5 let numberOfTests = 100;
      6 
      7 // Duration of each grain to be played.  Make a whole number of frames
      8 let duration = Math.floor(0.01 * sampleRate) / sampleRate;
      9 
     10 // A little extra bit of silence between grain boundaries.  Must be a whole
     11 // number of frames.
     12 let grainGap = Math.floor(0.005 * sampleRate) / sampleRate;
     13 
     14 // Time step between the start of each grain.  We need to add a little
     15 // bit of silence so we can detect grain boundaries
     16 let timeStep = duration + grainGap;
     17 
     18 // Time step between the start for each grain.  Must be a whole number of
     19 // frames.
     20 let grainOffsetStep = Math.floor(0.001 * sampleRate) / sampleRate;
     21 
     22 // How long to render to cover all of the grains.
     23 let renderTime = (numberOfTests + 1) * timeStep;
     24 
     25 let context;
     26 let renderedData;
     27 
     28 // Create a buffer containing the data that we want.  The function f
     29 // returns the desired value at sample frame k.
     30 function createSignalBuffer(context, f) {
     31  // Make sure the buffer has enough data for all of the possible
     32  // grain offsets and durations.  The additional 1 is for any
     33  // round-off errors.
     34  let signalLength =
     35      Math.floor(1 + sampleRate * (numberOfTests * grainOffsetStep + duration));
     36 
     37  let buffer = context.createBuffer(2, signalLength, sampleRate);
     38  let data = buffer.getChannelData(0);
     39 
     40  for (let k = 0; k < signalLength; ++k) {
     41    data[k] = f(k);
     42  }
     43 
     44  return buffer;
     45 }
     46 
     47 // From the data array, find the start and end sample frame for each
     48 // grain.  This depends on the data having 0's between grain, and
     49 // that the grain is always strictly non-zero.
     50 function findStartAndEndSamples(data) {
     51  let nSamples = data.length;
     52 
     53  let startTime = [];
     54  let endTime = [];
     55  let lookForStart = true;
     56 
     57  // Look through the rendered data to find the start and stop
     58  // times of each grain.
     59  for (let k = 0; k < nSamples; ++k) {
     60    if (lookForStart) {
     61      // Find a non-zero point and record the start.  We're not
     62      // concerned with the value in this test, only that the
     63      // grain started here.
     64      if (renderedData[k]) {
     65        startTime.push(k);
     66        lookForStart = false;
     67      }
     68    } else {
     69      // Find a zero and record the end of the grain.
     70      if (!renderedData[k]) {
     71        endTime.push(k);
     72        lookForStart = true;
     73      }
     74    }
     75  }
     76 
     77  return {start: startTime, end: endTime};
     78 }
     79 
     80 function playGrain(context, source, time, offset, duration) {
     81  let bufferSource = context.createBufferSource();
     82 
     83  bufferSource.buffer = source;
     84  bufferSource.connect(context.destination);
     85  bufferSource.start(time, offset, duration);
     86 }
     87 
     88 // Play out all grains.  Returns a object containing two arrays, one
     89 // for the start time and one for the grain offset time.
     90 function playAllGrains(context, source, numberOfNotes) {
     91  let startTimes = new Array(numberOfNotes);
     92  let offsets = new Array(numberOfNotes);
     93 
     94  for (let k = 0; k < numberOfNotes; ++k) {
     95    let timeOffset = k * timeStep;
     96    let grainOffset = k * grainOffsetStep;
     97 
     98    playGrain(context, source, timeOffset, grainOffset, duration);
     99    startTimes[k] = timeOffset;
    100    offsets[k] = grainOffset;
    101  }
    102 
    103  return {startTimes: startTimes, grainOffsetTimes: offsets};
    104 }
    105 
    106 // Verify that the start and end frames for each grain match our
    107 // expected start and end frames.
    108 function verifyStartAndEndFrames(startEndFrames, should) {
    109  let startFrames = startEndFrames.start;
    110  let endFrames = startEndFrames.end;
    111 
    112  // Count of how many grains started at the incorrect time.
    113  let errorCountStart = 0;
    114 
    115  // Count of how many grains ended at the incorrect time.
    116  let errorCountEnd = 0;
    117 
    118  should(
    119      startFrames.length == endFrames.length, 'Found all grain starts and ends')
    120      .beTrue();
    121 
    122  should(startFrames.length, 'Number of start frames').beEqualTo(numberOfTests);
    123  should(endFrames.length, 'Number of end frames').beEqualTo(numberOfTests);
    124 
    125  // Examine the start and stop times to see if they match our
    126  // expectations.
    127  for (let k = 0; k < startFrames.length; ++k) {
    128    let expectedStart = timeToSampleFrame(k * timeStep, sampleRate);
    129    // The end point is the duration.
    130    let expectedEnd = expectedStart +
    131        grainLengthInSampleFrames(k * grainOffsetStep, duration, sampleRate);
    132 
    133    if (startFrames[k] != expectedStart) {
    134      ++errorCountStart;
    135    }
    136    if (endFrames[k] != expectedEnd) {
    137      ++errorCountEnd;
    138    }
    139 
    140    should([startFrames[k], endFrames[k]], 'Pulse ' + k + ' boundary')
    141        .beEqualToArray([expectedStart, expectedEnd]);
    142  }
    143 
    144  // Check that all the grains started or ended at the correct time.
    145  if (!errorCountStart) {
    146    should(
    147        startFrames.length, 'Number of grains that started at the correct time')
    148        .beEqualTo(numberOfTests);
    149  } else {
    150    should(
    151        errorCountStart,
    152        'Number of grains out of ' + numberOfTests +
    153            'that started at the wrong time')
    154        .beEqualTo(0);
    155  }
    156 
    157  if (!errorCountEnd) {
    158    should(endFrames.length, 'Number of grains that ended at the correct time')
    159        .beEqualTo(numberOfTests);
    160  } else {
    161    should(
    162        errorCountEnd,
    163        'Number of grains out of ' + numberOfTests +
    164            ' that ended at the wrong time')
    165        .beEqualTo(0);
    166  }
    167 }
    168 
    169 function verifyStartAndEndFrames_W3CTH(startEndFrames) {
    170  const startFrames = startEndFrames.start;
    171  const endFrames = startEndFrames.end;
    172 
    173  let errorCountStart = 0;
    174  let errorCountEnd = 0;
    175 
    176  assert_equals(
    177      startFrames.length, endFrames.length,
    178      'Found all grain starts and ends');
    179  assert_equals(startFrames.length, numberOfTests, 'Number of start frames');
    180  assert_equals(endFrames.length, numberOfTests, 'Number of end frames');
    181 
    182  for (let k = 0; k < startFrames.length; ++k) {
    183    const expectedStart = timeToSampleFrame(k * timeStep, sampleRate);
    184    const expectedEnd =
    185        expectedStart + grainLengthInSampleFrames(
    186            k * grainOffsetStep, duration, sampleRate);
    187 
    188    if (startFrames[k] !== expectedStart) {
    189      ++errorCountStart;
    190    }
    191    if (endFrames[k] !== expectedEnd) {
    192      ++errorCountEnd;
    193    }
    194 
    195    assert_array_equals(
    196        [startFrames[k], endFrames[k]],
    197        [expectedStart, expectedEnd],
    198        'Pulse ' + k + ' boundary');
    199  }
    200 
    201  if (!errorCountStart) {
    202    assert_equals(
    203        startFrames.length, numberOfTests,
    204        'Number of grains that started at the correct time');
    205  } else {
    206    assert_equals(
    207        errorCountStart, 0,
    208        `Number of grains out of ${numberOfTests} that ` +
    209            `started at the wrong time`);
    210  }
    211 
    212  if (!errorCountEnd) {
    213    assert_equals(
    214        endFrames.length, numberOfTests,
    215        'Number of grains that ended at the correct time');
    216  } else {
    217    assert_equals(
    218        errorCountEnd, 0,
    219        `Number of grains out of ${numberOfTests} that ` +
    220            `ended at the wrong time`);
    221  }
    222 }