tor-browser

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

audioparam-setValueCurve-exceptions.html (15100B)


      1 <!DOCTYPE html>
      2 <html>
      3  <head>
      4    <title>
      5      Test Exceptions from setValueCurveAtTime
      6    </title>
      7    <script src="/resources/testharness.js"></script>
      8    <script src="/resources/testharnessreport.js"></script>
      9    <script src="/webaudio/resources/audit-util.js"></script>
     10    <script src="/webaudio/resources/audit.js"></script>
     11  </head>
     12  <body>
     13    <script id="layout-test-code">
     14      let sampleRate = 48000;
     15      // Some short duration because we don't need to run the test for very
     16      // long.
     17      let testDurationSec = 0.125;
     18      let testDurationFrames = testDurationSec * sampleRate;
     19 
     20      let audit = Audit.createTaskRunner();
     21 
     22      audit.define('setValueCurve', (task, should) => {
     23        let context =
     24            new OfflineAudioContext(1, testDurationFrames, sampleRate);
     25        let g = context.createGain();
     26        let curve = new Float32Array(2);
     27 
     28        // Start time and duration for setValueCurveAtTime
     29        let curveStartTime = 0.1 * testDurationSec;
     30        let duration = 0.1 * testDurationSec;
     31 
     32        // Some time that is known to be during the setValueCurveTime interval.
     33        let automationTime = curveStartTime + duration / 2;
     34 
     35        should(
     36            () => {
     37              g.gain.setValueCurveAtTime(curve, curveStartTime, duration);
     38            },
     39            'setValueCurveAtTime(curve, ' + curveStartTime + ', ' + duration +
     40                ')')
     41            .notThrow();
     42 
     43        should(
     44            function() {
     45              g.gain.setValueAtTime(1, automationTime);
     46            },
     47            'setValueAtTime(1, ' + automationTime + ')')
     48            .throw(DOMException, 'NotSupportedError');
     49 
     50        should(
     51            function() {
     52              g.gain.linearRampToValueAtTime(1, automationTime);
     53            },
     54            'linearRampToValueAtTime(1, ' + automationTime + ')')
     55            .throw(DOMException, 'NotSupportedError');
     56 
     57        should(
     58            function() {
     59              g.gain.exponentialRampToValueAtTime(1, automationTime);
     60            },
     61            'exponentialRampToValueAtTime(1, ' + automationTime + ')')
     62            .throw(DOMException, 'NotSupportedError');
     63 
     64        should(
     65            function() {
     66              g.gain.setTargetAtTime(1, automationTime, 1);
     67            },
     68            'setTargetAtTime(1, ' + automationTime + ', 1)')
     69            .throw(DOMException, 'NotSupportedError');
     70 
     71        should(
     72            function() {
     73              g.gain.setValueAtTime(1, curveStartTime + 1.1 * duration);
     74            },
     75            'setValueAtTime(1, ' + (curveStartTime + 1.1 * duration) + ')')
     76            .notThrow();
     77 
     78        task.done();
     79      });
     80 
     81      audit.define('value setter', (task, should) => {
     82        let context =
     83            new OfflineAudioContext(1, testDurationFrames, sampleRate);
     84        let g = context.createGain();
     85        let curve = new Float32Array(2);
     86 
     87        // Start time and duration for setValueCurveAtTime
     88        let curveStartTime = 0.;
     89        let duration = 0.2 * testDurationSec;
     90 
     91        // Some time that is known to be during the setValueCurveTime interval.
     92        let automationTime = 0.;
     93 
     94        should(
     95            () => {
     96              g.gain.setValueCurveAtTime(curve, curveStartTime, duration);
     97            },
     98            'setValueCurveAtTime(curve, ' + curveStartTime + ', ' + duration +
     99                ')')
    100            .notThrow();
    101 
    102        should(
    103            function() {
    104              g.gain.value = 0.;
    105            },
    106            'value setter')
    107            .throw(DOMException, 'NotSupportedError');
    108 
    109        task.done();
    110      });
    111 
    112      audit.define('automations', (task, should) => {
    113        let context =
    114            new OfflineAudioContext(1, testDurationFrames, sampleRate);
    115        let g = context.createGain();
    116 
    117        let curve = new Float32Array(2);
    118        // Start time and duration for setValueCurveAtTime
    119        let startTime = 0;
    120        let timeInterval = testDurationSec / 10;
    121        let time;
    122 
    123        startTime += timeInterval;
    124        should(() => {
    125          g.gain.linearRampToValueAtTime(1, startTime);
    126        }, 'linearRampToValueAtTime(1, ' + startTime + ')').notThrow();
    127 
    128        startTime += timeInterval;
    129        should(() => {
    130          g.gain.exponentialRampToValueAtTime(1, startTime);
    131        }, 'exponentialRampToValueAtTime(1, ' + startTime + ')').notThrow();
    132 
    133        startTime += timeInterval;
    134        should(() => {
    135          g.gain.setTargetAtTime(1, startTime, 0.1);
    136        }, 'setTargetAtTime(1, ' + startTime + ', 0.1)').notThrow();
    137 
    138        startTime += timeInterval;
    139        should(() => {
    140          g.gain.setValueCurveAtTime(curve, startTime, 0.1);
    141        }, 'setValueCurveAtTime(curve, ' + startTime + ', 0.1)').notThrow();
    142 
    143        // Now try to setValueCurve that overlaps each of the above automations
    144        startTime = timeInterval / 2;
    145 
    146        for (let k = 0; k < 4; ++k) {
    147          time = startTime + timeInterval * k;
    148          should(
    149              () => {
    150                g.gain.setValueCurveAtTime(curve, time, 0.01);
    151              },
    152              'setValueCurveAtTime(curve, ' + time + ', 0.01)')
    153              .throw(DOMException, 'NotSupportedError');
    154        }
    155 
    156        // Elements of setValueCurve should be finite.
    157        should(
    158            () => {
    159              g.gain.setValueCurveAtTime(
    160                  Float32Array.from([NaN, NaN]), time, 0.01);
    161            },
    162            'setValueCurveAtTime([NaN, NaN], ' + time + ', 0.01)')
    163            .throw(TypeError);
    164 
    165        should(
    166            () => {
    167              g.gain.setValueCurveAtTime(
    168                  Float32Array.from([1, Infinity]), time, 0.01);
    169            },
    170            'setValueCurveAtTime([1, Infinity], ' + time + ', 0.01)')
    171            .throw(TypeError);
    172 
    173        let d = context.createDelay();
    174        // Check that we get warnings for out-of-range values and also throw for
    175        // non-finite values.
    176        should(
    177            () => {
    178              d.delayTime.setValueCurveAtTime(
    179                  Float32Array.from([1, 5]), time, 0.01);
    180            },
    181            'delayTime.setValueCurveAtTime([1, 5], ' + time + ', 0.01)')
    182            .notThrow();
    183 
    184        should(
    185            () => {
    186              d.delayTime.setValueCurveAtTime(
    187                  Float32Array.from([1, 5, Infinity]), time, 0.01);
    188            },
    189            'delayTime.setValueCurveAtTime([1, 5, Infinity], ' + time +
    190                ', 0.01)')
    191            .throw(TypeError);
    192 
    193        // One last test that prints out lots of digits for the time.
    194        time = Math.PI / 100;
    195        should(
    196            () => {
    197              g.gain.setValueCurveAtTime(curve, time, 0.01);
    198            },
    199            'setValueCurveAtTime(curve, ' + time + ', 0.01)')
    200            .throw(DOMException, 'NotSupportedError');
    201 
    202        task.done();
    203      });
    204 
    205      audit.define('catch-exception', (task, should) => {
    206        // Verify that the curve isn't inserted into the time line even if we
    207        // catch the exception.
    208        let context =
    209            new OfflineAudioContext(1, testDurationFrames, sampleRate);
    210        let gain = context.createGain();
    211        let source = context.createBufferSource();
    212        let buffer = context.createBuffer(1, 1, context.sampleRate);
    213        buffer.getChannelData(0)[0] = 1;
    214        source.buffer = buffer;
    215        source.loop = true;
    216 
    217        source.connect(gain);
    218        gain.connect(context.destination);
    219 
    220        gain.gain.setValueAtTime(1, 0);
    221        try {
    222          // The value curve has an invalid element. This automation shouldn't
    223          // be inserted into the timeline at all.
    224          gain.gain.setValueCurveAtTime(
    225              Float32Array.from([0, NaN]), 128 / context.sampleRate, .5);
    226        } catch (e) {
    227        };
    228        source.start();
    229 
    230        context.startRendering()
    231            .then(function(resultBuffer) {
    232              // Since the setValueCurve wasn't inserted, the output should be
    233              // exactly 1 for the entire duration.
    234              should(
    235                  resultBuffer.getChannelData(0),
    236                  'Handled setValueCurve exception so output')
    237                  .beConstantValueOf(1);
    238 
    239            })
    240            .then(() => task.done());
    241      });
    242 
    243      audit.define('start-end', (task, should) => {
    244        let context =
    245            new OfflineAudioContext(1, testDurationFrames, sampleRate);
    246        let g = context.createGain();
    247        let curve = new Float32Array(2);
    248 
    249        // Verify that a setValueCurve can start at the end of an automation.
    250        let time = 0;
    251        let timeInterval = testDurationSec / 50;
    252        should(() => {
    253          g.gain.setValueAtTime(1, time);
    254        }, 'setValueAtTime(1, ' + time + ')').notThrow();
    255 
    256        time += timeInterval;
    257        should(() => {
    258          g.gain.linearRampToValueAtTime(0, time);
    259        }, 'linearRampToValueAtTime(0, ' + time + ')').notThrow();
    260 
    261        // setValueCurve starts at the end of the linear ramp. This should be
    262        // fine.
    263        should(
    264            () => {
    265              g.gain.setValueCurveAtTime(curve, time, timeInterval);
    266            },
    267            'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')')
    268            .notThrow();
    269 
    270        // exponentialRamp ending one interval past the setValueCurve should be
    271        // fine.
    272        time += 2 * timeInterval;
    273        should(() => {
    274          g.gain.exponentialRampToValueAtTime(1, time);
    275        }, 'exponentialRampToValueAtTime(1, ' + time + ')').notThrow();
    276 
    277        // setValueCurve starts at the end of the exponential ramp. This should
    278        // be fine.
    279        should(
    280            () => {
    281              g.gain.setValueCurveAtTime(curve, time, timeInterval);
    282            },
    283            'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')')
    284            .notThrow();
    285 
    286        // setValueCurve at the end of the setValueCurve should be fine.
    287        time += timeInterval;
    288        should(
    289            () => {
    290              g.gain.setValueCurveAtTime(curve, time, timeInterval);
    291            },
    292            'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')')
    293            .notThrow();
    294 
    295        // setValueAtTime at the end of setValueCurve should be fine.
    296        time += timeInterval;
    297        should(() => {
    298          g.gain.setValueAtTime(0, time);
    299        }, 'setValueAtTime(0, ' + time + ')').notThrow();
    300 
    301        // setValueCurve at the end of setValueAtTime should be fine.
    302        should(
    303            () => {
    304              g.gain.setValueCurveAtTime(curve, time, timeInterval);
    305            },
    306            'setValueCurveAtTime(..., ' + time + ', ' + timeInterval + ')')
    307            .notThrow();
    308 
    309        // setTarget starting at the end of setValueCurve should be fine.
    310        time += timeInterval;
    311        should(() => {
    312          g.gain.setTargetAtTime(1, time, 1);
    313        }, 'setTargetAtTime(1, ' + time + ', 1)').notThrow();
    314 
    315        task.done();
    316      });
    317 
    318      audit.define('curve overlap', (task, should) => {
    319        let context =
    320            new OfflineAudioContext(1, testDurationFrames, sampleRate);
    321        let g = context.createGain();
    322        let startTime = 5;
    323        let startTimeLater = 10;
    324        let startTimeEarlier = 2.5;
    325        let curveDuration = 10;
    326        let curveDurationShorter = 5;
    327        let curve = [1, 2, 3];
    328 
    329        // An initial curve event
    330        should(
    331            () => {
    332              g.gain.setValueCurveAtTime(curve, startTime, curveDuration);
    333            },
    334            `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`)
    335            .notThrow();
    336 
    337        // Check that an exception is thrown when trying to overlap two curves,
    338        // in various ways
    339 
    340        // Same start time and end time (curve exactly overlapping)
    341        should(
    342            () => {
    343              g.gain.setValueCurveAtTime(curve, startTime, curveDuration);
    344            },
    345            `second g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`)
    346            .throw(DOMException, 'NotSupportedError');
    347        // Same start time, shorter end time
    348        should(
    349            () => {
    350              g.gain.setValueCurveAtTime(curve, startTime, curveDurationShorter);
    351            },
    352            `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDurationShorter})`)
    353            .throw(DOMException, 'NotSupportedError');
    354        // Earlier start time, end time after the start time an another curve
    355        should(
    356            () => {
    357              g.gain.setValueCurveAtTime(curve, startTimeEarlier, curveDuration);
    358            },
    359            `g.gain.setValueCurveAtTime([${curve}], ${startTimeEarlier}, ${curveDuration})`)
    360            .throw(DOMException, 'NotSupportedError');
    361        // Start time after the start time of the other curve, but earlier than
    362        // its end.
    363        should(
    364            () => {
    365              g.gain.setValueCurveAtTime(curve, startTimeLater, curveDuration);
    366            },
    367            `g.gain.setValueCurveAtTime([${curve}], ${startTimeLater}, ${curveDuration})`)
    368            .throw(DOMException, 'NotSupportedError');
    369 
    370        // New event wholly contained inside existing event
    371        should(
    372            () => {
    373              g.gain.setValueCurveAtTime(curve, startTime + 1, curveDuration - 1);
    374            },
    375            `g.gain.setValueCurveAtTime([${curve}], ${startTime+1}, ${curveDuration-1})`)
    376            .throw(DOMException, 'NotSupportedError');
    377        // Old event completely contained inside new event
    378        should(
    379            () => {
    380              g.gain.setValueCurveAtTime(curve, startTime - 1, curveDuration + 1);
    381            },
    382            `g.gain.setValueCurveAtTime([${curve}], ${startTime-1}, ${curveDuration+1})`)
    383            .throw(DOMException, 'NotSupportedError');
    384        // Setting an event exactly at the end of the curve should work.
    385        should(
    386            () => {
    387              g.gain.setValueAtTime(1.0, startTime + curveDuration);
    388            },
    389            `g.gain.setValueAtTime(1.0, ${startTime + curveDuration})`)
    390            .notThrow();
    391 
    392        task.done();
    393      });
    394 
    395      audit.define('curve lengths', (task, should) => {
    396        let context =
    397            new OfflineAudioContext(1, testDurationFrames, sampleRate);
    398        let g = context.createGain();
    399        let time = 0;
    400 
    401        // Check for invalid curve lengths
    402        should(
    403            () => {
    404              g.gain.setValueCurveAtTime(Float32Array.from([]), time, 0.01);
    405            },
    406            'setValueCurveAtTime([], ' + time + ', 0.01)')
    407            .throw(DOMException, 'InvalidStateError');
    408 
    409        should(
    410            () => {
    411              g.gain.setValueCurveAtTime(Float32Array.from([1]), time, 0.01);
    412            },
    413            'setValueCurveAtTime([1], ' + time + ', 0.01)')
    414            .throw(DOMException, 'InvalidStateError');
    415 
    416        should(() => {
    417          g.gain.setValueCurveAtTime(Float32Array.from([1, 2]), time, 0.01);
    418        }, 'setValueCurveAtTime([1,2], ' + time + ', 0.01)').notThrow();
    419 
    420        task.done();
    421      });
    422 
    423      audit.run();
    424    </script>
    425  </body>
    426 </html>