summaryrefslogtreecommitdiffstats
path: root/dom/media/webaudio/test/test_delayNodeCycles.html
blob: 82c5f6250404af7cb8bfa9ab8902535a6d89eb5c (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<!DOCTYPE HTML>
<html>
<head>
  <title>Test the support of cycles.</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="webaudio.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script src="webaudio.js" type="text/javascript"></script>
<script class="testbody" type="text/javascript">

SimpleTest.waitForExplicitFinish();

const sampleRate = 48000;
const inputLength = 2048;

addLoadEvent(function() {
  function addSine(b) {
    for (var i = 0; i < b.length; i++) {
      b[i] += Math.sin(440 * 2 * Math.PI * i / sampleRate);
    }
  }

  function getSineBuffer(ctx) {
    var buffer = ctx.createBuffer(1, inputLength, ctx.sampleRate);
    addSine(buffer.getChannelData(0));
    return buffer;
  }

  function createAndPlayWithCycleAndDelayNode(ctx, delayFrames) {
    var source = ctx.createBufferSource();
    source.buffer = getSineBuffer(ctx);

    var gain = ctx.createGain();
    var delay = ctx.createDelay();
    delay.delayTime.value = delayFrames/ctx.sampleRate;

    source.connect(gain);
    gain.connect(delay);
    delay.connect(ctx.destination);
    // cycle
    delay.connect(gain);

    source.start(0);
  }

  function createAndPlayWithCycleAndNoDelayNode(ctx) {
    var source = ctx.createBufferSource();
    source.loop = true;
    source.buffer = getSineBuffer(ctx);

    var gain = ctx.createGain();
    var gain2 = ctx.createGain();

    source.connect(gain);
    gain.connect(gain2);
    // cycle
    gain2.connect(gain);
    gain2.connect(ctx.destination);

    source.start(0);
  }

  function createAndPlayWithCycleAndNoDelayNodeInCycle(ctx) {
    var source = ctx.createBufferSource();
    source.loop = true;
    source.buffer = getSineBuffer(ctx);

    var delay = ctx.createDelay();
    var gain = ctx.createGain();
    var gain2 = ctx.createGain();

    // Their is a cycle, a delay, but the delay is not in the cycle.
    source.connect(delay);
    delay.connect(gain);
    gain.connect(gain2);
    // cycle
    gain2.connect(gain);
    gain2.connect(ctx.destination);

    source.start(0);
  }

  var remainingTests = 0;
  function finish() {
    if (--remainingTests == 0) {
      SimpleTest.finish();
    }
  }

  function getOfflineContext(oncomplete) {
    var ctx = new OfflineAudioContext(1, sampleRate, sampleRate);
    ctx.oncomplete = oncomplete;
    return ctx;
  }

  function checkSilentBuffer(e) {
    var buffer = e.renderedBuffer.getChannelData(0);
    for (var i = 0; i < buffer.length; i++) {
      if (buffer[i] != 0.0) {
        ok(false, "buffer should be silent.");
        finish();
        return;
      }
    }
    ok(true, "buffer should be silent.");
    finish();
  }

  function checkNoisyBuffer(e, aDelayFrames) {
    delayFrames = Math.max(128, aDelayFrames);

    var expected = new Float32Array(e.renderedBuffer.length);
    for (var i = delayFrames; i < expected.length; i += delayFrames) {
      addSine(expected.subarray(i, i + inputLength));
    }

    compareChannels(e.renderedBuffer.getChannelData(0), expected);
    finish();
  }

  function expectSilentOutput(f) {
    remainingTests++;
    var ctx = getOfflineContext(checkSilentBuffer);
    f(ctx);
    ctx.startRendering();
  }

  function expectNoisyOutput(delayFrames) {
    remainingTests++;
    var ctx = getOfflineContext();
    ctx.oncomplete = function(e) { checkNoisyBuffer(e, delayFrames); };
    createAndPlayWithCycleAndDelayNode(ctx, delayFrames);
    ctx.startRendering();
  }

  // This is trying to make a graph with a cycle and no DelayNode in the graph.
  // The cycle subgraph should be muted, in this graph the output should be silent.
  expectSilentOutput(createAndPlayWithCycleAndNoDelayNode);
  // This is trying to make a graph with a cycle and a DelayNode in the graph, but
  // not part of the cycle.
  // The cycle subgraph should be muted, in this graph the output should be silent.
  expectSilentOutput(createAndPlayWithCycleAndNoDelayNodeInCycle);
  // Those are making legal graphs, with at least one DelayNode in the cycle.
  // There should be some non-silent output.
  expectNoisyOutput(sampleRate/4);
  // DelayNode.delayTime will be clamped to 128/ctx.sampleRate.
  // There should be some non-silent output.
  expectNoisyOutput(0);
});

</script>
</pre>
</body>
</html>