summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webaudio/the-audio-api/the-waveshapernode-interface/curve-tests.html
blob: d09cf78fd84131326b2412fba96a2bf7be82b9b9 (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!doctype html>
<html>
<head>
    <title>WaveShaperNode interface - Curve tests | WebAudio</title>

    <script type="text/javascript" src="/resources/testharness.js"></script>
    <script type="text/javascript" src="/resources/testharnessreport.js"></script>
</head>
<body>
    <div id="log">
    </div>

    <script type="text/javascript">
        var sampleRate=44100.0;
        var tolerance=0.01;

        /*
        Testing that -1, 0 and +1 map correctly to curve (with 1:1 correlation)
        =======================================================================
        From the specification:
            The input signal is nominally within the range -1 -> +1.
            Each input sample within this range will index into the shaping curve with a signal level of zero corresponding
                to the center value of the curve array.
        */
        (function() {
            var threeElementCurve=[2.0, -3.0, 4.0];
            var inputData=[-1.0, 0, 1.0];
            var expectedData=[2.0, -3.0, 4.0];
            executeTest(threeElementCurve, inputData, expectedData, "Testing that -1, 0 and +1 map correctly to curve (with 1:1 correlation)");
        })();

        /*
        Testing interpolation (where inputs don't correlate directly to curve elements)
        ===============================================================================
        From the specification:
            The implementation must perform linear interpolation between adjacent points in the curve.
        */
        (function() {
            var threeElementCurve=[2.0, -3.0, 4.0];
            var inputData=[-0.5, +0.5, +0.75];
            var expectedData=[-0.5, +0.5, +2.25];
            executeTest(threeElementCurve, inputData, expectedData, "Testing interpolation (where inputs don't correlate directly to curve elements)");
        })();

        /*
        Testing out-of-range inputs (should be mapped to the first/last elements of the curve)
        ======================================================================================
        From the specification:
            Any sample value less than -1 will correspond to the first value in the curve array.
            Any sample value greater than +1 will correspond to the last value in the curve array.
        */
        (function() {
            var threeElementCurve=[2.0, -3.0, 4.0];
            var inputData=[-1.5, +1.5];
            var expectedData=[2.0, 4.0];
            executeTest(threeElementCurve, inputData, expectedData, "Testing out-of-range inputs (should be mapped to the first/last elements of the curve)");
        })();

        /*
        Testing a 2-element curve (does not have a middle element)
        ==========================================================
        From the specification:
            Each input sample within this range will index into the shaping curve with a signal level of zero corresponding
                to the center value of the curve array.
            The implementation must perform linear interpolation between adjacent points in the curve.
        */
        (function() {
            var twoElementCurve=[2.0, -2.0];
            var inputData=[-1.0, 0, 1.0];
            var expectedData=[2.0, 0.0, -2.0];
            executeTest(twoElementCurve, inputData, expectedData, "Testing a 2-element curve (does not have a middle element)");
        })();

        /*
        Testing a 4-element curve (does not have a middle element)
        ==========================================================
        From the specification:
            Each input sample within this range will index into the shaping curve with a signal level of zero corresponding
                to the center value of the curve array.
            The implementation must perform linear interpolation between adjacent points in the curve.
        */
        (function() {
            var fourElementCurve=[1.0, 2.0, 4.0, 7.0];
            var inputData=[-1.0, 0, 1.0];
            var expectedData=[1.0, 3.0, 7.0];
            executeTest(fourElementCurve, inputData, expectedData, "Testing a 4-element curve (does not have a middle element)");
        })();

        /*
        Testing a huge curve
        ====================
        From the specification:
            Each input sample within this range will index into the shaping curve with a signal level of zero corresponding
                to the center value of the curve array.
        */
        (function() {
            var bigCurve=[];
            for(var i=0;i<=60000;i++) { bigCurve.push(i/3.5435); }
            var inputData=[-1.0, 0, 1.0];
            var expectedData=[bigCurve[0], bigCurve[30000], bigCurve[60000]];
            executeTest(bigCurve, inputData, expectedData, "Testing a huge curve");
        })();

        /*
        Testing single-element curve (boundary condition)
        =================================================
        From the specification:
            Each input sample within this range will index into the shaping curve with a signal level of zero corresponding
                to the center value of the curve array.
            Any sample value less than -1 will correspond to the first value in the curve array.
            Any sample value greater than +1 will correspond to the last value in the curve array.
            The implementation must perform linear interpolation between adjacent points in the curve.
        */

        /*
        Testing null curve (should return input values)
        ===============================================
        From the specification:
            Initially the curve attribute is null, which means that the WaveShaperNode will pass its input to its output
                without modification.
        */
        (function() {
            var inputData=[-1.0, 0, 1.0, 2.0];
            var expectedData=[-1.0, 0.0, 1.0, 2.0];
            executeTest(null, inputData, expectedData, "Testing null curve (should return input values)");
        })();

        /**
        * Function that does the actual testing (using an asynchronous test).
        * @param {?Array.<number>} curveData - Array containing values for the WaveShaper curve.
        * @param {!Array.<number>} inputData - Array containing values for the input stream.
        * @param {!Array.<number>} expectedData - Array containing expected results for each of the corresponding inputs.
        * @param {!string} testName - Name of the test case.
        */
        function executeTest(curveData, inputData, expectedData, testName) {
            var stTest=async_test("WaveShaperNode - "+testName);
            stTest.step(function() {

                // Create offline audio context.
                var ac=new OfflineAudioContext(1, inputData.length, sampleRate);

                // Create the WaveShaper and its curve.
                var waveShaper=ac.createWaveShaper();
                if(curveData!=null) {
                    var curve=new Float32Array(curveData.length);
                    for(var i=0;i<curveData.length;i++) { curve[i]=curveData[i]; }
                    waveShaper.curve=curve;
                }
                waveShaper.connect(ac.destination);

                // Create buffer containing the input values.
                var inputBuffer=ac.createBuffer(1, Math.max(inputData.length, 2), sampleRate);
                var d=inputBuffer.getChannelData(0);
                for(var i=0;i<inputData.length;i++) { d[i]=inputData[i]; }

                // Play the input buffer through the WaveShaper.
                var src=ac.createBufferSource();
                src.buffer=inputBuffer;
                src.connect(waveShaper);
                src.start();

                // Test the outputs match the expected values.
                ac.oncomplete=stTest.step_func_done(function(ev) {
                    var d=ev.renderedBuffer.getChannelData(0);

                    for(var i=0;i<expectedData.length;i++) {
                        var curveText="null";
                        if(curve!=null) {
                            if(curveData.length<20) {
                                curveText=curveData.join(",");
                            } else {
                                curveText="TooBigToDisplay ("+(curveData.length-1)+" elements)";
                            }
                        }
                        var comment="Input="+inputData[i]+", Curve=["+curveText+"] >>> ";
                        assert_approx_equals(d[i], expectedData[i], tolerance, comment);
                    }
                });
                ac.startRendering();
            });
        }
    </script>
</body>
</html>