import Test from "helper/Test"; import Context from "Tone/core/Context"; import Tone from "Tone/core/Tone"; import Offline from "helper/Offline"; import Supports from "helper/Supports"; describe("Context", function(){ if (!Supports.AUDIO_CONTEXT_CLOSE_RESOLVES){ return; } context("AudioContext", function(){ it("extends the AudioContext methods", function(){ var ctx = new Context(); expect(ctx).to.have.property("createGain"); expect(ctx.createGain()).to.be.instanceOf(GainNode); expect(ctx).to.have.property("createOscillator"); expect(ctx.createOscillator()).to.be.instanceOf(OscillatorNode); expect(ctx).to.have.property("createDelay"); expect(ctx.createDelay()).to.be.instanceOf(DelayNode); expect(ctx).to.have.property("createConstantSource"); return ctx.dispose(); }); it("clock is running", function(done){ var interval = setInterval(function(){ if (Tone.context.currentTime > 0.5){ clearInterval(interval); done(); } }, 20); }); it("can be created an disposed", function(){ var ctx = new Context(); return ctx.dispose().then(function(){ Test.wasDisposed(ctx); }); }); it("has a rawContext", function(){ var ctx = new Context(); expect(ctx.rawContext).is.instanceOf(window.AudioContext); return ctx.dispose(); }); it("'dispose' returns a promise which resolves", function(){ var ctx = new Context(); var promise = ctx.dispose(); expect(promise).to.have.property("then"); return promise; }); it("can be constructed with an options object", function(){ var ctx = new Context({ "lookAhead" : 0.2, "latencyHint" : "fastest", "clockSource" : "timeout" }); expect(ctx.lookAhead).to.equal(0.2); expect(ctx.latencyHint).to.equal("fastest"); expect(ctx.clockSource).to.equal("timeout"); return ctx.dispose(); }); }); if (Supports.ONLINE_TESTING){ context("clockSource", function(){ var ctx; beforeEach(function(){ ctx = new Context(); return ctx.resume(); }); afterEach(function(){ return ctx.dispose(); }); it("defaults to 'worker'", function(){ expect(ctx.clockSource).to.equal("worker"); }); it("provides callback", function(done){ expect(ctx.clockSource).to.equal("worker"); ctx.setTimeout(function(){ done(); }, 0.1); }); it("can be set to 'timeout'", function(done){ ctx.clockSource = "timeout"; expect(ctx.clockSource).to.equal("timeout"); ctx.setTimeout(function(){ done(); }, 0.1); }); it("can be set to 'offline'", function(done){ ctx.clockSource = "offline"; expect(ctx.clockSource).to.equal("offline"); //provides no callback ctx.setTimeout(function(){ throw new Error("shouldn't be called"); }, 0.1); setTimeout(function(){ done(); }, 200); }); }); } context("setTimeout", function(){ if (Supports.ONLINE_TESTING){ var ctx; beforeEach(function(){ ctx = new Context(); return ctx.resume(); }); afterEach(function(){ return ctx.dispose(); }); it("can set a timeout", function(done){ ctx.setTimeout(function(){ done(); }, 0.1); }); it("returns an id", function(){ expect(ctx.setTimeout(function(){}, 0.1)).to.be.a("number"); //try clearing a random ID, shouldn't cause any errors ctx.clearTimeout(-2); }); it("timeout is not invoked when cancelled", function(done){ var id = ctx.setTimeout(function(){ throw new Error("shouldn't be invoked"); }, 0.01); ctx.clearTimeout(id); ctx.setTimeout(function(){ done(); }, 0.02); }); it("order is maintained", function(done){ var wasInvoked = false; ctx.setTimeout(function(){ expect(wasInvoked).to.be.true; done(); }, 0.02); ctx.setTimeout(function(){ wasInvoked = true; }, 0.01); }); } it("is invoked in the offline context", function(){ return Offline(function(Transport){ Transport.context.setTimeout(function(){ expect(Tone.now()).to.be.closeTo(0.01, 0.005); }, 0.01); }, 0.05); }); }); context("Tone", function(){ it("has a context", function(){ expect(Tone.context).to.exist; expect(Tone.context).to.be.instanceOf(Context); }); it("can set a new context", function(){ var originalContext = Tone.context; Tone.context = new Context(); return Tone.context.dispose().then(function(){ Tone.context = originalContext; }); }); it("has a consistent context after offline rendering", function(){ var initialContext = Tone.context; var initialTransport = Tone.Transport; return Offline(function(){}).then(function(){ expect(Tone.context).to.equal(initialContext); expect(Tone.Transport).to.equal(initialTransport); }); }); it("invokes the resume promise", function(){ return Tone.context.resume(); }); it("invokes init when a new context is set", function(done){ this.timeout(200); var initFn = function(context){ expect(Tone.context).to.equal(context); Context.off("init", initFn); done(); }; Context.on("init", initFn); Tone.context = new Context(); }); it("invokes close when a context is disposed", function(done){ this.timeout(200); var closeFn = function(context){ expect(context).to.be.instanceOf(Context); Context.off("close", closeFn); //set a new context Tone.context = new Context(); done(); }; Context.on("close", closeFn); Tone.context.dispose(); }); }); context("get/set", function(){ var ctx; beforeEach(function(){ ctx = new Context(); return ctx.resume(); }); afterEach(function(){ return ctx.dispose(); }); it("can set the lookAhead", function(){ ctx.lookAhead = 0.05; expect(ctx.lookAhead).to.equal(0.05); }); it("can set the updateInterval", function(){ ctx.updateInterval = 0.05; expect(ctx.updateInterval).to.equal(0.05); }); it("can set the latencyHint", function(){ ctx.latencyHint = "fastest"; expect(ctx.latencyHint).to.equal("fastest"); expect(ctx.lookAhead).to.be.closeTo(0.01, 0.05); expect(ctx.updateInterval).to.be.closeTo(0.01, 0.05); // test all other latency hints var latencyHints = ["interactive", "playback", "balanced", 0.2]; latencyHints.forEach(function(hint){ ctx.latencyHint = hint; expect(ctx.latencyHint).to.equal(hint); }); }); it("gets a constant signal", function(){ var bufferSrc = ctx.getConstant(1); expect(bufferSrc).is.instanceOf(AudioBufferSourceNode); var buffer = bufferSrc.buffer.getChannelData(0); for (var i = 0; i < buffer.length; i++){ expect(buffer[i]).to.equal(1); } }); it("multiple calls return the same buffer source", function(){ var bufferA = ctx.getConstant(2); var bufferB = ctx.getConstant(2); expect(bufferA).to.equal(bufferB); }); }); });