| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <html> | 2 <html> |
| 3 | 3 <head> |
| 4 <head> | 4 <title> |
| 5 <script src="../../resources/testharness.js"></script> | 5 audionode-disconnect-audioparam.html |
| 6 <script src="../../resources/testharnessreport.js"></script> | 6 </title> |
| 7 <script src="../resources/audit-util.js"></script> | 7 <script src="../../resources/testharness.js"></script> |
| 8 <script src="../resources/audit.js"></script> | 8 <script src="../../resources/testharnessreport.js"></script> |
| 9 </head> | 9 <script src="../resources/audit-util.js"></script> |
| 10 | 10 <script src="../resources/audit.js"></script> |
| 11 <body> | 11 </head> |
| 12 <script> | 12 <body> |
| 13 | 13 <script id="layout-test-code"> |
| 14 var renderQuantum = 128; | 14 let renderQuantum = 128; |
| 15 | 15 |
| 16 var sampleRate = 44100; | 16 let sampleRate = 44100; |
| 17 var renderDuration = 0.5; | 17 let renderDuration = 0.5; |
| 18 var disconnectTime = 0.5 * renderDuration; | 18 let disconnectTime = 0.5 * renderDuration; |
| 19 | 19 |
| 20 var audit = Audit.createTaskRunner(); | 20 let audit = Audit.createTaskRunner(); |
| 21 | 21 |
| 22 // Calculate the index for disconnection. | 22 // Calculate the index for disconnection. |
| 23 function getDisconnectIndex(disconnectTime) { | 23 function getDisconnectIndex(disconnectTime) { |
| 24 var disconnectIndex = disconnectTime * sampleRate; | 24 let disconnectIndex = disconnectTime * sampleRate; |
| 25 return disconnectIndex -= (disconnectIndex) % renderQuantum; | 25 return disconnectIndex -= (disconnectIndex) % renderQuantum; |
| 26 } | 26 } |
| 27 | 27 |
| 28 // Get the index of value change. | 28 // Get the index of value change. |
| 29 function getValueChangeIndex(array, targetValue) { | 29 function getValueChangeIndex(array, targetValue) { |
| 30 return array.findIndex(function (element, index) { | 30 return array.findIndex(function(element, index) { |
| 31 if (element === targetValue) | 31 if (element === targetValue) |
| 32 return true; | 32 return true; |
| 33 }); |
| 34 } |
| 35 |
| 36 // Task 1: test disconnect(AudioParam) method. |
| 37 audit.define('disconnect(AudioParam)', (task, should) => { |
| 38 |
| 39 // Creates a buffer source with value [1] and then connect it to two |
| 40 // gain nodes in series. The output of the buffer source is lowered by |
| 41 // half |
| 42 // (* 0.5) and then connected to two |.gain| AudioParams in each gain |
| 43 // node. |
| 44 // |
| 45 // (1) bufferSource => gain1 => gain2 |
| 46 // (2) bufferSource => half => gain1.gain |
| 47 // (3) half => gain2.gain |
| 48 // |
| 49 // This graph should produce the output of 2.25 (= 1 * 1.5 * 1.5). After |
| 50 // disconnecting (3), it should produce 1.5. |
| 51 let context = |
| 52 new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate); |
| 53 let source = context.createBufferSource(); |
| 54 let buffer1ch = createConstantBuffer(context, 1, 1); |
| 55 let half = context.createGain(); |
| 56 let gain1 = context.createGain(); |
| 57 let gain2 = context.createGain(); |
| 58 |
| 59 source.buffer = buffer1ch; |
| 60 source.loop = true; |
| 61 half.gain.value = 0.5; |
| 62 |
| 63 source.connect(gain1); |
| 64 gain1.connect(gain2); |
| 65 gain2.connect(context.destination); |
| 66 source.connect(half); |
| 67 |
| 68 // Connecting |half| to both |gain1.gain| and |gain2.gain| amplifies the |
| 69 // signal by 2.25 (= 1.5 * 1.5) because each gain node amplifies the |
| 70 // signal by 1.5 (= 1.0 + 0.5). |
| 71 half.connect(gain1.gain); |
| 72 half.connect(gain2.gain); |
| 73 |
| 74 source.start(); |
| 75 |
| 76 // Schedule the disconnection at the half of render duration. |
| 77 context.suspend(disconnectTime).then(function() { |
| 78 half.disconnect(gain2.gain); |
| 79 context.resume(); |
| 80 }); |
| 81 |
| 82 context.startRendering() |
| 83 .then(function(buffer) { |
| 84 let channelData = buffer.getChannelData(0); |
| 85 let disconnectIndex = getDisconnectIndex(disconnectTime); |
| 86 let valueChangeIndex = getValueChangeIndex(channelData, 1.5); |
| 87 |
| 88 // Expected values are: 1 * 1.5 * 1.5 -> 1 * 1.5 = [2.25, 1.5] |
| 89 should(channelData, 'Channel #0').containValues([2.25, 1.5]); |
| 90 should(valueChangeIndex, 'The index of value change') |
| 91 .beEqualTo(disconnectIndex); |
| 92 |
| 93 }) |
| 94 .then(() => task.done()); |
| 33 }); | 95 }); |
| 34 } | 96 |
| 35 | 97 // Task 2: test disconnect(AudioParam, output) method. |
| 36 // Task 1: test disconnect(AudioParam) method. | 98 audit.define('disconnect(AudioParam, output)', (task, should) => { |
| 37 audit.define('disconnect(AudioParam)', (task, should) => { | 99 |
| 38 | 100 // Create a 2-channel buffer source with [1, 2] in each channel and |
| 39 // Creates a buffer source with value [1] and then connect it to two gain | 101 // make a serial connection through gain1 and gain 2. The make the |
| 40 // nodes in series. The output of the buffer source is lowered by half | 102 // buffer source half with a gain node and connect it to a 2-output |
| 41 // (* 0.5) and then connected to two |.gain| AudioParams in each gain node
. | 103 // splitter. Connect each output to 2 gain AudioParams respectively. |
| 42 // | 104 // |
| 43 // (1) bufferSource => gain1 => gain2 | 105 // (1) bufferSource => gain1 => gain2 |
| 44 // (2) bufferSource => half => gain1.gain | 106 // (2) bufferSource => half => splitter(2) |
| 45 // (3) half => gain2.gain | 107 // (3) splitter#0 => gain1.gain |
| 46 // | 108 // (4) splitter#1 => gain2.gain |
| 47 // This graph should produce the output of 2.25 (= 1 * 1.5 * 1.5). After | 109 // |
| 48 // disconnecting (3), it should produce 1.5. | 110 // This graph should produce 3 (= 1 * 1.5 * 2) and 6 (= 2 * 1.5 * 2) for |
| 49 var context = new OfflineAudioContext(1, renderDuration * sampleRate, samp
leRate); | 111 // each channel. After disconnecting (4), it should output 1.5 and 3. |
| 50 var source = context.createBufferSource(); | 112 let context = |
| 51 var buffer1ch = createConstantBuffer(context, 1, 1); | 113 new OfflineAudioContext(2, renderDuration * sampleRate, sampleRate); |
| 52 var half = context.createGain(); | 114 let source = context.createBufferSource(); |
| 53 var gain1 = context.createGain(); | 115 let buffer2ch = createConstantBuffer(context, 1, [1, 2]); |
| 54 var gain2 = context.createGain(); | 116 let splitter = context.createChannelSplitter(2); |
| 55 | 117 let half = context.createGain(); |
| 56 source.buffer = buffer1ch; | 118 let gain1 = context.createGain(); |
| 57 source.loop = true; | 119 let gain2 = context.createGain(); |
| 58 half.gain.value = 0.5; | 120 |
| 59 | 121 source.buffer = buffer2ch; |
| 60 source.connect(gain1); | 122 source.loop = true; |
| 61 gain1.connect(gain2); | 123 half.gain.value = 0.5; |
| 62 gain2.connect(context.destination); | 124 |
| 63 source.connect(half); | 125 source.connect(gain1); |
| 64 | 126 gain1.connect(gain2); |
| 65 // Connecting |half| to both |gain1.gain| and |gain2.gain| amplifies the | 127 gain2.connect(context.destination); |
| 66 // signal by 2.25 (= 1.5 * 1.5) because each gain node amplifies the signa
l | 128 |
| 67 // by 1.5 (= 1.0 + 0.5). | 129 // |source| originally is [1, 2] but it becomes [0.5, 1] after 0.5 gain. |
| 68 half.connect(gain1.gain); | 130 // Each splitter's output will be applied to |gain1.gain| and |
| 69 half.connect(gain2.gain); | 131 // |gain2.gain| respectively in an additive fashion. |
| 70 | 132 source.connect(half); |
| 71 source.start(); | 133 half.connect(splitter); |
| 72 | 134 |
| 73 // Schedule the disconnection at the half of render duration. | 135 // This amplifies the signal by 1.5. (= 1.0 + 0.5) |
| 74 context.suspend(disconnectTime).then(function () { | 136 splitter.connect(gain1.gain, 0); |
| 75 half.disconnect(gain2.gain); | 137 |
| 76 context.resume(); | 138 // This amplifies the signal by 2. (= 1.0 + 1.0) |
| 139 splitter.connect(gain2.gain, 1); |
| 140 |
| 141 source.start(); |
| 142 |
| 143 // Schedule the disconnection at the half of render duration. |
| 144 context.suspend(disconnectTime).then(function() { |
| 145 splitter.disconnect(gain2.gain, 1); |
| 146 context.resume(); |
| 147 }); |
| 148 |
| 149 context.startRendering() |
| 150 .then(function(buffer) { |
| 151 let channelData0 = buffer.getChannelData(0); |
| 152 let channelData1 = buffer.getChannelData(1); |
| 153 |
| 154 let disconnectIndex = getDisconnectIndex(disconnectTime); |
| 155 let valueChangeIndexCh0 = getValueChangeIndex(channelData0, 1.5); |
| 156 let valueChangeIndexCh1 = getValueChangeIndex(channelData1, 3); |
| 157 |
| 158 // Expected values are: 1 * 1.5 * 2 -> 1 * 1.5 = [3, 1.5] |
| 159 should(channelData0, 'Channel #0').containValues([3, 1.5]); |
| 160 should( |
| 161 valueChangeIndexCh0, |
| 162 'The index of value change in channel #0') |
| 163 .beEqualTo(disconnectIndex); |
| 164 |
| 165 // Expected values are: 2 * 1.5 * 2 -> 2 * 1.5 = [6, 3] |
| 166 should(channelData1, 'Channel #1').containValues([6, 3]); |
| 167 should( |
| 168 valueChangeIndexCh1, |
| 169 'The index of value change in channel #1') |
| 170 .beEqualTo(disconnectIndex); |
| 171 |
| 172 }) |
| 173 .then(() => task.done()); |
| 77 }); | 174 }); |
| 78 | 175 |
| 79 context.startRendering().then(function (buffer) { | 176 // Task 3: exception checks. |
| 80 var channelData = buffer.getChannelData(0); | 177 audit.define('exceptions', (task, should) => { |
| 81 var disconnectIndex = getDisconnectIndex(disconnectTime); | 178 let context = new AudioContext(); |
| 82 var valueChangeIndex = getValueChangeIndex(channelData, 1.5); | 179 let gain1 = context.createGain(); |
| 83 | 180 let splitter = context.createChannelSplitter(2); |
| 84 // Expected values are: 1 * 1.5 * 1.5 -> 1 * 1.5 = [2.25, 1.5] | 181 let gain2 = context.createGain(); |
| 85 should(channelData, 'Channel #0').containValues([2.25, 1.5]); | 182 let gain3 = context.createGain(); |
| 86 should(valueChangeIndex, 'The index of value change') | 183 |
| 87 .beEqualTo(disconnectIndex); | 184 // Connect a splitter to gain nodes and merger so we can test the |
| 88 | 185 // possible ways of disconnecting the nodes to verify that appropriate |
| 89 }).then(() => task.done()); | 186 // exceptions are thrown. |
| 90 }); | 187 gain1.connect(splitter); |
| 91 | 188 splitter.connect(gain2.gain, 0); |
| 92 // Task 2: test disconnect(AudioParam, output) method. | 189 splitter.connect(gain3.gain, 1); |
| 93 audit.define('disconnect(AudioParam, output)', (task, should) => { | 190 gain2.connect(gain3); |
| 94 | 191 gain3.connect(context.destination); |
| 95 // Create a 2-channel buffer source with [1, 2] in each channel and | 192 |
| 96 // make a serial connection through gain1 and gain 2. The make the buffer | 193 // gain1 is not connected to gain3.gain. Exception should be thrown. |
| 97 // source half with a gain node and connect it to a 2-output splitter. | 194 should(function() { |
| 98 // Connect each output to 2 gain AudioParams respectively. | 195 gain1.disconnect(gain3.gain); |
| 99 // | 196 }, 'gain1.disconnect(gain3.gain)').throw('InvalidAccessError'); |
| 100 // (1) bufferSource => gain1 => gain2 | 197 |
| 101 // (2) bufferSource => half => splitter(2) | 198 // When the output index is good but the destination is invalid. |
| 102 // (3) splitter#0 => gain1.gain | 199 should(function() { |
| 103 // (4) splitter#1 => gain2.gain | 200 splitter.disconnect(gain1.gain, 1); |
| 104 // | 201 }, 'splitter.disconnect(gain1.gain, 1)').throw('InvalidAccessError'); |
| 105 // This graph should produce 3 (= 1 * 1.5 * 2) and 6 (= 2 * 1.5 * 2) for | 202 |
| 106 // each channel. After disconnecting (4), it should output 1.5 and 3. | 203 // When both arguments are wrong, throw IndexSizeError first. |
| 107 var context = new OfflineAudioContext(2, renderDuration * sampleRate, samp
leRate); | 204 should(function() { |
| 108 var source = context.createBufferSource(); | 205 splitter.disconnect(gain1.gain, 2); |
| 109 var buffer2ch = createConstantBuffer(context, 1, [1, 2]); | 206 }, 'splitter.disconnect(gain1.gain, 2)').throw('IndexSizeError'); |
| 110 var splitter = context.createChannelSplitter(2); | 207 |
| 111 var half = context.createGain(); | 208 task.done(); |
| 112 var gain1 = context.createGain(); | |
| 113 var gain2 = context.createGain(); | |
| 114 | |
| 115 source.buffer = buffer2ch; | |
| 116 source.loop = true; | |
| 117 half.gain.value = 0.5; | |
| 118 | |
| 119 source.connect(gain1); | |
| 120 gain1.connect(gain2); | |
| 121 gain2.connect(context.destination); | |
| 122 | |
| 123 // |source| originally is [1, 2] but it becomes [0.5, 1] after 0.5 gain. | |
| 124 // Each splitter's output will be applied to |gain1.gain| and |gain2.gain| | |
| 125 // respectively in an additive fashion. | |
| 126 source.connect(half); | |
| 127 half.connect(splitter); | |
| 128 | |
| 129 // This amplifies the signal by 1.5. (= 1.0 + 0.5) | |
| 130 splitter.connect(gain1.gain, 0); | |
| 131 | |
| 132 // This amplifies the signal by 2. (= 1.0 + 1.0) | |
| 133 splitter.connect(gain2.gain, 1); | |
| 134 | |
| 135 source.start(); | |
| 136 | |
| 137 // Schedule the disconnection at the half of render duration. | |
| 138 context.suspend(disconnectTime).then(function () { | |
| 139 splitter.disconnect(gain2.gain, 1); | |
| 140 context.resume(); | |
| 141 }); | 209 }); |
| 142 | 210 |
| 143 context.startRendering().then(function (buffer) { | 211 audit.run(); |
| 144 var channelData0 = buffer.getChannelData(0); | 212 </script> |
| 145 var channelData1 = buffer.getChannelData(1); | 213 </body> |
| 146 | |
| 147 var disconnectIndex = getDisconnectIndex(disconnectTime); | |
| 148 var valueChangeIndexCh0 = getValueChangeIndex(channelData0, 1.5); | |
| 149 var valueChangeIndexCh1 = getValueChangeIndex(channelData1, 3); | |
| 150 | |
| 151 // Expected values are: 1 * 1.5 * 2 -> 1 * 1.5 = [3, 1.5] | |
| 152 should(channelData0, 'Channel #0').containValues([3, 1.5]); | |
| 153 should(valueChangeIndexCh0, 'The index of value change in channel #0') | |
| 154 .beEqualTo(disconnectIndex); | |
| 155 | |
| 156 // Expected values are: 2 * 1.5 * 2 -> 2 * 1.5 = [6, 3] | |
| 157 should(channelData1, 'Channel #1').containValues([6, 3]); | |
| 158 should(valueChangeIndexCh1, 'The index of value change in channel #1') | |
| 159 .beEqualTo(disconnectIndex); | |
| 160 | |
| 161 }).then(() => task.done()); | |
| 162 }); | |
| 163 | |
| 164 // Task 3: exception checks. | |
| 165 audit.define('exceptions', (task, should) => { | |
| 166 var context = new AudioContext(); | |
| 167 var gain1 = context.createGain(); | |
| 168 var splitter = context.createChannelSplitter(2); | |
| 169 var gain2 = context.createGain(); | |
| 170 var gain3 = context.createGain(); | |
| 171 | |
| 172 // Connect a splitter to gain nodes and merger so we can test the possible | |
| 173 // ways of disconnecting the nodes to verify that appropriate exceptions | |
| 174 // are thrown. | |
| 175 gain1.connect(splitter); | |
| 176 splitter.connect(gain2.gain, 0); | |
| 177 splitter.connect(gain3.gain, 1); | |
| 178 gain2.connect(gain3); | |
| 179 gain3.connect(context.destination); | |
| 180 | |
| 181 // gain1 is not connected to gain3.gain. Exception should be thrown. | |
| 182 should(function () { | |
| 183 gain1.disconnect(gain3.gain); | |
| 184 }, 'gain1.disconnect(gain3.gain)').throw('InvalidAccessError'); | |
| 185 | |
| 186 // When the output index is good but the destination is invalid. | |
| 187 should(function () { | |
| 188 splitter.disconnect(gain1.gain, 1); | |
| 189 }, 'splitter.disconnect(gain1.gain, 1)').throw('InvalidAccessError'); | |
| 190 | |
| 191 // When both arguments are wrong, throw IndexSizeError first. | |
| 192 should(function () { | |
| 193 splitter.disconnect(gain1.gain, 2); | |
| 194 }, 'splitter.disconnect(gain1.gain, 2)').throw('IndexSizeError'); | |
| 195 | |
| 196 task.done(); | |
| 197 }); | |
| 198 | |
| 199 audit.run(); | |
| 200 </script> | |
| 201 </body> | |
| 202 | |
| 203 </html> | 214 </html> |
| OLD | NEW |