Skip to content

Latest commit

 

History

History
290 lines (223 loc) · 8.98 KB

README.md

File metadata and controls

290 lines (223 loc) · 8.98 KB

Disclaimer

This is a relatively old package, which wasn't maintained for several years. We've forked it so that we have the ability to update bits of it that are no longer compliant with the Web Audio API.

Developing and Publishing

To release a new version:

  1. Make your changes
  2. Bump the version in package.json
  3. type npm publish

If publishing doesn't work, you must be logged into the npm account with the command npm login

web-audio-test-api

Build Status NPM Version License

Web Audio API test library for CI

Installation

node.js

$ npm install --save-dev web-audio-test-api

Install Web Audio API interfaces to global scope

import "web-audio-test-api";

browser

Replace existing Web Audio API with web-audio-test-api

<script src="/path/to/web-audio-test-api.js"></script>

if you won't use web-audio-test-api

WebAudioTestAPI.unuse();

Online Test Suite

Documents

Features

  • Strict type check more than original Web Audio API
var audioContext = new AudioContext();
var osc = audioContext.createOsillator();

// correct
osc.frequency.value = 880;

// wrong
assert.throws(function() {
  osc.frequency = 880;
}, function(e) {
  return e instanceof TypeError &&
    e.message === "OscillatorNode#frequency is readonly";
});

assert.throws(function() {
  osc.type = 2;
}, function(e) {
  return e instanceof TypeError &&
    e.message === "OscillatorNode#type should be an enum { sine, square, sawtooth, triangle }, but got: 2";
});
});
  • Convert to JSON from audio graph
var audioContext = new AudioContext();
var osc = audioContext.createOscillator();
var lfo = audioContext.createOscillator();
var amp = audioContext.createGain();

lfo.$id = "LFO"; // name for debugging

osc.type = "sawtooth";
osc.frequency.value = 880;

lfo.frequency.value = 2;

lfo.connect(amp.gain);
osc.connect(amp);
amp.connect(audioContext.destination);

assert.deepEqual(audioContext.toJSON(), {
  name: "AudioDestinationNode"            // +------------------+
  inputs: [                               // | OscillatorNode   |
    {                                     // | - type: sawtooth |
      name: "GainNode",                   // | - frequency: 220 |
      gain: {                             // | - detune: 0      |
        value: 1,                         // +------------------+
        inputs: [                         //   |
          {                               // +-----------+  +--------------------+
            name: "OscillatorNode#LFO",   // | GainNode  |  | OscillatorNode#LFO |
            type: "sine",                 // | - gain: 1 |--| - frequency: 2     |
            frequency: {                  // +-----------+  | - detune: 0        |
              value: 2,                   //   |            +--------------------+
              inputs: []                  //   |
            },                            // +----------------------+
            detune: {                     // | AudioDestinationNode |
              value: 0,                   // +----------------------+
              inputs: []
            },
            inputs: []
          }
        ]
      },
      inputs: [
        {
          name: "OscillatorNode",
          type: "sawtooth",
          frequency: {
            value: 880,
            inputs: []
          },
          detune: {
            value: 0,
            inputs: []
          },
          inputs: []
        }
      ]
    }
  ]
});
  • OscillatorNode/BufferSourceNode state
var audioContext = new AudioContext();
var node = audioContext.createOscillator();

assert(node.$state === "UNSCHEDULED");

node.start(0.100);
node.stop(0.150);
node.connect(audioContext.destination);

audioContext.$processTo("00:00.000");
assert(node.$state === "SCHEDULED", "00:00.000");

audioContext.$processTo("00:00.099");
assert(node.$state === "SCHEDULED", "00:00.099");

audioContext.$processTo("00:00.100");
assert(node.$state === "PLAYING", "00:00.100");

audioContext.$processTo("00:00.149");
assert(node.$state === "PLAYING", "00:00.149");

audioContext.$processTo("00:00.150");
assert(node.$state === "FINISHED", "00:00.150");

// other way
assert(node.$stateAtTime("00:00.000") === "SCHEDULED");
assert(node.$stateAtTime("00:00.099") === "SCHEDULED");
assert(node.$stateAtTime("00:00.100") === "PLAYING");
assert(node.$stateAtTime("00:00.149") === "PLAYING");
assert(node.$stateAtTime("00:00.150") === "FINISHED");
  • AudioParam simulation
var audioContext = new AudioContext();
var node = audioContext.createOscillator();

node.frequency.setValueAtTime(880, 0.500);
node.frequency.linearRampToValueAtTime(440, 1.500);
node.connect(audioContext.destination);

audioContext.$processTo("00:00.000");
assert(node.frequency.value === 440, "00:00.000");

audioContext.$processTo("00:00.250");
assert(node.frequency.value === 440, "00:00.250");

audioContext.$processTo("00:00.500");
assert(node.frequency.value === 880, "00:00.500"); // <- setValueAtTime
                                                   //  ^
audioContext.$processTo("00:00.750");              //  |
assert(node.frequency.value === 770, "00:00.750"); //  |
                                                   //  |
audioContext.$processTo("00:01.000");              //  |
assert(node.frequency.value === 660, "00:01.000"); //  | linearRampToValueAtTime
                                                   //  |
audioContext.$processTo("00:01.250");              //  |
assert(node.frequency.value === 550, "00:01.250"); //  |
                                                   //  |
audioContext.$processTo("00:01.500");              //  v
assert(node.frequency.value === 440, "00:01.500"); //

audioContext.$processTo("00:01.750");
assert(node.frequency.value === 440, "00:01.750");

// other way
assert(node.frequency.$valueAtTime("00:00.000" === 440);
assert(node.frequency.$valueAtTime("00:00.250" === 440);
assert(node.frequency.$valueAtTime("00:00.500" === 880); // <- setValueAtTime
assert(node.frequency.$valueAtTime("00:00.750" === 770); //  ^
assert(node.frequency.$valueAtTime("00:01.000" === 660); //  | linearRampToValueAtTime
assert(node.frequency.$valueAtTime("00:01.250" === 550); //  v
assert(node.frequency.$valueAtTime("00:01.500" === 440); //
assert(node.frequency.$valueAtTime("00:01.750" === 440);
  • ScriptProcessing simulation
var audioContext = new AudioContext();
var node = audioContext.createScriptProcessor(1024, 2, 2);

node.onaudioprocess = sinon.spy();
node.connect(audioContext.destination);

audioContext.$processTo("00:00.500");
assert(node.onaudioprocess.callCount === 22);
// 22times call (0.5 / (1024 / 44100) = 21.5332)
  • DecodeAudioData simulation
var audioContext = new AudioContext();

// audioContext.DECODE_AUDIO_DATA_RESULT = customResult;
// audioContext.DECODE_AUDIO_DATA_FAILED = true;

audioContext.decodeAudioData(audioData, function(result) {
  // successCallback
  assert(result instanceof AudioBuffer);
}, function() {
  // errorCallback
  throw new ERROR("NOT REACHED");
});
  • New API support
WebAudioTestAPI.setState({
  "AudioContext#createStereoPanner": "enabled",
});

var audioContext = new AudioContext();

var node = audioContext.createStereoPanner();

console.log(WebAudioTestAPI.getState("AudioContext#createStereoPanner")); // "enabled"
API Name states
AnalyserNode#getFloatTimeDomainData "enabled" or "disabled"
AudioBuffer#copyToChannel "enabled" or "disabled"
AudioBuffer#copyFromChannel "enabled" or "disabled"
AudioContext#createAudioWorker "disabled"
AudioContext#createStereoPanner "enabled" or "disabled"
AudioContext#close "enabled" or "disabled"
AudioContext#suspend "enabled" or "disabled"
AudioContext#resume "enabled" or "disabled"
AudioContext#decodeAudioData "promise" or "void"
OfflineAudioContext#startRendering "promise" or "void"
AudioNode#disconnect "selective" or "channel"

License

web-audio-test-api.js is available under the The MIT License.