tor-browser

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

k-rate-panner-connections.html (8917B)


      1 <!doctype html>
      2 <html>
      3  <head>
      4    <title>
      5      k-rate AudioParams with inputs for PannerNode
      6    </title>
      7    <script src="/resources/testharness.js"></script>
      8    <script src="/resources/testharnessreport.js"></script>
      9    <script src="/webaudio/resources/audit.js"></script>
     10    <script src="/webaudio/resources/audit-util.js"></script>
     11    </title>
     12  </head>
     13 
     14  <body>
     15    <script>
     16      let audit = Audit.createTaskRunner();
     17 
     18      audit.define(
     19          {label: 'Panner x', description: 'k-rate input'},
     20          async (task, should) => {
     21            await testPannerParams(should, {param: 'positionX'});
     22            task.done();
     23          });
     24 
     25      audit.define(
     26          {label: 'Panner y', description: 'k-rate input'},
     27          async (task, should) => {
     28            await testPannerParams(should, {param: 'positionY'});
     29            task.done();
     30          });
     31 
     32      audit.define(
     33          {label: 'Panner z', description: 'k-rate input'},
     34          async (task, should) => {
     35            await testPannerParams(should, {param: 'positionZ'});
     36            task.done();
     37          });
     38 
     39      audit.define(
     40          {label: 'Listener x', description: 'k-rate input'},
     41          async (task, should) => {
     42            await testListenerParams(should, {param: 'positionX'});
     43            task.done();
     44          });
     45 
     46      audit.define(
     47          {label: 'Listener y', description: 'k-rate input'},
     48          async (task, should) => {
     49            await testListenerParams(should, {param: 'positionY'});
     50            task.done();
     51          });
     52 
     53      audit.define(
     54          {label: 'Listener z', description: 'k-rate input'},
     55          async (task, should) => {
     56            await testListenerParams(should, {param: 'positionZ'});
     57            task.done();
     58          });
     59 
     60      audit.run();
     61 
     62      async function testPannerParams(should, options) {
     63        // Arbitrary sample rate and duration.
     64        const sampleRate = 8000;
     65        const testFrames = 5 * RENDER_QUANTUM_FRAMES;
     66        let testDuration = testFrames / sampleRate;
     67        // Four channels needed because the first two are for the output of
     68        // the reference panner, and the next two are for the test panner.
     69        let context = new OfflineAudioContext({
     70          numberOfChannels: 4,
     71          sampleRate: sampleRate,
     72          length: testDuration * sampleRate
     73        });
     74 
     75        let merger = new ChannelMergerNode(
     76            context, {numberOfInputs: context.destination.channelCount});
     77        merger.connect(context.destination);
     78 
     79        // Create a stereo source out of two mono sources
     80        let src0 = new ConstantSourceNode(context, {offset: 1});
     81        let src1 = new ConstantSourceNode(context, {offset: 2});
     82        let src = new ChannelMergerNode(context, {numberOfInputs: 2});
     83        src0.connect(src, 0, 0);
     84        src1.connect(src, 0, 1);
     85 
     86        let finalPosition = 100;
     87 
     88        // Reference panner node with k-rate AudioParam automations.  The
     89        // output of this panner is the reference output.
     90        let refNode = new PannerNode(context);
     91        // Initialize the panner location to somewhat arbitrary values.
     92        refNode.positionX.value = 1;
     93        refNode.positionY.value = 50;
     94        refNode.positionZ.value = -25;
     95 
     96        // Set the AudioParam under test with the appropriate automations.
     97        refNode[options.param].automationRate = 'k-rate';
     98        refNode[options.param].setValueAtTime(1, 0);
     99        refNode[options.param].linearRampToValueAtTime(
    100            finalPosition, testDuration);
    101        let refSplit = new ChannelSplitterNode(context, {numberOfOutputs: 2});
    102 
    103        // Test panner node with k-rate AudioParam with inputs.
    104        let tstNode = new PannerNode(context);
    105        tstNode.positionX.value = 1;
    106        tstNode.positionY.value = 50;
    107        tstNode.positionZ.value = -25;
    108        tstNode[options.param].value = 0;
    109        tstNode[options.param].automationRate = 'k-rate';
    110        let tstSplit = new ChannelSplitterNode(context, {numberOfOutputs: 2});
    111 
    112        // The input to the AudioParam.  It must have the same automation
    113        // sequence as used by refNode.  And must be a-rate to demonstrate
    114        // the k-rate effect of the AudioParam.
    115        let mod = new ConstantSourceNode(context, {offset: 0});
    116        mod.offset.setValueAtTime(1, 0);
    117        mod.offset.linearRampToValueAtTime(finalPosition, testDuration);
    118 
    119        mod.connect(tstNode[options.param]);
    120 
    121        src.connect(refNode).connect(refSplit);
    122        src.connect(tstNode).connect(tstSplit);
    123 
    124        refSplit.connect(merger, 0, 0);
    125        refSplit.connect(merger, 1, 1);
    126        tstSplit.connect(merger, 0, 2);
    127        tstSplit.connect(merger, 1, 3);
    128 
    129        mod.start();
    130        src0.start();
    131        src1.start();
    132 
    133        const buffer = await context.startRendering();
    134        let expected0 = buffer.getChannelData(0);
    135        let expected1 = buffer.getChannelData(1);
    136        let actual0 = buffer.getChannelData(2);
    137        let actual1 = buffer.getChannelData(3);
    138 
    139        should(expected0, `Panner: ${options.param}: Expected output channel 0`)
    140            .notBeConstantValueOf(expected0[0]);
    141        should(expected1, `${options.param}: Expected output channel 1`)
    142            .notBeConstantValueOf(expected1[0]);
    143 
    144        // Verify output is a stair step because positionX is k-rate,
    145        // and no other AudioParam is changing.
    146 
    147        for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
    148          should(
    149              actual0.slice(k, k + RENDER_QUANTUM_FRAMES),
    150              `Panner: ${options.param}: Channel 0 output[${k}, ${
    151                  k + RENDER_QUANTUM_FRAMES - 1}]`)
    152              .beConstantValueOf(actual0[k]);
    153        }
    154 
    155        for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
    156          should(
    157              actual1.slice(k, k + RENDER_QUANTUM_FRAMES),
    158              `Panner: ${options.param}: Channel 1 output[${k}, ${
    159                  k + RENDER_QUANTUM_FRAMES - 1}]`)
    160              .beConstantValueOf(actual1[k]);
    161        }
    162 
    163        should(actual0, `Panner: ${options.param}: Actual output channel 0`)
    164            .beCloseToArray(expected0, {absoluteThreshold: 0});
    165        should(actual1, `Panner: ${options.param}: Actual output channel 1`)
    166            .beCloseToArray(expected1, {absoluteThreshold: 0});
    167      }
    168 
    169      async function testListenerParams(should, options) {
    170        // Arbitrary sample rate and duration.
    171        const sampleRate = 8000;
    172        const testFrames = 5 * RENDER_QUANTUM_FRAMES;
    173        let testDuration = testFrames / sampleRate;
    174        // Four channels needed because the first two are for the output of
    175        // the reference panner, and the next two are for the test panner.
    176        let context = new OfflineAudioContext({
    177          numberOfChannels: 2,
    178          sampleRate: sampleRate,
    179          length: testDuration * sampleRate
    180        });
    181 
    182        // Create a stereo source out of two mono sources
    183        let src0 = new ConstantSourceNode(context, {offset: 1});
    184        let src1 = new ConstantSourceNode(context, {offset: 2});
    185        let src = new ChannelMergerNode(context, {numberOfInputs: 2});
    186        src0.connect(src, 0, 0);
    187        src1.connect(src, 0, 1);
    188 
    189        let finalPosition = 100;
    190 
    191        // Reference panner node with k-rate AudioParam automations.  The
    192        // output of this panner is the reference output.
    193        let panner = new PannerNode(context);
    194        panner.positionX.value = 10;
    195        panner.positionY.value = 50;
    196        panner.positionZ.value = -25;
    197 
    198        src.connect(panner);
    199 
    200        let mod = new ConstantSourceNode(context, {offset: 0});
    201        mod.offset.setValueAtTime(1, 0);
    202        mod.offset.linearRampToValueAtTime(finalPosition, testDuration);
    203 
    204        context.listener[options.param].automationRate = 'k-rate';
    205        mod.connect(context.listener[options.param]);
    206 
    207        panner.connect(context.destination);
    208 
    209        src0.start();
    210        src1.start();
    211        mod.start();
    212 
    213        const buffer = await context.startRendering();
    214        let c0 = buffer.getChannelData(0);
    215        let c1 = buffer.getChannelData(1);
    216 
    217        // Verify output is a stair step because positionX is k-rate,
    218        // and no other AudioParam is changing.
    219 
    220        for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
    221          should(
    222              c0.slice(k, k + RENDER_QUANTUM_FRAMES),
    223              `Listener: ${options.param}: Channel 0 output[${k}, ${
    224                  k + RENDER_QUANTUM_FRAMES - 1}]`)
    225              .beConstantValueOf(c0[k]);
    226        }
    227 
    228        for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
    229          should(
    230              c1.slice(k, k + RENDER_QUANTUM_FRAMES),
    231              `Listener: ${options.param}: Channel 1 output[${k}, ${
    232                  k + RENDER_QUANTUM_FRAMES - 1}]`)
    233              .beConstantValueOf(c1[k]);
    234        }
    235      }
    236    </script>
    237  </body>
    238 </html>