summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/k-rate-connections.html
blob: 730f03e5619577abf98c30b5566cddeeccf31551 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<!doctype html>
<html>
  <head>
    <title>k-rate AudioParams with Inputs</title>
    <script src="/resources/testharness.js"></script>
    <script src="/resources/testharnessreport.js"></script>
    <script src="/webaudio/resources/audit-util.js"></script>
    <script src="/webaudio/resources/audit.js"></script>
  </head>

  <body>
    <script>
      let audit = Audit.createTaskRunner();

      // Must be power of two to eliminate round-off
      const sampleRate = 8192;

      // Arbitrary duration that doesn't need to be too long to verify k-rate
      // automations.  Probably should be at least a few render quanta.
      const testDuration = 8 * RENDER_QUANTUM_FRAMES / sampleRate;

      // Test k-rate GainNode.gain is k-rate
      audit.define(
          {label: 'Gain', description: 'k-rate GainNode.gain'},
          (task, should) => {
            let context = new OfflineAudioContext({
              numberOfChannels: 2,
              sampleRate: sampleRate,
              length: testDuration * sampleRate
            });

            let merger = new ChannelMergerNode(
                context, {numberOfInputs: context.destination.channelCount});
            merger.connect(context.destination);

            let src = new ConstantSourceNode(context);

            createTestSubGraph(context, src, merger, 'GainNode', 'gain');

            src.start();
            context.startRendering()
                .then(buffer => {
                  let actual = buffer.getChannelData(0);
                  let expected = buffer.getChannelData(1);

                  for (let k = 0; k < actual.length;
                       k += RENDER_QUANTUM_FRAMES) {
                    should(
                        actual.slice(k, k + RENDER_QUANTUM_FRAMES),
                        `gain[${k}:${k + RENDER_QUANTUM_FRAMES}]`)
                        .beConstantValueOf(expected[k]);
                  }
                })
                .then(() => task.done());
          });

      // Test k-rate StereoPannerNode.pan is k-rate
      audit.define(
          {label: 'StereoPanner', description: 'k-rate StereoPannerNode.pan'},
          (task, should) => {
            let context = new OfflineAudioContext({
              numberOfChannels: 2,
              sampleRate: sampleRate,
              length: testDuration * sampleRate
            });
            let merger = new ChannelMergerNode(
                context, {numberOfInputs: context.destination.channelCount});
            merger.connect(context.destination);

            let src = new ConstantSourceNode(context);

            createTestSubGraph(
                context, src, merger, 'StereoPannerNode', 'pan', {
                  testModSetup: node => {
                    node.offset.setValueAtTime(-1, 0);
                    node.offset.linearRampToValueAtTime(1, testDuration);
                  }
                });

            src.start();
            context.startRendering()
                .then(buffer => {
                  let actual = buffer.getChannelData(0);
                  let expected = buffer.getChannelData(1);

                  for (let k = 0; k < actual.length; k += 128) {
                    should(actual.slice(k, k + 128), `pan[${k}:${k + 128}]`)
                        .beConstantValueOf(expected[k]);
                  }
                })
                .then(() => task.done());
          });

      audit.run();

      function createTestSubGraph(
          context, src, merger, nodeName, paramName, options) {
        // The test node which has its AudioParam set up for k-rate autmoations.
        let tstNode = new window[nodeName](context);

        if (options && options.setups) {
          options.setups(tstNode);
        }
        tstNode[paramName].automationRate = 'k-rate';

        // Modulating signal for the test node.  Just a linear ramp. This is
        // connected to the AudioParam of the tstNode.
        let tstMod = new ConstantSourceNode(context);
        if (options && options.testModSetup) {
          options.testModSetup(tstMod);
        } else {
          tstMod.offset.linearRampToValueAtTime(context.length, testDuration);
        }

        tstMod.connect(tstNode[paramName]);
        src.connect(tstNode).connect(merger, 0, 0);

        // The ref node is the same type of node as the test node, but uses
        // a-rate automation.  However, the modulating signal is k-rate.  This
        // causes the input to the audio param to be constant over a render,
        // which is basically the same as making the audio param be k-rate.
        let refNode = new window[nodeName](context);
        let refMod = new ConstantSourceNode(context);
        refMod.offset.automationRate = 'k-rate';
        if (options && options.testModSetup) {
          options.testModSetup(refMod);
        } else {
          refMod.offset.linearRampToValueAtTime(context.length, testDuration);
        }

        refMod.connect(refNode[paramName]);
        src.connect(refNode).connect(merger, 0, 1);

        tstMod.start();
        refMod.start();
      }
    </script>
  </body>
</html>