| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <html> |
| 3 <head> |
| 4 <title> |
| 5 waveshaper.html |
| 6 </title> |
| 7 <script src="../../resources/testharness.js"></script> |
| 8 <script src="../../resources/testharnessreport.js"></script> |
| 9 <script src="../resources/audit-util.js"></script> |
| 10 <script src="../resources/audit.js"></script> |
| 11 <script src="../resources/buffer-loader.js"></script> |
| 12 </head> |
| 13 <body> |
| 14 <script id="layout-test-code"> |
| 15 let audit = Audit.createTaskRunner(); |
| 2 | 16 |
| 3 <html> | 17 let sampleRate = 44100; |
| 4 <head> | 18 let lengthInSeconds = 4; |
| 5 <script src="../../resources/testharness.js"></script> | 19 let numberOfRenderFrames = sampleRate * lengthInSeconds; |
| 6 <script src="../../resources/testharnessreport.js"></script> | 20 let numberOfCurveFrames = 65536; |
| 7 <script src="../resources/audit-util.js"></script> | 21 let inputBuffer; |
| 8 <script src="../resources/audit.js"></script> | 22 let waveShapingCurve; |
| 9 <script type="text/javascript" src="../resources/buffer-loader.js"></script> | |
| 10 </head> | |
| 11 | 23 |
| 12 <body> | 24 let context; |
| 13 <script> | |
| 14 var audit = Audit.createTaskRunner(); | |
| 15 | 25 |
| 16 var sampleRate = 44100; | 26 function generateInputBuffer() { |
| 17 var lengthInSeconds = 4; | 27 // Create mono input buffer. |
| 18 var numberOfRenderFrames = sampleRate * lengthInSeconds; | 28 let buffer = |
| 19 var numberOfCurveFrames = 65536; | 29 context.createBuffer(1, numberOfRenderFrames, context.sampleRate); |
| 20 var inputBuffer; | 30 let data = buffer.getChannelData(0); |
| 21 var waveShapingCurve; | |
| 22 | 31 |
| 23 var context; | 32 // Generate an input vector with values from -1 -> +1 over a duration of |
| 33 // lengthInSeconds. This exercises the full nominal input range and will |
| 34 // touch every point of the shaping curve. |
| 35 for (let i = 0; i < numberOfRenderFrames; ++i) { |
| 36 let x = i / numberOfRenderFrames; // 0 -> 1 |
| 37 x = 2 * x - 1; // -1 -> +1 |
| 38 data[i] = x; |
| 39 } |
| 24 | 40 |
| 25 function generateInputBuffer() { | 41 return buffer; |
| 26 // Create mono input buffer. | 42 } |
| 27 var buffer = context.createBuffer(1, numberOfRenderFrames, context.sampleRat
e); | |
| 28 var data = buffer.getChannelData(0); | |
| 29 | |
| 30 // Generate an input vector with values from -1 -> +1 over a duration of len
gthInSeconds. | |
| 31 // This exercises the full nominal input range and will touch every point of
the shaping curve. | |
| 32 for (var i = 0; i < numberOfRenderFrames; ++i) { | |
| 33 var x = i / numberOfRenderFrames; // 0 -> 1 | |
| 34 x = 2 * x - 1; // -1 -> +1 | |
| 35 data[i] = x; | |
| 36 } | |
| 37 | 43 |
| 38 return buffer; | 44 // Generates a symmetric curve: Math.atan(5 * x) / (0.5 * Math.PI) |
| 39 } | 45 // (with x == 0 corresponding to the center of the array) |
| 46 // This curve is arbitrary, but would be useful in the real-world. |
| 47 // To some extent, the actual curve we choose is not important in this |
| 48 // test, since the input vector walks through all possible curve values. |
| 49 function generateWaveShapingCurve() { |
| 50 let curve = new Float32Array(numberOfCurveFrames); |
| 40 | 51 |
| 41 // Generates a symmetric curve: Math.atan(5 * x) / (0.5 * Math.PI) | 52 let n = numberOfCurveFrames; |
| 42 // (with x == 0 corresponding to the center of the array) | 53 let n2 = n / 2; |
| 43 // This curve is arbitrary, but would be useful in the real-world. | |
| 44 // To some extent, the actual curve we choose is not important in this test, | |
| 45 // since the input vector walks through all possible curve values. | |
| 46 function generateWaveShapingCurve() { | |
| 47 var curve = new Float32Array(numberOfCurveFrames); | |
| 48 | |
| 49 var n = numberOfCurveFrames; | |
| 50 var n2 = n / 2; | |
| 51 | |
| 52 for (var i = 0; i < n; ++i) { | |
| 53 var x = (i - n2) / n2; | |
| 54 var y = Math.atan(5 * x) / (0.5 * Math.PI); | |
| 55 } | |
| 56 | 54 |
| 57 return curve; | 55 for (let i = 0; i < n; ++i) { |
| 58 } | 56 let x = (i - n2) / n2; |
| 57 let y = Math.atan(5 * x) / (0.5 * Math.PI); |
| 58 } |
| 59 | 59 |
| 60 function checkShapedCurve(buffer, should) { | 60 return curve; |
| 61 var inputData = inputBuffer.getChannelData(0); | 61 } |
| 62 var outputData = buffer.getChannelData(0); | |
| 63 | 62 |
| 64 var success = true; | 63 function checkShapedCurve(buffer, should) { |
| 65 | 64 let inputData = inputBuffer.getChannelData(0); |
| 66 // Go through every sample and make sure it has been shaped exactly accordin
g to the shaping curve we gave it. | 65 let outputData = buffer.getChannelData(0); |
| 67 for (var i = 0; i < buffer.length; ++i) { | |
| 68 var input = inputData[i]; | |
| 69 | |
| 70 // Calculate an index based on input -1 -> +1 with 0 being at the center
of the curve data. | |
| 71 var index = Math.floor(numberOfCurveFrames * 0.5 * (input + 1)); | |
| 72 | 66 |
| 73 // Clip index to the input range of the curve. | 67 let success = true; |
| 74 // This takes care of input outside of nominal range -1 -> +1 | |
| 75 index = index < 0 ? 0 : index; | |
| 76 index = index > numberOfCurveFrames - 1 ? numberOfCurveFrames - 1 : inde
x; | |
| 77 | 68 |
| 78 var expectedOutput = waveShapingCurve[index]; | 69 // Go through every sample and make sure it has been shaped exactly |
| 79 | 70 // according to the shaping curve we gave it. |
| 80 var output = outputData[i]; | 71 for (let i = 0; i < buffer.length; ++i) { |
| 81 | 72 let input = inputData[i]; |
| 82 if (output != expectedOutput) { | 73 |
| 74 // Calculate an index based on input -1 -> +1 with 0 being at the |
| 75 // center of the curve data. |
| 76 let index = Math.floor(numberOfCurveFrames * 0.5 * (input + 1)); |
| 77 |
| 78 // Clip index to the input range of the curve. |
| 79 // This takes care of input outside of nominal range -1 -> +1 |
| 80 index = index < 0 ? 0 : index; |
| 81 index = |
| 82 index > numberOfCurveFrames - 1 ? numberOfCurveFrames - 1 : index; |
| 83 |
| 84 let expectedOutput = waveShapingCurve[index]; |
| 85 |
| 86 let output = outputData[i]; |
| 87 |
| 88 if (output != expectedOutput) { |
| 83 success = false; | 89 success = false; |
| 84 break; | 90 break; |
| 91 } |
| 85 } | 92 } |
| 86 } | |
| 87 | 93 |
| 88 should(success, "WaveShaperNode applied non-linear distortion correctly") | 94 should( |
| 89 .beTrue(); | 95 success, 'WaveShaperNode applied non-linear distortion correctly') |
| 90 } | 96 .beTrue(); |
| 97 } |
| 91 | 98 |
| 92 audit.define("test", function (task, should) { | 99 audit.define('test', function(task, should) { |
| 93 // Create offline audio context. | 100 // Create offline audio context. |
| 94 context = new OfflineAudioContext(1, numberOfRenderFrames, sampleRate); | 101 context = new OfflineAudioContext(1, numberOfRenderFrames, sampleRate); |
| 95 | |
| 96 // source -> waveshaper -> destination | |
| 97 var source = context.createBufferSource(); | |
| 98 var waveshaper = context.createWaveShaper(); | |
| 99 source.connect(waveshaper); | |
| 100 waveshaper.connect(context.destination); | |
| 101 | 102 |
| 102 // Create an input test vector. | 103 // source -> waveshaper -> destination |
| 103 inputBuffer = generateInputBuffer(); | 104 let source = context.createBufferSource(); |
| 104 source.buffer = inputBuffer; | 105 let waveshaper = context.createWaveShaper(); |
| 105 | 106 source.connect(waveshaper); |
| 106 // We'll apply non-linear distortion according to this shaping curve. | 107 waveshaper.connect(context.destination); |
| 107 waveShapingCurve = generateWaveShapingCurve(); | |
| 108 waveshaper.curve = waveShapingCurve; | |
| 109 | |
| 110 source.start(0); | |
| 111 | |
| 112 context.startRendering() | |
| 113 .then(buffer => checkShapedCurve(buffer, should)) | |
| 114 .then(task.done.bind(task)); | |
| 115 }); | |
| 116 | 108 |
| 117 audit.run(); | 109 // Create an input test vector. |
| 110 inputBuffer = generateInputBuffer(); |
| 111 source.buffer = inputBuffer; |
| 118 | 112 |
| 119 </script> | 113 // We'll apply non-linear distortion according to this shaping curve. |
| 114 waveShapingCurve = generateWaveShapingCurve(); |
| 115 waveshaper.curve = waveShapingCurve; |
| 120 | 116 |
| 121 </body> | 117 source.start(0); |
| 118 |
| 119 context.startRendering() |
| 120 .then(buffer => checkShapedCurve(buffer, should)) |
| 121 .then(task.done.bind(task)); |
| 122 }); |
| 123 |
| 124 audit.run(); |
| 125 </script> |
| 126 </body> |
| 122 </html> | 127 </html> |
| OLD | NEW |