tor-browser

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

panner-automation-basic.html (10792B)


      1 <!DOCTYPE html>
      2 <html>
      3  <head>
      4    <title>
      5      Test Basic PannerNode with Automation Position Properties
      6    </title>
      7    <script src="/resources/testharness.js"></script>
      8    <script src="/resources/testharnessreport.js"></script>
      9    <script src="../../resources/audit-util.js"></script>
     10    <script src="../../resources/audit.js"></script>
     11    <script src="../../resources/panner-formulas.js"></script>
     12  </head>
     13  <body>
     14    <script id="layout-test-code">
     15      let sampleRate = 48000;
     16 
     17      // These tests are quite slow, so don't run for many frames.  256 frames
     18      // should be enough to demonstrate that automations are working.
     19      let renderFrames = 256;
     20      let renderDuration = renderFrames / sampleRate;
     21 
     22      let audit = Audit.createTaskRunner();
     23 
     24      // Array of tests for setting the panner positions.  These tests basically
     25      // verify that the position setters for the panner and listener are
     26      // working correctly.
     27      let testConfig = [
     28        {
     29          setter: 'positionX',
     30        },
     31        {
     32          setter: 'positionY',
     33        },
     34        {
     35          setter: 'positionZ',
     36        }
     37      ];
     38 
     39      // Create tests for the panner position setters.  Both mono and steroe
     40      // sources are tested.
     41      for (let k = 0; k < testConfig.length; ++k) {
     42        let config = testConfig[k];
     43        // Function to create the test to define the test.
     44        let tester = function(config, channelCount) {
     45          return (task, should) => {
     46            let nodes = createGraph(channelCount);
     47            let {context, source, panner} = nodes;
     48 
     49            let message = channelCount == 1 ? 'Mono' : 'Stereo';
     50            message += ' panner.' + config.setter;
     51 
     52            testPositionSetter(should, {
     53              nodes: nodes,
     54              pannerSetter: panner[config.setter],
     55              message: message
     56            }).then(() => task.done());
     57          }
     58        };
     59 
     60        audit.define('Stereo panner.' + config.setter, tester(config, 2));
     61        audit.define('Mono panner.' + config.setter, tester(config, 1));
     62      }
     63 
     64      // Create tests for the listener position setters.  Both mono and steroe
     65      // sources are tested.
     66      for (let k = 0; k < testConfig.length; ++k) {
     67        let config = testConfig[k];
     68        // Function to create the test to define the test.
     69        let tester = function(config, channelCount) {
     70          return (task, should) => {
     71            let nodes = createGraph(channelCount);
     72            let {context, source, panner} = nodes;
     73 
     74            let message = channelCount == 1 ? 'Mono' : 'Stereo';
     75            message += ' listener.' + config.setter;
     76 
     77            // Some relatively arbitrary (non-default) position for the source
     78            // location.
     79            panner.setPosition(1, 0, 1);
     80 
     81            testPositionSetter(should, {
     82              nodes: nodes,
     83              pannerSetter: context.listener[config.setter],
     84              message: message
     85            }).then(() => task.done());
     86          }
     87        };
     88 
     89        audit.define('Stereo listener.' + config.setter, tester(config, 2));
     90        audit.define('Mono listener.' + config.setter, tester(config, 1));
     91      }
     92 
     93      // Test setPosition method.
     94      audit.define('setPosition', (task, should) => {
     95        let {context, panner, source} = createGraph(2);
     96 
     97        // Initialize source position (values don't really matter).
     98        panner.setPosition(1, 1, 1);
     99 
    100        // After some (unimportant) time, move the panner to a (any) new
    101        // location.
    102        let suspendFrame = 128;
    103        context.suspend(suspendFrame / sampleRate)
    104            .then(function() {
    105              panner.setPosition(-100, 2000, 8000);
    106            })
    107            .then(context.resume.bind(context));
    108 
    109        context.startRendering()
    110            .then(function(resultBuffer) {
    111              verifyPannerOutputChanged(
    112                  should, resultBuffer,
    113                  {message: 'setPosition', suspendFrame: suspendFrame});
    114            })
    115            .then(() => task.done());
    116      });
    117 
    118      audit.define('orientation setter', (task, should) => {
    119        let {context, panner, source} = createGraph(2);
    120 
    121        // For orientation to matter, we need to make the source directional,
    122        // and also move away from the listener (because the default location is
    123        // 0,0,0).
    124        panner.setPosition(0, 0, 1);
    125        panner.coneInnerAngle = 0;
    126        panner.coneOuterAngle = 360;
    127        panner.coneOuterGain = .001;
    128 
    129        // After some (unimportant) time, change the panner orientation to a new
    130        // orientation.  The only constraint is that the orientation changes
    131        // from before.
    132        let suspendFrame = 128;
    133        context.suspend(suspendFrame / sampleRate)
    134            .then(function() {
    135              panner.orientationX.value = -100;
    136              panner.orientationY.value = 2000;
    137              panner.orientationZ.value = 8000;
    138            })
    139            .then(context.resume.bind(context));
    140 
    141        context.startRendering()
    142            .then(function(resultBuffer) {
    143              verifyPannerOutputChanged(should, resultBuffer, {
    144                message: 'panner.orientation{XYZ}',
    145                suspendFrame: suspendFrame
    146              });
    147            })
    148            .then(() => task.done());
    149      });
    150 
    151      audit.define('forward setter', (task, should) => {
    152        let {context, panner, source} = createGraph(2);
    153 
    154        // For orientation to matter, we need to make the source directional,
    155        // and also move away from the listener (because the default location is
    156        // 0,0,0).
    157        panner.setPosition(0, 0, 1);
    158        panner.coneInnerAngle = 0;
    159        panner.coneOuterAngle = 360;
    160        panner.coneOuterGain = .001;
    161 
    162        // After some (unimportant) time, change the panner orientation to a new
    163        // orientation.  The only constraint is that the orientation changes
    164        // from before.
    165        let suspendFrame = 128;
    166        context.suspend(suspendFrame / sampleRate)
    167            .then(function() {
    168              context.listener.forwardX.value = -100;
    169              context.listener.forwardY.value = 2000;
    170              context.listener.forwardZ.value = 8000;
    171            })
    172            .then(context.resume.bind(context));
    173 
    174        context.startRendering()
    175            .then(function(resultBuffer) {
    176              verifyPannerOutputChanged(should, resultBuffer, {
    177                message: 'listener.forward{XYZ}',
    178                suspendFrame: suspendFrame
    179              });
    180            })
    181            .then(() => task.done());
    182      });
    183 
    184      audit.define('up setter', (task, should) => {
    185        let {context, panner, source} = createGraph(2);
    186 
    187        // For orientation to matter, we need to make the source directional,
    188        // and also move away from the listener (because the default location is
    189        // 0,0,0).
    190        panner.setPosition(0, 0, 1);
    191        panner.coneInnerAngle = 0;
    192        panner.coneOuterAngle = 360;
    193        panner.coneOuterGain = .001;
    194        panner.setPosition(1, 0, 1);
    195 
    196        // After some (unimportant) time, change the panner orientation to a new
    197        // orientation.  The only constraint is that the orientation changes
    198        // from before.
    199        let suspendFrame = 128;
    200        context.suspend(suspendFrame / sampleRate)
    201            .then(function() {
    202              context.listener.upX.value = 100;
    203              context.listener.upY.value = 100;
    204              context.listener.upZ.value = 100;
    205              ;
    206            })
    207            .then(context.resume.bind(context));
    208 
    209        context.startRendering()
    210            .then(function(resultBuffer) {
    211              verifyPannerOutputChanged(
    212                  should, resultBuffer,
    213                  {message: 'listener.up{XYZ}', suspendFrame: suspendFrame});
    214            })
    215            .then(() => task.done());
    216      });
    217 
    218      audit.run();
    219 
    220      function createGraph(channelCount) {
    221        let context = new OfflineAudioContext(2, renderFrames, sampleRate);
    222        let panner = context.createPanner();
    223        let source = context.createBufferSource();
    224        source.buffer =
    225            createConstantBuffer(context, 1, channelCount == 1 ? 1 : [1, 2]);
    226        source.loop = true;
    227 
    228        source.connect(panner);
    229        panner.connect(context.destination);
    230 
    231        source.start();
    232        return {context: context, source: source, panner: panner};
    233      }
    234 
    235      function testPositionSetter(should, options) {
    236        let {nodes, pannerSetter, message} = options;
    237 
    238        let {context, source, panner} = nodes;
    239 
    240        // Set panner x position. (Value doesn't matter);
    241        pannerSetter.value = 1;
    242 
    243        // Wait a bit and set a new position.  (Actual time and position doesn't
    244        // matter).
    245        let suspendFrame = 128;
    246        context.suspend(suspendFrame / sampleRate)
    247            .then(function() {
    248              pannerSetter.value = 10000;
    249            })
    250            .then(context.resume.bind(context));
    251 
    252        return context.startRendering().then(function(resultBuffer) {
    253          verifyPannerOutputChanged(
    254              should, resultBuffer,
    255              {message: message, suspendFrame: suspendFrame});
    256        });
    257      }
    258 
    259      function verifyPannerOutputChanged(should, resultBuffer, options) {
    260        let {message, suspendFrame} = options;
    261        // Verify that the first part of output is constant. (Doesn't matter
    262        // what.)
    263        let data0 = resultBuffer.getChannelData(0);
    264        let data1 = resultBuffer.getChannelData(1);
    265 
    266        let middle = '[0, ' + suspendFrame + ') ';
    267        should(
    268            data0.slice(0, suspendFrame),
    269            message + '.value frame ' + middle + 'channel 0')
    270            .beConstantValueOf(data0[0]);
    271        should(
    272            data1.slice(0, suspendFrame),
    273            message + '.value frame ' + middle + 'channel 1')
    274            .beConstantValueOf(data1[0]);
    275 
    276        // The rest after suspendTime should be constant and different from the
    277        // first part.
    278        middle = '[' + suspendFrame + ', ' + renderFrames + ') ';
    279        should(
    280            data0.slice(suspendFrame),
    281            message + '.value frame ' + middle + 'channel 0')
    282            .beConstantValueOf(data0[suspendFrame]);
    283        should(
    284            data1.slice(suspendFrame),
    285            message + '.value frame ' + middle + 'channel 1')
    286            .beConstantValueOf(data1[suspendFrame]);
    287        should(
    288            data0[suspendFrame],
    289            message + ': Output at frame ' + suspendFrame + ' channel 0')
    290            .notBeEqualTo(data0[0]);
    291        should(
    292            data1[suspendFrame],
    293            message + ': Output at frame ' + suspendFrame + ' channel 1')
    294            .notBeEqualTo(data1[0]);
    295      }
    296    </script>
    297  </body>
    298 </html>