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:
- Make your changes
- Bump the version in package.json
- 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
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.