| Index: third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
|
| diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
|
| index ff0eb2860a0da56d02b7e95fa613288b24fdee44..d8ae87131bba0569b211da314c2fe4dc205c7c68 100644
|
| --- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
|
| +++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-automation.html
|
| @@ -1,125 +1,135 @@
|
| -<!doctype html>
|
| +<!DOCTYPE html>
|
| <html>
|
| <head>
|
| - <title>Biquad Automation Test</title>
|
| + <title>
|
| + Biquad Automation Test
|
| + </title>
|
| <script src="../../resources/testharness.js"></script>
|
| - <script src="../../resources/testharnessreport.js"></script>
|
| + <script src="../../resources/testharnessreport.js"></script>
|
| <script src="../resources/audit-util.js"></script>
|
| <script src="../resources/audit.js"></script>
|
| <script src="../resources/biquad-filters.js"></script>
|
| <script src="../resources/audioparam-testing.js"></script>
|
| </head>
|
| <body>
|
| - <script>
|
| -
|
| -
|
| - // Don't need to run these tests at high sampling rate, so just use a low one to reduce memory
|
| - // usage and complexity.
|
| - var sampleRate = 16000;
|
| + <script id="layout-test-code">
|
| + // Don't need to run these tests at high sampling rate, so just use a low
|
| + // one to reduce memory usage and complexity.
|
| + let sampleRate = 16000;
|
|
|
| // How long to render for each test.
|
| - var renderDuration = 0.25;
|
| + let renderDuration = 0.25;
|
| // Where to end the automations. Fairly arbitrary, but must end before
|
| // the renderDuration.
|
| - var automationEndTime = renderDuration / 2;
|
| + let automationEndTime = renderDuration / 2;
|
|
|
| - var audit = Audit.createTaskRunner();
|
| + let audit = Audit.createTaskRunner();
|
|
|
| // The definition of the linear ramp automation function.
|
| function linearRamp(t, v0, v1, t0, t1) {
|
| return v0 + (v1 - v0) * (t - t0) / (t1 - t0);
|
| }
|
|
|
| - // Generate the filter coefficients for the specified filter using the given parameters for
|
| - // the given duration. |filterTypeFunction| is a function that returns the filter
|
| - // coefficients for one set of parameters. |parameters| is a property bag that contains the
|
| - // start and end values (as an array) for each of the biquad attributes. The properties are
|
| - // |freq|, |Q|, |gain|, and |detune|. |duration| is the number of seconds for which the
|
| - // coefficients are generated.
|
| + // Generate the filter coefficients for the specified filter using the
|
| + // given parameters for the given duration. |filterTypeFunction| is a
|
| + // function that returns the filter coefficients for one set of
|
| + // parameters. |parameters| is a property bag that contains the start and
|
| + // end values (as an array) for each of the biquad attributes. The
|
| + // properties are |freq|, |Q|, |gain|, and |detune|. |duration| is the
|
| + // number of seconds for which the coefficients are generated.
|
| //
|
| - // A property bag with properties |b0|, |b1|, |b2|, |a1|, |a2|. Each propery is an array
|
| - // consisting of the coefficients for the time-varying biquad filter.
|
| - function generateFilterCoefficients(filterTypeFunction, parameters, duration) {
|
| - var renderEndFrame = Math.ceil(renderDuration * sampleRate);
|
| - var endFrame = Math.ceil(duration * sampleRate);
|
| - var nCoef = renderEndFrame;
|
| - var b0 = new Float64Array(nCoef);
|
| - var b1 = new Float64Array(nCoef);
|
| - var b2 = new Float64Array(nCoef);
|
| - var a1 = new Float64Array(nCoef);
|
| - var a2 = new Float64Array(nCoef);
|
| -
|
| - var k = 0;
|
| - // If the property is not given, use the defaults.
|
| - var freqs = parameters.freq || [350, 350];
|
| - var qs = parameters.Q || [1, 1];
|
| - var gains = parameters.gain || [0, 0];
|
| - var detunes = parameters.detune || [0, 0];
|
| -
|
| - for (var frame = 0; frame <= endFrame; ++frame) {
|
| - // Apply linear ramp at frame |frame|.
|
| - var f = linearRamp(frame / sampleRate, freqs[0], freqs[1], 0, duration);
|
| - var q = linearRamp(frame / sampleRate, qs[0], qs[1], 0, duration);
|
| - var g = linearRamp(frame / sampleRate, gains[0], gains[1], 0, duration);
|
| - var d = linearRamp(frame / sampleRate, detunes[0], detunes[1], 0, duration);
|
| -
|
| - // Compute actual frequency parameter
|
| - f = f * Math.pow(2, d / 1200);
|
| -
|
| - // Compute filter coefficients
|
| - var coef = filterTypeFunction(f / (sampleRate / 2), q, g);
|
| - b0[k] = coef.b0;
|
| - b1[k] = coef.b1;
|
| - b2[k] = coef.b2;
|
| - a1[k] = coef.a1;
|
| - a2[k] = coef.a2;
|
| - ++k;
|
| - }
|
| -
|
| - // Fill the rest of the arrays with the constant value to the end of
|
| - // the rendering duration.
|
| - b0.fill(b0[endFrame], endFrame + 1);
|
| - b1.fill(b1[endFrame], endFrame + 1);
|
| - b2.fill(b2[endFrame], endFrame + 1);
|
| - a1.fill(a1[endFrame], endFrame + 1);
|
| - a2.fill(a2[endFrame], endFrame + 1);
|
| -
|
| - return {b0: b0, b1: b1, b2: b2, a1: a1, a2: a2};
|
| + // A property bag with properties |b0|, |b1|, |b2|, |a1|, |a2|. Each
|
| + // propery is an array consisting of the coefficients for the time-varying
|
| + // biquad filter.
|
| + function generateFilterCoefficients(
|
| + filterTypeFunction, parameters, duration) {
|
| + let renderEndFrame = Math.ceil(renderDuration * sampleRate);
|
| + let endFrame = Math.ceil(duration * sampleRate);
|
| + let nCoef = renderEndFrame;
|
| + let b0 = new Float64Array(nCoef);
|
| + let b1 = new Float64Array(nCoef);
|
| + let b2 = new Float64Array(nCoef);
|
| + let a1 = new Float64Array(nCoef);
|
| + let a2 = new Float64Array(nCoef);
|
| +
|
| + let k = 0;
|
| + // If the property is not given, use the defaults.
|
| + let freqs = parameters.freq || [350, 350];
|
| + let qs = parameters.Q || [1, 1];
|
| + let gains = parameters.gain || [0, 0];
|
| + let detunes = parameters.detune || [0, 0];
|
| +
|
| + for (let frame = 0; frame <= endFrame; ++frame) {
|
| + // Apply linear ramp at frame |frame|.
|
| + let f =
|
| + linearRamp(frame / sampleRate, freqs[0], freqs[1], 0, duration);
|
| + let q = linearRamp(frame / sampleRate, qs[0], qs[1], 0, duration);
|
| + let g =
|
| + linearRamp(frame / sampleRate, gains[0], gains[1], 0, duration);
|
| + let d = linearRamp(
|
| + frame / sampleRate, detunes[0], detunes[1], 0, duration);
|
| +
|
| + // Compute actual frequency parameter
|
| + f = f * Math.pow(2, d / 1200);
|
| +
|
| + // Compute filter coefficients
|
| + let coef = filterTypeFunction(f / (sampleRate / 2), q, g);
|
| + b0[k] = coef.b0;
|
| + b1[k] = coef.b1;
|
| + b2[k] = coef.b2;
|
| + a1[k] = coef.a1;
|
| + a2[k] = coef.a2;
|
| + ++k;
|
| + }
|
| +
|
| + // Fill the rest of the arrays with the constant value to the end of
|
| + // the rendering duration.
|
| + b0.fill(b0[endFrame], endFrame + 1);
|
| + b1.fill(b1[endFrame], endFrame + 1);
|
| + b2.fill(b2[endFrame], endFrame + 1);
|
| + a1.fill(a1[endFrame], endFrame + 1);
|
| + a2.fill(a2[endFrame], endFrame + 1);
|
| +
|
| + return {b0: b0, b1: b1, b2: b2, a1: a1, a2: a2};
|
| }
|
|
|
| - // Apply the given time-varying biquad filter to the given signal, |signal|. |coef| should be
|
| - // the time-varying coefficients of the filter, as returned by |generateFilterCoefficients|.
|
| + // Apply the given time-varying biquad filter to the given signal,
|
| + // |signal|. |coef| should be the time-varying coefficients of the
|
| + // filter, as returned by |generateFilterCoefficients|.
|
| function timeVaryingFilter(signal, coef) {
|
| - var length = signal.length;
|
| + let length = signal.length;
|
| // Use double precision for the internal computations.
|
| - var y = new Float64Array(length);
|
| + let y = new Float64Array(length);
|
|
|
| // Prime the pump. (Assumes the signal has length >= 2!)
|
| y[0] = coef.b0[0] * signal[0];
|
| - y[1] = coef.b0[1] * signal[1] + coef.b1[1] * signal[0] - coef.a1[1] * y[0];
|
| + y[1] =
|
| + coef.b0[1] * signal[1] + coef.b1[1] * signal[0] - coef.a1[1] * y[0];
|
|
|
| - for (var n = 2; n < length; ++n) {
|
| - y[n] = coef.b0[n] * signal[n] + coef.b1[n] * signal[n-1] + coef.b2[n] * signal[n-2];
|
| - y[n] -= coef.a1[n] * y[n-1] + coef.a2[n] * y[n-2];
|
| + for (let n = 2; n < length; ++n) {
|
| + y[n] = coef.b0[n] * signal[n] + coef.b1[n] * signal[n - 1] +
|
| + coef.b2[n] * signal[n - 2];
|
| + y[n] -= coef.a1[n] * y[n - 1] + coef.a2[n] * y[n - 2];
|
| }
|
|
|
| // But convert the result to single precision for comparison.
|
| return y.map(Math.fround);
|
| }
|
|
|
| - // Configure the audio graph using |context|. Returns the biquad filter node and the
|
| - // AudioBuffer used for the source.
|
| + // Configure the audio graph using |context|. Returns the biquad filter
|
| + // node and the AudioBuffer used for the source.
|
| function configureGraph(context, toneFrequency) {
|
| // The source is just a simple sine wave.
|
| - var src = context.createBufferSource();
|
| - var b = context.createBuffer(1, renderDuration * sampleRate, sampleRate);
|
| - var data = b.getChannelData(0);
|
| - var omega = 2 * Math.PI * toneFrequency / sampleRate;
|
| - for (var k = 0; k < data.length; ++k) {
|
| + let src = context.createBufferSource();
|
| + let b =
|
| + context.createBuffer(1, renderDuration * sampleRate, sampleRate);
|
| + let data = b.getChannelData(0);
|
| + let omega = 2 * Math.PI * toneFrequency / sampleRate;
|
| + for (let k = 0; k < data.length; ++k) {
|
| data[k] = Math.sin(omega * k);
|
| }
|
| src.buffer = b;
|
| - var f = context.createBiquadFilter();
|
| + let f = context.createBiquadFilter();
|
| src.connect(f);
|
| f.connect(context.destination);
|
|
|
| @@ -128,10 +138,12 @@
|
| return {filter: f, source: b};
|
| }
|
|
|
| - function createFilterVerifier(should, filterCreator, threshold, parameters, input, message) {
|
| - return function (resultBuffer) {
|
| - var actual = resultBuffer.getChannelData(0);
|
| - var coefs = generateFilterCoefficients(filterCreator, parameters, automationEndTime);
|
| + function createFilterVerifier(
|
| + should, filterCreator, threshold, parameters, input, message) {
|
| + return function(resultBuffer) {
|
| + let actual = resultBuffer.getChannelData(0);
|
| + let coefs = generateFilterCoefficients(
|
| + filterCreator, parameters, automationEndTime);
|
|
|
| reference = timeVaryingFilter(input, coefs);
|
|
|
| @@ -141,13 +153,16 @@
|
| };
|
| }
|
|
|
| - // Automate just the frequency parameter. A bandpass filter is used where the center
|
| - // frequency is swept across the source (which is a simple tone).
|
| - audit.define("automate-freq", (task, should) => {
|
| - var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| + // Automate just the frequency parameter. A bandpass filter is used where
|
| + // the center frequency is swept across the source (which is a simple
|
| + // tone).
|
| + audit.define('automate-freq', (task, should) => {
|
| + let context =
|
| + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
|
|
| - // Center frequency of bandpass filter and also the frequency of the test tone.
|
| - var centerFreq = 10*440;
|
| + // Center frequency of bandpass filter and also the frequency of the
|
| + // test tone.
|
| + let centerFreq = 10 * 440;
|
|
|
| // Sweep the frequency +/- 5*440 Hz from the center. This should cause
|
| // the output to be low at the beginning and end of the test where the
|
| @@ -155,217 +170,234 @@
|
| // of the automation time where the tone is near the center of the pass
|
| // band. Make sure the frequency sweep stays inside the Nyquist
|
| // frequency.
|
| - var parameters = {
|
| - freq: [centerFreq - 5*440, centerFreq + 5*440]
|
| - };
|
| - var graph = configureGraph(context, centerFreq);
|
| - var f = graph.filter;
|
| - var b = graph.source;
|
| + let parameters = {freq: [centerFreq - 5 * 440, centerFreq + 5 * 440]};
|
| + let graph = configureGraph(context, centerFreq);
|
| + let f = graph.filter;
|
| + let b = graph.source;
|
|
|
| - f.type = "bandpass";
|
| + f.type = 'bandpass';
|
| f.frequency.setValueAtTime(parameters.freq[0], 0);
|
| - f.frequency.linearRampToValueAtTime(parameters.freq[1], automationEndTime);
|
| + f.frequency.linearRampToValueAtTime(
|
| + parameters.freq[1], automationEndTime);
|
|
|
| context.startRendering()
|
| - .then(createFilterVerifier(should, createBandpassFilter, 4.6455e-6,
|
| - parameters, b.getChannelData(0),
|
| - "Output of bandpass filter with frequency automation"))
|
| - .then(() => task.done());
|
| + .then(createFilterVerifier(
|
| + should, createBandpassFilter, 4.6455e-6, parameters,
|
| + b.getChannelData(0),
|
| + 'Output of bandpass filter with frequency automation'))
|
| + .then(() => task.done());
|
| });
|
|
|
| - // Automate just the Q parameter. A bandpass filter is used where the Q of the filter is
|
| - // swept.
|
| - audit.define("automate-q", (task, should) => {
|
| - var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| + // Automate just the Q parameter. A bandpass filter is used where the Q
|
| + // of the filter is swept.
|
| + audit.define('automate-q', (task, should) => {
|
| + let context =
|
| + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
|
|
| // The frequency of the test tone.
|
| - var centerFreq = 440;
|
| + let centerFreq = 440;
|
|
|
| - // Sweep the Q paramter between 1 and 200. This will cause the output of the filter to pass
|
| - // most of the tone at the beginning to passing less of the tone at the end. This is
|
| - // because we set center frequency of the bandpass filter to be slightly off from the actual
|
| - // tone.
|
| - var parameters = {
|
| + // Sweep the Q paramter between 1 and 200. This will cause the output
|
| + // of the filter to pass most of the tone at the beginning to passing
|
| + // less of the tone at the end. This is because we set center frequency
|
| + // of the bandpass filter to be slightly off from the actual tone.
|
| + let parameters = {
|
| Q: [1, 200],
|
| - // Center frequency of the bandpass filter is just 25 Hz above the tone frequency.
|
| + // Center frequency of the bandpass filter is just 25 Hz above the
|
| + // tone frequency.
|
| freq: [centerFreq + 25, centerFreq + 25]
|
| };
|
| - var graph = configureGraph(context, centerFreq);
|
| - var f = graph.filter;
|
| - var b = graph.source;
|
| + let graph = configureGraph(context, centerFreq);
|
| + let f = graph.filter;
|
| + let b = graph.source;
|
|
|
| - f.type = "bandpass";
|
| + f.type = 'bandpass';
|
| f.frequency.value = parameters.freq[0];
|
| f.Q.setValueAtTime(parameters.Q[0], 0);
|
| f.Q.linearRampToValueAtTime(parameters.Q[1], automationEndTime);
|
|
|
| context.startRendering()
|
| - .then(createFilterVerifier(should, createBandpassFilter, 9.8348e-7,
|
| - parameters, b.getChannelData(0),
|
| - "Output of bandpass filter with Q automation"))
|
| - .then(() => task.done());
|
| + .then(createFilterVerifier(
|
| + should, createBandpassFilter, 9.8348e-7, parameters,
|
| + b.getChannelData(0),
|
| + 'Output of bandpass filter with Q automation'))
|
| + .then(() => task.done());
|
| });
|
|
|
| - // Automate just the gain of the lowshelf filter. A test tone will be in the lowshelf part of
|
| - // the filter. The output will vary as the gain of the lowshelf is changed.
|
| - audit.define("automate-gain", (task, should) => {
|
| - var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| + // Automate just the gain of the lowshelf filter. A test tone will be in
|
| + // the lowshelf part of the filter. The output will vary as the gain of
|
| + // the lowshelf is changed.
|
| + audit.define('automate-gain', (task, should) => {
|
| + let context =
|
| + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
|
|
| // Frequency of the test tone.
|
| - var centerFreq = 440;
|
| -
|
| - // Set the cutoff frequency of the lowshelf to be significantly higher than the test tone.
|
| - // Sweep the gain from 20 dB to -20 dB. (We go from 20 to -20 to easily verify that the
|
| - // filter didn't go unstable.)
|
| - var parameters = {
|
| - freq: [3500, 3500],
|
| - gain: [20, -20]
|
| - };
|
| - var graph = configureGraph(context, centerFreq);
|
| - var f = graph.filter;
|
| - var b = graph.source;
|
| + let centerFreq = 440;
|
|
|
| - f.type = "lowshelf";
|
| + // Set the cutoff frequency of the lowshelf to be significantly higher
|
| + // than the test tone. Sweep the gain from 20 dB to -20 dB. (We go from
|
| + // 20 to -20 to easily verify that the filter didn't go unstable.)
|
| + let parameters = {freq: [3500, 3500], gain: [20, -20]};
|
| + let graph = configureGraph(context, centerFreq);
|
| + let f = graph.filter;
|
| + let b = graph.source;
|
| +
|
| + f.type = 'lowshelf';
|
| f.frequency.value = parameters.freq[0];
|
| f.gain.setValueAtTime(parameters.gain[0], 0);
|
| f.gain.linearRampToValueAtTime(parameters.gain[1], automationEndTime);
|
|
|
| context.startRendering()
|
| - .then(createFilterVerifier(should, createLowShelfFilter, 2.7657e-5,
|
| - parameters, b.getChannelData(0),
|
| - "Output of lowshelf filter with gain automation"))
|
| - .then(() => task.done());
|
| + .then(createFilterVerifier(
|
| + should, createLowShelfFilter, 2.7657e-5, parameters,
|
| + b.getChannelData(0),
|
| + 'Output of lowshelf filter with gain automation'))
|
| + .then(() => task.done());
|
| });
|
|
|
| - // Automate just the detune parameter. Basically the same test as for the frequncy parameter
|
| - // but we just use the detune parameter to modulate the frequency parameter.
|
| - audit.define("automate-detune", (task, should) => {
|
| - var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| - var centerFreq = 10*440;
|
| - var parameters = {
|
| + // Automate just the detune parameter. Basically the same test as for the
|
| + // frequncy parameter but we just use the detune parameter to modulate the
|
| + // frequency parameter.
|
| + audit.define('automate-detune', (task, should) => {
|
| + let context =
|
| + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| + let centerFreq = 10 * 440;
|
| + let parameters = {
|
| freq: [centerFreq, centerFreq],
|
| - detune: [-10*1200, 10*1200]
|
| + detune: [-10 * 1200, 10 * 1200]
|
| };
|
| - var graph = configureGraph(context, centerFreq);
|
| - var f = graph.filter;
|
| - var b = graph.source;
|
| + let graph = configureGraph(context, centerFreq);
|
| + let f = graph.filter;
|
| + let b = graph.source;
|
|
|
| - f.type = "bandpass";
|
| + f.type = 'bandpass';
|
| f.frequency.value = parameters.freq[0];
|
| f.detune.setValueAtTime(parameters.detune[0], 0);
|
| - f.detune.linearRampToValueAtTime(parameters.detune[1], automationEndTime);
|
| + f.detune.linearRampToValueAtTime(
|
| + parameters.detune[1], automationEndTime);
|
|
|
| context.startRendering()
|
| - .then(createFilterVerifier(should, createBandpassFilter, 3.1471e-5,
|
| - parameters, b.getChannelData(0),
|
| - "Output of bandpass filter with detune automation"))
|
| - .then(() => task.done());
|
| + .then(createFilterVerifier(
|
| + should, createBandpassFilter, 3.1471e-5, parameters,
|
| + b.getChannelData(0),
|
| + 'Output of bandpass filter with detune automation'))
|
| + .then(() => task.done());
|
| });
|
|
|
| - // Automate all of the filter parameters at once. This is a basic check that everything is
|
| - // working. A peaking filter is used because it uses all of the parameters.
|
| - audit.define("automate-all", (task, should) => {
|
| - var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| - var graph = configureGraph(context, 10*440);
|
| - var f = graph.filter;
|
| - var b = graph.source;
|
| + // Automate all of the filter parameters at once. This is a basic check
|
| + // that everything is working. A peaking filter is used because it uses
|
| + // all of the parameters.
|
| + audit.define('automate-all', (task, should) => {
|
| + let context =
|
| + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| + let graph = configureGraph(context, 10 * 440);
|
| + let f = graph.filter;
|
| + let b = graph.source;
|
|
|
| // Sweep all of the filter parameters. These are pretty much arbitrary.
|
| - var parameters = {
|
| + let parameters = {
|
| freq: [8000, 100],
|
| Q: [f.Q.value, .0001],
|
| gain: [f.gain.value, 20],
|
| detune: [2400, -2400]
|
| };
|
|
|
| - f.type = "peaking";
|
| - // Set starting points for all parameters of the filter. Start at 10 kHz for the center
|
| - // frequency, and the defaults for Q and gain.
|
| + f.type = 'peaking';
|
| + // Set starting points for all parameters of the filter. Start at 10
|
| + // kHz for the center frequency, and the defaults for Q and gain.
|
| f.frequency.setValueAtTime(parameters.freq[0], 0);
|
| f.Q.setValueAtTime(parameters.Q[0], 0);
|
| f.gain.setValueAtTime(parameters.gain[0], 0);
|
| f.detune.setValueAtTime(parameters.detune[0], 0);
|
|
|
| // Linear ramp each parameter
|
| - f.frequency.linearRampToValueAtTime(parameters.freq[1], automationEndTime);
|
| + f.frequency.linearRampToValueAtTime(
|
| + parameters.freq[1], automationEndTime);
|
| f.Q.linearRampToValueAtTime(parameters.Q[1], automationEndTime);
|
| f.gain.linearRampToValueAtTime(parameters.gain[1], automationEndTime);
|
| - f.detune.linearRampToValueAtTime(parameters.detune[1], automationEndTime);
|
| + f.detune.linearRampToValueAtTime(
|
| + parameters.detune[1], automationEndTime);
|
|
|
| context.startRendering()
|
| - .then(createFilterVerifier(should, createPeakingFilter, 6.2907e-4,
|
| - parameters, b.getChannelData(0),
|
| - "Output of peaking filter with automation of all parameters"))
|
| - .then(() => task.done());
|
| + .then(createFilterVerifier(
|
| + should, createPeakingFilter, 6.2907e-4, parameters,
|
| + b.getChannelData(0),
|
| + 'Output of peaking filter with automation of all parameters'))
|
| + .then(() => task.done());
|
| });
|
|
|
| - // Test that modulation of the frequency parameter of the filter works. A sinusoid of 440 Hz
|
| - // is the test signal that is applied to a bandpass biquad filter. The frequency parameter of
|
| - // the filter is modulated by a sinusoid at 103 Hz, and the frequency modulation varies from
|
| - // 116 to 412 Hz. (This test was taken from the description in
|
| + // Test that modulation of the frequency parameter of the filter works. A
|
| + // sinusoid of 440 Hz is the test signal that is applied to a bandpass
|
| + // biquad filter. The frequency parameter of the filter is modulated by a
|
| + // sinusoid at 103 Hz, and the frequency modulation varies from 116 to 412
|
| + // Hz. (This test was taken from the description in
|
| // https://github.com/WebAudio/web-audio-api/issues/509#issuecomment-94731355)
|
| - audit.define("modulation", (task, should) => {
|
| - var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
| + audit.define('modulation', (task, should) => {
|
| + let context =
|
| + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
|
|
|
| - // Create a graph with the sinusoidal source at 440 Hz as the input to a biquad filter.
|
| - var graph = configureGraph(context, 440);
|
| - var f = graph.filter;
|
| - var b = graph.source;
|
| + // Create a graph with the sinusoidal source at 440 Hz as the input to a
|
| + // biquad filter.
|
| + let graph = configureGraph(context, 440);
|
| + let f = graph.filter;
|
| + let b = graph.source;
|
|
|
| - f.type = "bandpass";
|
| + f.type = 'bandpass';
|
| f.Q.value = 5;
|
| f.frequency.value = 264;
|
|
|
| - // Create the modulation source, a sinusoid with frequency 103 Hz and amplitude 148. (The
|
| - // amplitude of 148 is added to the filter's frequency value of 264 to produce a sinusoidal
|
| - // modulation of the frequency parameter from 116 to 412 Hz.)
|
| - var mod = context.createBufferSource();
|
| - var mbuffer = context.createBuffer(1, renderDuration * sampleRate, sampleRate);
|
| - var d = mbuffer.getChannelData(0);
|
| - var omega = 2 * Math.PI * 103 / sampleRate;
|
| - for (var k = 0; k < d.length; ++k) {
|
| + // Create the modulation source, a sinusoid with frequency 103 Hz and
|
| + // amplitude 148. (The amplitude of 148 is added to the filter's
|
| + // frequency value of 264 to produce a sinusoidal modulation of the
|
| + // frequency parameter from 116 to 412 Hz.)
|
| + let mod = context.createBufferSource();
|
| + let mbuffer =
|
| + context.createBuffer(1, renderDuration * sampleRate, sampleRate);
|
| + let d = mbuffer.getChannelData(0);
|
| + let omega = 2 * Math.PI * 103 / sampleRate;
|
| + for (let k = 0; k < d.length; ++k) {
|
| d[k] = 148 * Math.sin(omega * k);
|
| }
|
| mod.buffer = mbuffer;
|
|
|
| mod.connect(f.frequency);
|
| -
|
| +
|
| mod.start();
|
| context.startRendering()
|
| - .then(function (resultBuffer) {
|
| - var actual = resultBuffer.getChannelData(0);
|
| - // Compute the filter coefficients using the mod sine wave
|
| -
|
| - var endFrame = Math.ceil(renderDuration * sampleRate);
|
| - var nCoef = endFrame;
|
| - var b0 = new Float64Array(nCoef);
|
| - var b1 = new Float64Array(nCoef);
|
| - var b2 = new Float64Array(nCoef);
|
| - var a1 = new Float64Array(nCoef);
|
| - var a2 = new Float64Array(nCoef);
|
| -
|
| - // Generate the filter coefficients when the frequency varies from 116 to 248 Hz using
|
| - // the 103 Hz sinusoid.
|
| - for (var k = 0; k < nCoef; ++k) {
|
| - var freq = f.frequency.value + d[k];
|
| - var c = createBandpassFilter(freq / (sampleRate / 2), f.Q.value, f.gain.value);
|
| - b0[k] = c.b0;
|
| - b1[k] = c.b1;
|
| - b2[k] = c.b2;
|
| - a1[k] = c.a1;
|
| - a2[k] = c.a2;
|
| - }
|
| - reference = timeVaryingFilter(b.getChannelData(0),
|
| - {b0: b0, b1: b1, b2: b2, a1: a1, a2: a2});
|
| -
|
| - should(actual,
|
| - "Output of bandpass filter with sinusoidal modulation of bandpass center frequency"
|
| - )
|
| - .beCloseToArray(reference, {
|
| - absoluteThreshold: 3.9787e-5
|
| - });
|
| - })
|
| - .then(() => task.done());
|
| + .then(function(resultBuffer) {
|
| + let actual = resultBuffer.getChannelData(0);
|
| + // Compute the filter coefficients using the mod sine wave
|
| +
|
| + let endFrame = Math.ceil(renderDuration * sampleRate);
|
| + let nCoef = endFrame;
|
| + let b0 = new Float64Array(nCoef);
|
| + let b1 = new Float64Array(nCoef);
|
| + let b2 = new Float64Array(nCoef);
|
| + let a1 = new Float64Array(nCoef);
|
| + let a2 = new Float64Array(nCoef);
|
| +
|
| + // Generate the filter coefficients when the frequency varies from
|
| + // 116 to 248 Hz using the 103 Hz sinusoid.
|
| + for (let k = 0; k < nCoef; ++k) {
|
| + let freq = f.frequency.value + d[k];
|
| + let c = createBandpassFilter(
|
| + freq / (sampleRate / 2), f.Q.value, f.gain.value);
|
| + b0[k] = c.b0;
|
| + b1[k] = c.b1;
|
| + b2[k] = c.b2;
|
| + a1[k] = c.a1;
|
| + a2[k] = c.a2;
|
| + }
|
| + reference = timeVaryingFilter(
|
| + b.getChannelData(0),
|
| + {b0: b0, b1: b1, b2: b2, a1: a1, a2: a2});
|
| +
|
| + should(
|
| + actual,
|
| + 'Output of bandpass filter with sinusoidal modulation of bandpass center frequency')
|
| + .beCloseToArray(reference, {absoluteThreshold: 3.9787e-5});
|
| + })
|
| + .then(() => task.done());
|
| });
|
|
|
| audit.run();
|
|
|