| OLD | NEW |
| (Empty) |
| 1 <!DOCTYPE html> | |
| 2 <html> | |
| 3 <head> | |
| 4 <title>AudioBufferSourceNode - playbackRate test</title> | |
| 5 <script src="../resources/js-test.js"></script> | |
| 6 <script src="resources/compatibility.js"></script> | |
| 7 <script src="resources/audit-util.js"></script> | |
| 8 <script src="resources/audio-testing.js"></script> | |
| 9 </head> | |
| 10 <body> | |
| 11 <script> | |
| 12 description("Test if AudioBufferSourceNode.playbackRate can playback at differ
ent rates properly."); | |
| 13 window.jsTestIsAsync = true; | |
| 14 | |
| 15 // Any sample rate mutiple of 128 is valid for this test, but here it uses | |
| 16 // 48000Hz because it is a commonly used number that happens to be multiple | |
| 17 // of 128. | |
| 18 var sampleRate = 48000; | |
| 19 | |
| 20 // The test iterates over 60 pitches starting from 36. (MIDI pitch of C2) | |
| 21 var fundamentalPitch = 36; | |
| 22 var numberOfPitches = 60; | |
| 23 | |
| 24 var noteDuration = 0.025; | |
| 25 var totalDuration = noteDuration * numberOfPitches; | |
| 26 | |
| 27 // Test constraints for each octave. | |
| 28 var testConstraints = [{ | |
| 29 thresholdSNR: 103.8508, | |
| 30 thresholdDiffULP: 0.3028 | |
| 31 }, { | |
| 32 thresholdSNR: 103.8657, | |
| 33 thresholdDiffULP: 0.3029 | |
| 34 }, { | |
| 35 thresholdSNR: 103.8141, | |
| 36 thresholdDiffULP: 0.3047 | |
| 37 }, { | |
| 38 thresholdSNR: 103.6818, | |
| 39 thresholdDiffULP: 0.3262 | |
| 40 }, { | |
| 41 thresholdSNR: 103.1514, | |
| 42 thresholdDiffULP: 0.3946 | |
| 43 }]; | |
| 44 | |
| 45 function pitchToFrequency(midiPitch) { | |
| 46 return 440 * Math.pow(2, (Math.floor(midiPitch) - 69) / 12); | |
| 47 } | |
| 48 | |
| 49 function pitchDiffToPlaybackRate(midiPitchDiff) { | |
| 50 return Math.pow(2, midiPitchDiff / 12); | |
| 51 } | |
| 52 | |
| 53 function createSineWaveBuffer(context, frequency, duration) { | |
| 54 var buffer = context.createBuffer(1, duration * sampleRate, sampleRate); | |
| 55 var data = buffer.getChannelData(0); | |
| 56 var omega = 2 * Math.PI * frequency / sampleRate; | |
| 57 for (var i = 0; i < data.length; i++) | |
| 58 data[i] = Math.sin(omega * i); | |
| 59 | |
| 60 return buffer; | |
| 61 } | |
| 62 | |
| 63 var context = new OfflineAudioContext(2, totalDuration * sampleRate, sampleRat
e); | |
| 64 | |
| 65 // This is the fundamental buffer for playbackRate modulation. The duration of | |
| 66 // this buffer is arbitrary but long enough to produce the sound without | |
| 67 // running short. | |
| 68 var fundamentalBuffer = createSineWaveBuffer(context, pitchToFrequency(fundame
ntalPitch), totalDuration); | |
| 69 | |
| 70 // A unit test consists of 2 sources: the 'actual' source runs a buffer with | |
| 71 // the playback rate modulated and the 'expected' source runs a mathmatically | |
| 72 // generated sound buffer. | |
| 73 function runUnitTest(context, noteStart, notePitch) { | |
| 74 var actualSrc = context.createBufferSource(); | |
| 75 var expectedSrc = context.createBufferSource(); | |
| 76 var merger = context.createChannelMerger(2); | |
| 77 | |
| 78 actualSrc.buffer = fundamentalBuffer; | |
| 79 expectedSrc.buffer = createSineWaveBuffer(context, pitchToFrequency(notePitc
h), noteDuration); | |
| 80 actualSrc.playbackRate.value = pitchDiffToPlaybackRate(notePitch - fundament
alPitch); | |
| 81 | |
| 82 actualSrc.connect(merger, 0, 0); | |
| 83 expectedSrc.connect(merger, 0, 1); | |
| 84 merger.connect(context.destination); | |
| 85 | |
| 86 actualSrc.start(noteStart); | |
| 87 actualSrc.stop(noteStart + noteDuration); | |
| 88 expectedSrc.start(noteStart); | |
| 89 expectedSrc.stop(noteStart + noteDuration); | |
| 90 } | |
| 91 | |
| 92 // Schedule tests up to 60 pitches above from the fundamental pitch. | |
| 93 for (var iteration = 0; iteration < numberOfPitches; iteration++) | |
| 94 runUnitTest(context, noteDuration * iteration, fundamentalPitch + iteration)
; | |
| 95 | |
| 96 // Once the rendering is complete, split the buffer into 5 octaves. Then | |
| 97 // perform the SNR and the maximum difference ULP check for each octave with | |
| 98 // different constraints. | |
| 99 context.startRendering().then(function (renderedBuffer) { | |
| 100 var actual = renderedBuffer.getChannelData(0); | |
| 101 var expected = renderedBuffer.getChannelData(1); | |
| 102 var octaveLength = Math.floor(noteDuration * 12 * sampleRate); | |
| 103 | |
| 104 for (var i = 0; i < numberOfPitches / 12; i++) { | |
| 105 var start = i * octaveLength, end = (i + 1) * octaveLength; | |
| 106 var octaveActual = actual.subarray(start, end); | |
| 107 var octaveExpected = expected.subarray(start, end); | |
| 108 | |
| 109 compareBuffersWithConstraints(octaveActual, octaveExpected, testConstraint
s[i]); | |
| 110 } | |
| 111 | |
| 112 finishJSTest(); | |
| 113 }); | |
| 114 | |
| 115 successfullyParsed = true; | |
| 116 </script> | |
| 117 </body> | |
| 118 </html> | |
| OLD | NEW |