// Notes about generated waveforms: // // QUESTION: Why does the wave shape not look like the exact shape (sharp edges)? // ANSWER: Because a shape with sharp edges has infinitely high frequency content. // Since a digital audio signal must be band-limited based on the nyquist frequency (half the sample-rate) // in order to avoid aliasing, this creates more rounded edges and "ringing" in the // appearance of the waveform. See Nyquist-Shannon sampling theorem: // http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem // // QUESTION: Why does the very end of the generated signal appear to get slightly weaker? // ANSWER: This is an artifact of the algorithm to avoid aliasing. var sampleRate = 44100.0; var nyquist = 0.5 * sampleRate; var lengthInSeconds = 4; var lowFrequency = 10; var highFrequency = nyquist + 2000; // go slightly higher than nyquist to make sure we generate silence there var context = 0; function generateExponentialOscillatorSweep(oscillatorType) { // Create offline audio context. context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRate); var osc = context.createOscillator(); if (oscillatorType == "custom") { // Create a simple waveform with three Fourier coefficients. // Note the first values are expected to be zero (DC for coeffA and Nyquist for coeffB). var coeffA = new Float32Array([0, 1, 0.5]); var coeffB = new Float32Array([0, 0, 0]); var wave = context.createPeriodicWave(coeffA, coeffB); osc.setPeriodicWave(wave); } else { osc.type = oscillatorType; } // Scale by 1/2 to better visualize the waveform and to avoid clipping past full scale. var gainNode = context.createGain(); gainNode.gain.value = 0.5; osc.connect(gainNode); gainNode.connect(context.destination); osc.start(0); var nyquist = 0.5 * sampleRate; osc.frequency.setValueAtTime(10, 0); osc.frequency.exponentialRampToValueAtTime(highFrequency, lengthInSeconds); context.oncomplete = finishAudioTest; context.startRendering(); testRunner.waitUntilDone(); }