OLD | NEW |
1 var sampleRate = 44100.0; | 1 var sampleRate = 44100.0; |
2 | 2 |
3 var renderLengthSeconds = 8; | 3 var renderLengthSeconds = 8; |
4 var pulseLengthSeconds = 1; | 4 var pulseLengthSeconds = 1; |
5 var pulseLengthFrames = pulseLengthSeconds * sampleRate; | 5 var pulseLengthFrames = pulseLengthSeconds * sampleRate; |
6 | 6 |
7 function createSquarePulseBuffer(context, sampleFrameLength) { | 7 function createSquarePulseBuffer(context, sampleFrameLength) { |
8 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleR
ate); | 8 let audioBuffer = |
| 9 context.createBuffer(1, sampleFrameLength, context.sampleRate); |
9 | 10 |
10 var n = audioBuffer.length; | 11 let n = audioBuffer.length; |
11 var data = audioBuffer.getChannelData(0); | 12 let data = audioBuffer.getChannelData(0); |
12 | 13 |
13 for (var i = 0; i < n; ++i) | 14 for (let i = 0; i < n; ++i) |
14 data[i] = 1; | 15 data[i] = 1; |
15 | 16 |
16 return audioBuffer; | 17 return audioBuffer; |
17 } | 18 } |
18 | 19 |
19 // The triangle buffer holds the expected result of the convolution. | 20 // The triangle buffer holds the expected result of the convolution. |
20 // It linearly ramps up from 0 to its maximum value (at the center) | 21 // It linearly ramps up from 0 to its maximum value (at the center) |
21 // then linearly ramps down to 0. The center value corresponds to the | 22 // then linearly ramps down to 0. The center value corresponds to the |
22 // point where the two square pulses overlap the most. | 23 // point where the two square pulses overlap the most. |
23 function createTrianglePulseBuffer(context, sampleFrameLength) { | 24 function createTrianglePulseBuffer(context, sampleFrameLength) { |
24 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleR
ate); | 25 let audioBuffer = |
| 26 context.createBuffer(1, sampleFrameLength, context.sampleRate); |
25 | 27 |
26 var n = audioBuffer.length; | 28 let n = audioBuffer.length; |
27 var halfLength = n / 2; | 29 let halfLength = n / 2; |
28 var data = audioBuffer.getChannelData(0); | 30 let data = audioBuffer.getChannelData(0); |
29 | |
30 for (var i = 0; i < halfLength; ++i) | |
31 data[i] = i + 1; | |
32 | 31 |
33 for (var i = halfLength; i < n; ++i) | 32 for (let i = 0; i < halfLength; ++i) |
34 data[i] = n - i - 1; | 33 data[i] = i + 1; |
35 | 34 |
36 return audioBuffer; | 35 for (let i = halfLength; i < n; ++i) |
| 36 data[i] = n - i - 1; |
| 37 |
| 38 return audioBuffer; |
37 } | 39 } |
38 | 40 |
39 function log10(x) { | 41 function log10(x) { |
40 return Math.log(x)/Math.LN10; | 42 return Math.log(x) / Math.LN10; |
41 } | 43 } |
42 | 44 |
43 function linearToDecibel(x) { | 45 function linearToDecibel(x) { |
44 return 20*log10(x); | 46 return 20 * log10(x); |
45 } | 47 } |
46 | 48 |
47 // Verify that the rendered result is very close to the reference | 49 // Verify that the rendered result is very close to the reference |
48 // triangular pulse. | 50 // triangular pulse. |
49 function checkTriangularPulse(rendered, reference, should) { | 51 function checkTriangularPulse(rendered, reference, should) { |
50 var match = true; | 52 let match = true; |
51 var maxDelta = 0; | 53 let maxDelta = 0; |
52 var valueAtMaxDelta = 0; | 54 let valueAtMaxDelta = 0; |
53 var maxDeltaIndex = 0; | 55 let maxDeltaIndex = 0; |
54 | 56 |
55 for (var i = 0; i < reference.length; ++i) { | 57 for (let i = 0; i < reference.length; ++i) { |
56 var diff = rendered[i] - reference[i]; | 58 let diff = rendered[i] - reference[i]; |
57 var x = Math.abs(diff); | 59 let x = Math.abs(diff); |
58 if (x > maxDelta) { | 60 if (x > maxDelta) { |
59 maxDelta = x; | 61 maxDelta = x; |
60 valueAtMaxDelta = reference[i]; | 62 valueAtMaxDelta = reference[i]; |
61 maxDeltaIndex = i; | 63 maxDeltaIndex = i; |
62 } | |
63 } | 64 } |
| 65 } |
64 | 66 |
65 // allowedDeviationFraction was determined experimentally. It | 67 // allowedDeviationFraction was determined experimentally. It |
66 // is the threshold of the relative error at the maximum | 68 // is the threshold of the relative error at the maximum |
67 // difference between the true triangular pulse and the | 69 // difference between the true triangular pulse and the |
68 // rendered pulse. | 70 // rendered pulse. |
69 var allowedDeviationDecibels = -124.41; | 71 let allowedDeviationDecibels = -124.41; |
70 var maxDeviationDecibels = linearToDecibel(maxDelta / valueAtMaxDelta); | 72 let maxDeviationDecibels = linearToDecibel(maxDelta / valueAtMaxDelta); |
71 | 73 |
72 should(maxDeviationDecibels, | 74 should( |
73 "Deviation (in dB) of triangular portion of convolution") | 75 maxDeviationDecibels, |
74 .beLessThanOrEqualTo(allowedDeviationDecibels); | 76 'Deviation (in dB) of triangular portion of convolution') |
| 77 .beLessThanOrEqualTo(allowedDeviationDecibels); |
75 | 78 |
76 return match; | 79 return match; |
77 } | 80 } |
78 | 81 |
79 // Verify that the rendered data is close to zero for the first part | 82 // Verify that the rendered data is close to zero for the first part |
80 // of the tail. | 83 // of the tail. |
81 function checkTail1(data, reference, breakpoint, should) { | 84 function checkTail1(data, reference, breakpoint, should) { |
82 var isZero = true; | 85 let isZero = true; |
83 var tail1Max = 0; | 86 let tail1Max = 0; |
84 | 87 |
85 for (var i = reference.length; i < reference.length + breakpoint; ++i) { | 88 for (let i = reference.length; i < reference.length + breakpoint; ++i) { |
86 var mag = Math.abs(data[i]); | 89 let mag = Math.abs(data[i]); |
87 if (mag > tail1Max) { | 90 if (mag > tail1Max) { |
88 tail1Max = mag; | 91 tail1Max = mag; |
89 } | |
90 } | 92 } |
| 93 } |
91 | 94 |
92 // Let's find the peak of the reference (even though we know a | 95 // Let's find the peak of the reference (even though we know a |
93 // priori what it is). | 96 // priori what it is). |
94 var refMax = 0; | 97 let refMax = 0; |
95 for (var i = 0; i < reference.length; ++i) { | 98 for (let i = 0; i < reference.length; ++i) { |
96 refMax = Math.max(refMax, Math.abs(reference[i])); | 99 refMax = Math.max(refMax, Math.abs(reference[i])); |
97 } | 100 } |
98 | 101 |
99 // This threshold is experimentally determined by examining the | 102 // This threshold is experimentally determined by examining the |
100 // value of tail1MaxDecibels. | 103 // value of tail1MaxDecibels. |
101 var threshold1 = -129.7; | 104 let threshold1 = -129.7; |
102 | 105 |
103 var tail1MaxDecibels = linearToDecibel(tail1Max/refMax); | 106 let tail1MaxDecibels = linearToDecibel(tail1Max / refMax); |
104 should(tail1MaxDecibels, | 107 should(tail1MaxDecibels, 'Deviation in first part of tail of convolutions') |
105 "Deviation in first part of tail of convolutions") | 108 .beLessThanOrEqualTo(threshold1); |
106 .beLessThanOrEqualTo(threshold1); | |
107 | 109 |
108 return isZero; | 110 return isZero; |
109 } | 111 } |
110 | 112 |
111 // Verify that the second part of the tail of the convolution is | 113 // Verify that the second part of the tail of the convolution is |
112 // exactly zero. | 114 // exactly zero. |
113 function checkTail2(data, reference, breakpoint, should) { | 115 function checkTail2(data, reference, breakpoint, should) { |
114 var isZero = true; | 116 let isZero = true; |
115 var tail2Max = 0; | 117 let tail2Max = 0; |
116 // For the second part of the tail, the maximum value should be | 118 // For the second part of the tail, the maximum value should be |
117 // exactly zero. | 119 // exactly zero. |
118 var threshold2 = 0; | 120 let threshold2 = 0; |
119 for (var i = reference.length + breakpoint; i < data.length; ++i) { | 121 for (let i = reference.length + breakpoint; i < data.length; ++i) { |
120 if (Math.abs(data[i]) > 0) { | 122 if (Math.abs(data[i]) > 0) { |
121 isZero = false; | 123 isZero = false; |
122 break; | 124 break; |
123 } | |
124 } | 125 } |
| 126 } |
125 | 127 |
126 should(isZero, | 128 should(isZero, 'Rendered signal after tail of convolution is silent') |
127 "Rendered signal after tail of convolution is silent") | 129 .beTrue(); |
128 .beTrue(); | |
129 | 130 |
130 return isZero; | 131 return isZero; |
131 } | 132 } |
132 | 133 |
133 function checkConvolvedResult(renderedBuffer, trianglePulse, should) { | 134 function checkConvolvedResult(renderedBuffer, trianglePulse, should) { |
134 var referenceData = trianglePulse.getChannelData(0); | 135 let referenceData = trianglePulse.getChannelData(0); |
135 var renderedData = renderedBuffer.getChannelData(0); | 136 let renderedData = renderedBuffer.getChannelData(0); |
136 | 137 |
137 var success = true; | 138 let success = true; |
138 | 139 |
139 // Verify the triangular pulse is actually triangular. | 140 // Verify the triangular pulse is actually triangular. |
140 | 141 |
141 success = success && checkTriangularPulse(renderedData, referenceData, | 142 success = |
142 should); | 143 success && checkTriangularPulse(renderedData, referenceData, should); |
143 | 144 |
144 // Make sure that portion after convolved portion is totally | 145 // Make sure that portion after convolved portion is totally |
145 // silent. But round-off prevents this from being completely | 146 // silent. But round-off prevents this from being completely |
146 // true. At the end of the triangle, it should be close to | 147 // true. At the end of the triangle, it should be close to |
147 // zero. If we go farther out, it should be even closer and | 148 // zero. If we go farther out, it should be even closer and |
148 // eventually zero. | 149 // eventually zero. |
149 | 150 |
150 // For the tail of the convolution (where the result would be | 151 // For the tail of the convolution (where the result would be |
151 // theoretically zero), we partition the tail into two | 152 // theoretically zero), we partition the tail into two |
152 // parts. The first is the at the beginning of the tail, | 153 // parts. The first is the at the beginning of the tail, |
153 // where we tolerate a small but non-zero value. The second part is | 154 // where we tolerate a small but non-zero value. The second part is |
154 // farther along the tail where the result should be zero. | 155 // farther along the tail where the result should be zero. |
155 | 156 |
156 // breakpoint is the point dividing the first two tail parts | 157 // breakpoint is the point dividing the first two tail parts |
157 // we're looking at. Experimentally determined. | 158 // we're looking at. Experimentally determined. |
158 var breakpoint = 12800; | 159 let breakpoint = 12800; |
159 | 160 |
160 success = success && checkTail1(renderedData, referenceData, breakpoint, | 161 success = |
161 should); | 162 success && checkTail1(renderedData, referenceData, breakpoint, should); |
162 | 163 |
163 success = success && checkTail2(renderedData, referenceData, breakpoint, | 164 success = |
164 should); | 165 success && checkTail2(renderedData, referenceData, breakpoint, should); |
165 | 166 |
166 should(success, "Test signal convolved") | 167 should(success, 'Test signal convolved').message('correctly', 'incorrectly'); |
167 .message("correctly", "incorrectly"); | |
168 } | 168 } |
OLD | NEW |