| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 | 2 |
| 3 <!-- | 3 <!-- |
| 4 Create two sources and play them simultaneously. This tests unity-gain summing
of AudioNode inputs. | 4 Create two sources and play them simultaneously. This tests unity-gain summing
of AudioNode inputs. |
| 5 The result should be some laughing playing at the same time as the drumming. | 5 The result should be some laughing playing at the same time as the drumming. |
| 6 --> | 6 --> |
| 7 | 7 |
| 8 <html> | 8 <html> |
| 9 <head> | 9 <head> |
| 10 <script src="../resources/testharness.js"></script> |
| 11 <script src="../resources/testharnessreport.js"></script> |
| 10 <script src="resources/audit-util.js"></script> | 12 <script src="resources/audit-util.js"></script> |
| 11 <script src="resources/audio-testing.js"></script> | 13 <script src="resources/audit.js"></script> |
| 12 <script type="text/javascript" src="resources/buffer-loader.js"></script> | |
| 13 | |
| 14 </head> | 14 </head> |
| 15 <body> | 15 <body> |
| 16 | 16 |
| 17 <script> | 17 <script> |
| 18 let audit = Audit.createTaskRunner(); |
| 18 | 19 |
| 19 window.onload = init; | 20 let sampleRate = 44100.0; |
| 21 let lengthInSeconds = 2; |
| 20 | 22 |
| 21 var sampleRate = 44100.0; | 23 audit.define('test', (task, should) => { |
| 22 var lengthInSeconds = 2; | 24 // Create offline audio context. |
| 25 let context = |
| 26 new OfflineAudioContext(2, sampleRate * lengthInSeconds, sampleRate); |
| 23 | 27 |
| 24 var context = 0; | 28 // Load up audio files and test |
| 25 var bufferLoader = 0; | 29 Promise |
| 30 .all([ |
| 31 // This file is stereo |
| 32 Audit.loadFileFromUrl('resources/hyper-reality/br-jam-loop.wav') |
| 33 .then(response => { return context.decodeAudioData(response); }), |
| 34 // This file is mono |
| 35 Audit.loadFileFromUrl('resources/hyper-reality/laughter.wav') |
| 36 .then(response => { return context.decodeAudioData(response); }), |
| 37 ]) |
| 38 .then(audioBuffers => { |
| 39 // Thresholds are experimentally determined |
| 40 return runTest(context, audioBuffers, should, [ |
| 41 {snrThreshold: Infinity, errorThreshold: 0}, |
| 42 {snrThreshold: Infinity, errorThreshold: 0} |
| 43 ]); |
| 44 }) |
| 45 .then(() => task.done()); |
| 46 }); |
| 26 | 47 |
| 27 function init() { | 48 audit.run(); |
| 28 if (!window.testRunner) | |
| 29 return; | |
| 30 | |
| 31 // Create offline audio context. | |
| 32 context = new OfflineAudioContext(2, sampleRate * lengthInSeconds, sampleRat
e); | |
| 33 | |
| 34 bufferLoader = new BufferLoader( | |
| 35 context, | |
| 36 [ | |
| 37 "resources/hyper-reality/br-jam-loop.wav", | |
| 38 "resources/hyper-reality/laughter.wav", | |
| 39 ], | |
| 40 finishedLoading | |
| 41 ); | |
| 42 | 49 |
| 43 bufferLoader.load(); | 50 function runTest(context, bufferList, should, testThresholds) { |
| 44 testRunner.waitUntilDone(); | 51 should(bufferList.length, 'Number of decoded files').beEqualTo(2); |
| 52 |
| 53 // Create two sources and play them at the same time. |
| 54 let source1 = context.createBufferSource(); |
| 55 let source2 = context.createBufferSource(); |
| 56 source1.buffer = bufferList[0]; |
| 57 source2.buffer = bufferList[1]; |
| 58 |
| 59 source1.connect(context.destination); |
| 60 source2.connect(context.destination); |
| 61 source1.start(0); |
| 62 source2.start(0); |
| 63 |
| 64 // Verify the number of channels in each source and the expected result. |
| 65 should(bufferList[0].numberOfChannels, 'Number of channels in stereo source') |
| 66 .beEqualTo(2); |
| 67 |
| 68 should(bufferList[1].numberOfChannels, 'Number of channels in mono source') |
| 69 .beEqualTo(1); |
| 70 |
| 71 return context.startRendering().then(verifyResult); |
| 45 } | 72 } |
| 46 | 73 |
| 47 function finishedLoading(bufferList) { | 74 function verifyResult(renderedBuffer) { |
| 48 // Create two sources and play them at the same time. | 75 // Test only works if we have a stereo result. |
| 49 var source1 = context.createBufferSource(); | 76 should( |
| 50 var source2 = context.createBufferSource(); | 77 renderedBuffer.numberOfChannels, 'Number of channels in rendered output') |
| 51 source1.buffer = bufferList[0]; | 78 .beEqualTo(2); |
| 52 source2.buffer = bufferList[1]; | 79 |
| 53 | 80 // Note: the source lengths may not match the context length. Create copies |
| 54 source1.connect(context.destination); | 81 // of the sources truncated or zero-filled to the rendering length. |
| 55 source2.connect(context.destination); | 82 |
| 56 source1.start(0); | 83 let stereoSource = new AudioBuffer({ |
| 57 source2.start(0); | 84 length: renderedBuffer.length, |
| 58 | 85 numberOfChannels: 2, |
| 59 context.oncomplete = finishAudioTest; | 86 sampleRate: context.sampleRate |
| 60 context.startRendering(); | 87 }); |
| 88 stereoSource.copyToChannel(bufferList[0].getChannelData(0), 0); |
| 89 stereoSource.copyToChannel(bufferList[0].getChannelData(1), 1); |
| 90 |
| 91 let monoSource = new AudioBuffer({ |
| 92 length: renderedBuffer.length, |
| 93 numberOfChannels: 1, |
| 94 sampleRate: context.sampleRate |
| 95 }); |
| 96 monoSource.copyToChannel(bufferList[1].getChannelData(0), 0); |
| 97 |
| 98 // Compute the expected result buffer0 is stereo and buffer1 is mono. The |
| 99 // result should be stereo, with the mono source implicitly upmixed to |
| 100 // stereo to produce the expected result. |
| 101 let expectedBuffer = new AudioBuffer({ |
| 102 length: renderedBuffer.length, |
| 103 numberOfChannels: 2, |
| 104 sampleRate: context.sampleRate |
| 105 }); |
| 106 |
| 107 let monoData = monoSource.getChannelData(0); |
| 108 for (let c = 0; c < expectedBuffer.numberOfChannels; ++c) { |
| 109 let expectedData = expectedBuffer.getChannelData(c); |
| 110 let stereoData = stereoSource.getChannelData(c); |
| 111 for (let k = 0; k < expectedBuffer.length; ++k) { |
| 112 expectedData[k] = stereoData[k] + monoData[k]; |
| 113 } |
| 114 } |
| 115 |
| 116 // Compare the rendered data with the expected data for each channel. |
| 117 for (let k = 0; k < renderedBuffer.numberOfChannels; ++k) { |
| 118 let actualData = renderedBuffer.getChannelData(k); |
| 119 let expectedData = expectedBuffer.getChannelData(k); |
| 120 let threshold = testThresholds[k]; |
| 121 let snr = 10 * Math.log10(computeSNR(actualData, expectedData)); |
| 122 |
| 123 should(snr, 'SNR for channel ' + k) |
| 124 .beGreaterThanOrEqualTo(threshold.snrThreshold); |
| 125 should(actualData, 'Rendered audio').beCloseToArray(expectedData, { |
| 126 absoluteThreshold: threshold.errorThreshold |
| 127 }); |
| 128 } |
| 61 } | 129 } |
| 62 | |
| 63 </script> | 130 </script> |
| 64 | 131 |
| 65 </body> | 132 </body> |
| 66 </html> | 133 </html> |
| OLD | NEW |