Web Audio API test library for CI
replace existing Web Audio API with web-audio-test-api
<script src="/path/to/web-audio-test-api.js"></script>
set WEB_AUDIO_TEST_API_IGNORE
flag if you won't use web-audio-test-api
WEB_AUDIO_TEST_API_IGNORE = true;
<script src="/path/to/web-audio-test-api.js"></script>
% npm install web-audio-test-api
install Web Audio API interfaces as global variables
require("web-audio-test-api");
describe("Strict Type Check", function() {
var ctx = new AudioContext();
var osc = ctx.createOsillator();
it("throw error if uses wrong", function() {
expect(function() {
osc.frequency = 880;
}, "uses wrong").to.throw(Error, "OscillatorNode#frequency is readonly");
expect(function() {
osc.frequency.value = 880;
}, "uses correctly").to.not.throw();
});
it("throw error if receives an invalid value", function() {
expect(function() {
osc.type = 2;
}).to.throw(Error,
"OscillatorNode#type should be any [ sine, square, sawtooth, triangle, custom ], but got 2"
);
});
});
describe("Modular Routine", function() {
it("should generate audio graph", function() {
var ctx = new AudioContext();
var osc = ctx.createOscillator();
var lfo = ctx.createOscillator();
var amp = ctx.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(ctx.destination);
// ctx.VERBOSE_JSON = true; // set this flag if you need more detailed data
expect(ctx.toJSON()).to.eql({
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: []
}
]
}
]
});
});
});
describe("OscillatorNode#$stateAtTime(t)", function() {
it("works", function() {
var ctx = new AudioContext();
var osc = ctx.createOscillator();
expect(osc.$state).to.equal("UNSCHEDULED");
osc.start(1);
osc.stop(2);
expect(osc.$stateAtTime(0.5)).to.equal("SCHEDULED");
expect(osc.$stateAtTime(1.5)).to.equal("PLAYING");
expect(osc.$stateAtTime(2.5)).to.equal("FINISHED");
});
it("with audioContext.$process()", function() {
var ctx = new AudioContext();
var osc = ctx.createOscillator();
expect(osc.$state).to.equal("UNSCHEDULED");
osc.start(1);
osc.stop(2);
expect(osc.$state, "00:00.000").to.equal("SCHEDULED");
ctx.$processTo("00:00.500");
expect(osc.$state, "00:00.500").to.equal("SCHEDULED");
ctx.$processTo("00:01.000");
expect(osc.$state, "00:01.000").to.equal("PLAYING");
ctx.$processTo("00:01.500");
expect(osc.$state, "00:01.500").to.equal("PLAYING");
ctx.$processTo("00:02.000");
expect(osc.$state, "00:02.000").to.equal("FINISHED");
ctx.$processTo("00:02.500");
expect(osc.$state, "00:02.500").to.equal("FINISHED");
});
});
describe("AudioParam", function() {
it("works", function() {
var ctx = new AudioContext();
var osc = ctx.createOscillator();
osc.frequency.setValueAtTime(880, 0.5);
osc.frequency.linearRampToValueAtTime(440, 1.5);
expect(osc.frequency.$valueAtTime(0.000), "00:00.000").to.equal(440);
expect(osc.frequency.$valueAtTime(0.250), "00:00.250").to.equal(440);
expect(osc.frequency.$valueAtTime(0.500), "00:00.500").to.equal(880); // <- setValueAtTime
expect(osc.frequency.$valueAtTime(0.750), "00:00.750").to.equal(770); // ^
expect(osc.frequency.$valueAtTime(1.000), "00:01.000").to.equal(660); // | linearRampToValueAtTime
expect(osc.frequency.$valueAtTime(1.250), "00:01.250").to.equal(550); // v
expect(osc.frequency.$valueAtTime(1.500), "00:01.500").to.equal(440); //
expect(osc.frequency.$valueAtTime(1.750), "00:01.750").to.equal(440);
});
it("with audioContext$process()", function() {
var ctx = new AudioContext();
var osc = ctx.createOscillator();
osc.frequency.setValueAtTime(880, 0.5);
osc.frequency.linearRampToValueAtTime(440, 1.5);
expect(osc.frequency.value, "00:00.000").to.equal(440);
ctx.$processTo("00:00.250");
expect(osc.frequency.value, "00:00.250").to.equal(440);
ctx.$processTo("00:00.500");
expect(osc.frequency.value, "00:00.500").to.equal(880); // <- setValueAtTime
// ^
ctx.$processTo("00:00.750"); // |
expect(osc.frequency.value, "00:00.750").to.equal(770); // |
// |
ctx.$processTo("00:01.000"); // |
expect(osc.frequency.value, "00:01.000").to.equal(660); // | linearRampToValueAtTime
// |
ctx.$processTo("00:01.250"); // |
expect(osc.frequency.value, "00:01.250").to.equal(550); // |
// |
ctx.$processTo("00:01.500"); // v
expect(osc.frequency.value, "00:01.500").to.equal(440); //
ctx.$processTo("00:01.750");
expect(osc.frequency.value, "00:01.750").to.equal(440);
});
});
describe("ScriptProcessorNode#onaudioprocess(e)", function() {
it("works", function() {
var ctx = new AudioContext();
var scp = ctx.createScriptProcessor(1024, 2, 2);
var count = 0;
scp.onaudioprocess = function(e) {
count += 1;
};
ctx.$process(0.5); // advance 0.5 sec
expect(count).to.equal(22); // 22times call (0.5 / (1024 / 44100) = 21.5332)
});
});
describe("AudioContext#decodeAudioData()", function() {
it("should return decoded buffer in async", function(done) {
var ctx = new AudioContext();
// ctx.DECODE_AUDIO_DATA_RESULT = customResult;
// ctx.DECODE_AUDIO_DATA_FAILED = true;
ctx.decodeAudioData(audioData, function(result) {
// successCallback
expect(result).to.be.instanceOf(AudioBuffer);
done();
}, function() {
// errorCallback
throw new ERROR("NOT REACHED");
});
});
});
web-audio-test-api.js is available under the The MIT License.