| 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 var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleR
ate); |
| 9 | 9 |
| 10 var n = audioBuffer.length; | 10 var n = audioBuffer.length; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 function log10(x) { | 39 function log10(x) { |
| 40 return Math.log(x)/Math.LN10; | 40 return Math.log(x)/Math.LN10; |
| 41 } | 41 } |
| 42 | 42 |
| 43 function linearToDecibel(x) { | 43 function linearToDecibel(x) { |
| 44 return 20*log10(x); | 44 return 20*log10(x); |
| 45 } | 45 } |
| 46 | 46 |
| 47 // Verify that the rendered result is very close to the reference | 47 // Verify that the rendered result is very close to the reference |
| 48 // triangular pulse. | 48 // triangular pulse. |
| 49 function checkTriangularPulse(rendered, reference) { | 49 function checkTriangularPulse(rendered, reference, should) { |
| 50 var match = true; | 50 var match = true; |
| 51 var maxDelta = 0; | 51 var maxDelta = 0; |
| 52 var valueAtMaxDelta = 0; | 52 var valueAtMaxDelta = 0; |
| 53 var maxDeltaIndex = 0; | 53 var maxDeltaIndex = 0; |
| 54 | 54 |
| 55 for (var i = 0; i < reference.length; ++i) { | 55 for (var i = 0; i < reference.length; ++i) { |
| 56 var diff = rendered[i] - reference[i]; | 56 var diff = rendered[i] - reference[i]; |
| 57 var x = Math.abs(diff); | 57 var x = Math.abs(diff); |
| 58 if (x > maxDelta) { | 58 if (x > maxDelta) { |
| 59 maxDelta = x; | 59 maxDelta = x; |
| 60 valueAtMaxDelta = reference[i]; | 60 valueAtMaxDelta = reference[i]; |
| 61 maxDeltaIndex = i; | 61 maxDeltaIndex = i; |
| 62 } | 62 } |
| 63 } | 63 } |
| 64 | 64 |
| 65 // allowedDeviationFraction was determined experimentally. It | 65 // allowedDeviationFraction was determined experimentally. It |
| 66 // is the threshold of the relative error at the maximum | 66 // is the threshold of the relative error at the maximum |
| 67 // difference between the true triangular pulse and the | 67 // difference between the true triangular pulse and the |
| 68 // rendered pulse. | 68 // rendered pulse. |
| 69 var allowedDeviationDecibels = -124.41; | 69 var allowedDeviationDecibels = -124.41; |
| 70 var maxDeviationDecibels = linearToDecibel(maxDelta / valueAtMaxDelta); | 70 var maxDeviationDecibels = linearToDecibel(maxDelta / valueAtMaxDelta); |
| 71 | 71 |
| 72 if (maxDeviationDecibels <= allowedDeviationDecibels) { | 72 should(maxDeviationDecibels, |
| 73 testPassed("Triangular portion of convolution is correct."); | 73 "Deviation (in dB) of triangular portion of convolution") |
| 74 } else { | 74 .beLessThanOrEqualTo(allowedDeviationDecibels); |
| 75 testFailed("Triangular portion of convolution is not correct. Max devia
tion = " + maxDeviationDecibels + " dB at " + maxDeltaIndex); | |
| 76 match = false; | |
| 77 } | |
| 78 | 75 |
| 79 return match; | 76 return match; |
| 80 } | 77 } |
| 81 | 78 |
| 82 // Verify that the rendered data is close to zero for the first part | 79 // Verify that the rendered data is close to zero for the first part |
| 83 // of the tail. | 80 // of the tail. |
| 84 function checkTail1(data, reference, breakpoint) { | 81 function checkTail1(data, reference, breakpoint, should) { |
| 85 var isZero = true; | 82 var isZero = true; |
| 86 var tail1Max = 0; | 83 var tail1Max = 0; |
| 87 | 84 |
| 88 for (var i = reference.length; i < reference.length + breakpoint; ++i) { | 85 for (var i = reference.length; i < reference.length + breakpoint; ++i) { |
| 89 var mag = Math.abs(data[i]); | 86 var mag = Math.abs(data[i]); |
| 90 if (mag > tail1Max) { | 87 if (mag > tail1Max) { |
| 91 tail1Max = mag; | 88 tail1Max = mag; |
| 92 } | 89 } |
| 93 } | 90 } |
| 94 | 91 |
| 95 // Let's find the peak of the reference (even though we know a | 92 // Let's find the peak of the reference (even though we know a |
| 96 // priori what it is). | 93 // priori what it is). |
| 97 var refMax = 0; | 94 var refMax = 0; |
| 98 for (var i = 0; i < reference.length; ++i) { | 95 for (var i = 0; i < reference.length; ++i) { |
| 99 refMax = Math.max(refMax, Math.abs(reference[i])); | 96 refMax = Math.max(refMax, Math.abs(reference[i])); |
| 100 } | 97 } |
| 101 | 98 |
| 102 // This threshold is experimentally determined by examining the | 99 // This threshold is experimentally determined by examining the |
| 103 // value of tail1MaxDecibels. | 100 // value of tail1MaxDecibels. |
| 104 var threshold1 = -129.7; | 101 var threshold1 = -129.7; |
| 105 | 102 |
| 106 var tail1MaxDecibels = linearToDecibel(tail1Max/refMax); | 103 var tail1MaxDecibels = linearToDecibel(tail1Max/refMax); |
| 107 if (tail1MaxDecibels <= threshold1) { | 104 should(tail1MaxDecibels, |
| 108 testPassed("First part of tail of convolution is sufficiently small."); | 105 "Deviation in first part of tail of convolutions") |
| 109 } else { | 106 .beLessThanOrEqualTo(threshold1); |
| 110 testFailed("First part of tail of convolution is not sufficiently small:
" + tail1MaxDecibels + " dB"); | |
| 111 isZero = false; | |
| 112 } | |
| 113 | 107 |
| 114 return isZero; | 108 return isZero; |
| 115 } | 109 } |
| 116 | 110 |
| 117 // Verify that the second part of the tail of the convolution is | 111 // Verify that the second part of the tail of the convolution is |
| 118 // exactly zero. | 112 // exactly zero. |
| 119 function checkTail2(data, reference, breakpoint) { | 113 function checkTail2(data, reference, breakpoint, should) { |
| 120 var isZero = true; | 114 var isZero = true; |
| 121 var tail2Max = 0; | 115 var tail2Max = 0; |
| 122 // For the second part of the tail, the maximum value should be | 116 // For the second part of the tail, the maximum value should be |
| 123 // exactly zero. | 117 // exactly zero. |
| 124 var threshold2 = 0; | 118 var threshold2 = 0; |
| 125 for (var i = reference.length + breakpoint; i < data.length; ++i) { | 119 for (var i = reference.length + breakpoint; i < data.length; ++i) { |
| 126 if (Math.abs(data[i]) > 0) { | 120 if (Math.abs(data[i]) > 0) { |
| 127 isZero = false; | 121 isZero = false; |
| 128 break; | 122 break; |
| 129 } | 123 } |
| 130 } | 124 } |
| 131 | 125 |
| 132 if (isZero) { | 126 should(isZero, |
| 133 testPassed("Rendered signal after tail of convolution is silent."); | 127 "Rendered signal after tail of convolution is silent") |
| 134 } else { | 128 .beTrue(); |
| 135 testFailed("Rendered signal after tail of convolution should be silent."
); | |
| 136 } | |
| 137 | 129 |
| 138 return isZero; | 130 return isZero; |
| 139 } | 131 } |
| 140 | 132 |
| 141 function checkConvolvedResult(trianglePulse) { | 133 function checkConvolvedResult(renderedBuffer, trianglePulse, should) { |
| 142 return function(event) { | 134 var referenceData = trianglePulse.getChannelData(0); |
| 143 var renderedBuffer = event.renderedBuffer; | 135 var renderedData = renderedBuffer.getChannelData(0); |
| 144 | 136 |
| 145 var referenceData = trianglePulse.getChannelData(0); | 137 var success = true; |
| 146 var renderedData = renderedBuffer.getChannelData(0); | |
| 147 | |
| 148 var success = true; | |
| 149 | |
| 150 // Verify the triangular pulse is actually triangular. | |
| 151 | 138 |
| 152 success = success && checkTriangularPulse(renderedData, referenceData); | 139 // Verify the triangular pulse is actually triangular. |
| 153 | |
| 154 // Make sure that portion after convolved portion is totally | |
| 155 // silent. But round-off prevents this from being completely | |
| 156 // true. At the end of the triangle, it should be close to | |
| 157 // zero. If we go farther out, it should be even closer and | |
| 158 // eventually zero. | |
| 159 | 140 |
| 160 // For the tail of the convolution (where the result would be | 141 success = success && checkTriangularPulse(renderedData, referenceData, |
| 161 // theoretically zero), we partition the tail into two | 142 should); |
| 162 // parts. The first is the at the beginning of the tail, | |
| 163 // where we tolerate a small but non-zero value. The second part is | |
| 164 // farther along the tail where the result should be zero. | |
| 165 | |
| 166 // breakpoint is the point dividing the first two tail parts | |
| 167 // we're looking at. Experimentally determined. | |
| 168 var breakpoint = 12800; | |
| 169 | 143 |
| 170 success = success && checkTail1(renderedData, referenceData, breakpoint)
; | 144 // Make sure that portion after convolved portion is totally |
| 171 | 145 // silent. But round-off prevents this from being completely |
| 172 success = success && checkTail2(renderedData, referenceData, breakpoint)
; | 146 // true. At the end of the triangle, it should be close to |
| 173 | 147 // zero. If we go farther out, it should be even closer and |
| 174 if (success) { | 148 // eventually zero. |
| 175 testPassed("Test signal was correctly convolved."); | |
| 176 } else { | |
| 177 testFailed("Test signal was not correctly convolved."); | |
| 178 } | |
| 179 | 149 |
| 180 finishJSTest(); | 150 // For the tail of the convolution (where the result would be |
| 181 } | 151 // theoretically zero), we partition the tail into two |
| 152 // 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 // farther along the tail where the result should be zero. |
| 155 |
| 156 // breakpoint is the point dividing the first two tail parts |
| 157 // we're looking at. Experimentally determined. |
| 158 var breakpoint = 12800; |
| 159 |
| 160 success = success && checkTail1(renderedData, referenceData, breakpoint, |
| 161 should); |
| 162 |
| 163 success = success && checkTail2(renderedData, referenceData, breakpoint, |
| 164 should); |
| 165 |
| 166 should(success, "Test signal convolved") |
| 167 .message("correctly", "incorrectly"); |
| 182 } | 168 } |
| OLD | NEW |