5 <script src=
"../resources/js-test.js"></script>
6 <script src=
"resources/compatibility.js"></script>
7 <script type=
"text/javascript" src=
"resources/audio-testing.js"></script>
8 <script type=
"text/javascript" src=
"resources/buffer-loader.js"></script>
13 <div id=
"description"></div>
14 <div id=
"console"></div>
17 description("Tests that WaveShaperNode applies proper non-linear distortion.");
19 var sampleRate
= 44100;
20 var lengthInSeconds
= 4;
21 var numberOfRenderFrames
= sampleRate
* lengthInSeconds
;
22 var numberOfCurveFrames
= 65536;
28 function generateInputBuffer() {
29 // Create mono input buffer.
30 var buffer
= context
.createBuffer(1, numberOfRenderFrames
, context
.sampleRate
);
31 var data
= buffer
.getChannelData(0);
33 // Generate an input vector with values from -1 -> +1 over a duration of lengthInSeconds.
34 // This exercises the full nominal input range and will touch every point of the shaping curve.
35 for (var i
= 0; i
< numberOfRenderFrames
; ++i
) {
36 var x
= i
/ numberOfRenderFrames
; // 0 -> 1
37 x
= 2 * x
- 1; // -1 -> +1
44 // Generates a symmetric curve: Math.atan(5 * x) / (0.5 * Math.PI)
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 test,
48 // since the input vector walks through all possible curve values.
49 function generateWaveShapingCurve() {
50 var curve
= new Float32Array(numberOfCurveFrames
);
52 var n
= numberOfCurveFrames
;
55 for (var i
= 0; i
< n
; ++i
) {
56 var x
= (i
- n2
) / n2
;
57 var y
= Math
.atan(5 * x
) / (0.5 * Math
.PI
);
63 function checkShapedCurve(event
) {
64 var buffer
= event
.renderedBuffer
;
66 var inputData
= inputBuffer
.getChannelData(0);
67 var outputData
= buffer
.getChannelData(0);
71 // Go through every sample and make sure it has been shaped exactly according to the shaping curve we gave it.
72 for (var i
= 0; i
< buffer
.length
; ++i
) {
73 var input
= inputData
[i
];
75 // Calculate an index based on input -1 -> +1 with 0 being at the center of the curve data.
76 var index
= Math
.floor(numberOfCurveFrames
* 0.5 * (input
+ 1));
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
= index
> numberOfCurveFrames
- 1 ? numberOfCurveFrames
- 1 : index
;
83 var expectedOutput
= waveShapingCurve
[index
];
85 var output
= outputData
[i
];
87 if (output
!= expectedOutput
) {
94 testPassed("WaveShaperNode properly applied non-linear distortion.");
96 testFailed("WaveShaperNode did not properly apply non-linear distortion.");
103 if (window
.testRunner
) {
104 testRunner
.dumpAsText();
105 testRunner
.waitUntilDone();
108 window
.jsTestIsAsync
= true;
110 // Create offline audio context.
111 context
= new OfflineAudioContext(1, numberOfRenderFrames
, sampleRate
);
113 // source -> waveshaper -> destination
114 var source
= context
.createBufferSource();
115 var waveshaper
= context
.createWaveShaper();
116 source
.connect(waveshaper
);
117 waveshaper
.connect(context
.destination
);
119 // Create an input test vector.
120 inputBuffer
= generateInputBuffer();
121 source
.buffer
= inputBuffer
;
123 // We'll apply non-linear distortion according to this shaping curve.
124 waveShapingCurve
= generateWaveShapingCurve();
125 waveshaper
.curve
= waveShapingCurve
;
129 context
.oncomplete
= checkShapedCurve
;
130 context
.startRendering();