mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 00:27:58 +00:00
converting Offline
This commit is contained in:
parent
5100fe8e3f
commit
f83fa7954a
2 changed files with 143 additions and 0 deletions
82
Tone/core/context/Offline.test.ts
Normal file
82
Tone/core/context/Offline.test.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { expect } from "chai";
|
||||
import { noOp } from "../util/Interface";
|
||||
import { Offline } from "./Offline";
|
||||
import { ToneAudioBuffer } from "./ToneAudioBuffer";
|
||||
// import Transport from "Tone/core/Transport";
|
||||
// import Oscillator from "Tone/source/Oscillator";
|
||||
// import Tone from "Tone/core/Tone";
|
||||
// import AudioBuffer from "Tone/core/Buffer";
|
||||
// import BufferTest from "helper/BufferTest";
|
||||
|
||||
describe("Offline", () => {
|
||||
|
||||
it("accepts a callback and a duration", () => {
|
||||
Offline(noOp, 0.01);
|
||||
});
|
||||
|
||||
it("returns a promise", () => {
|
||||
expect(Offline(noOp, 0.01)).to.have.property("then");
|
||||
});
|
||||
|
||||
it("generates a buffer", (done) => {
|
||||
Offline(noOp, 0.01).then((buffer) => {
|
||||
expect(buffer).to.be.instanceOf(ToneAudioBuffer);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("silent by default", (done) => {
|
||||
Offline(noOp, 0.01, 1).then((buffer) => {
|
||||
const isSilent = buffer.toArray().every(sample => sample === 0);
|
||||
expect(isSilent).to.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// it("records the master output", () => {
|
||||
// return Offline(() => {
|
||||
// new Oscillator().toMaster().start();
|
||||
// }, 0.01).then((buffer) => {
|
||||
// BufferTest(buffer);
|
||||
// expect(buffer.isSilent()).to.be.false;
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("returning a promise defers the rendering till the promise resolves", () => {
|
||||
// var wasInvoked = false;
|
||||
// return Offline(() => {
|
||||
// new Oscillator().toMaster().start();
|
||||
// return new Promise((done) => {
|
||||
// setTimeout(done, 100);
|
||||
// }).then(() => {
|
||||
// wasInvoked = true;
|
||||
// });
|
||||
// }, 0.01).then((buffer) => {
|
||||
// BufferTest(buffer);
|
||||
// expect(wasInvoked).to.be.true;
|
||||
// expect(buffer.isSilent()).to.be.false;
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("can schedule specific timing outputs", () => {
|
||||
// return Offline(() => {
|
||||
// new Oscillator().toMaster().start(0.05);
|
||||
// }, 0.1).then((buffer) => {
|
||||
// BufferTest(buffer);
|
||||
// expect(buffer.getFirstSoundTime()).to.be.closeTo(0.05, 0.0001);
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("can schedule Transport events", () => {
|
||||
// return Offline(function (Transport) {
|
||||
// var osc = new Oscillator().toMaster();
|
||||
// Transport.schedule(function (time) {
|
||||
// osc.start(time);
|
||||
// }, 0.05);
|
||||
// Transport.start(0);
|
||||
// }, 0.1).then((buffer) => {
|
||||
// BufferTest(buffer);
|
||||
// expect(buffer.getFirstSoundTime()).to.be.closeTo(0.05, 0.001);
|
||||
// });
|
||||
// });
|
||||
});
|
61
Tone/core/context/Offline.ts
Normal file
61
Tone/core/context/Offline.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { Context } from "./Context"
|
||||
import { OfflineContext } from "./OfflineContext";
|
||||
import { ToneAudioBuffer } from "./ToneAudioBuffer";
|
||||
|
||||
/**
|
||||
* Generate a buffer by rendering all of the Tone.js code within the callback using the OfflineAudioContext.
|
||||
* The OfflineAudioContext is capable of rendering much faster than real time in many cases.
|
||||
* The callback function also passes in an offline instance of Tone.Transport which can be used
|
||||
* to schedule events along the Transport. **NOTE** OfflineAudioContext has the same restrictions
|
||||
* as the AudioContext in that on certain platforms (like iOS) it must be invoked by an explicit
|
||||
* user action like a click or tap.
|
||||
* @param callback All Tone.js nodes which are created and scheduled
|
||||
* within this callback are recorded into the output Buffer.
|
||||
* @param duration the amount of time to record for.
|
||||
* @return The promise which is invoked with the Tone.Buffer of the recorded output.
|
||||
* @example
|
||||
* //render 2 seconds of the oscillator
|
||||
* Tone.Offline(function(){
|
||||
* //only nodes created in this callback will be recorded
|
||||
* var oscillator = new Tone.Oscillator().toMaster().start(0)
|
||||
* //schedule their events
|
||||
* }, 2).then(function(buffer){
|
||||
* //do something with the output buffer
|
||||
* })
|
||||
* @example
|
||||
* //can also schedule events along the Transport
|
||||
* //using the passed in Offline Transport
|
||||
* Tone.Offline(function(Transport){
|
||||
* var osc = new Tone.Oscillator().toMaster()
|
||||
* Transport.schedule(function(time){
|
||||
* osc.start(time).stop(time + 0.1)
|
||||
* }, 1)
|
||||
* Transport.start(0.2)
|
||||
* }, 4).then(function(buffer){
|
||||
* //do something with the output buffer
|
||||
* })
|
||||
*/
|
||||
export async function Offline(
|
||||
callback: (context: OfflineContext) => Promise<void> | void,
|
||||
duration: Seconds,
|
||||
channels: number = 2,
|
||||
sampleRate: number = Context.getGlobal().sampleRate,
|
||||
): Promise<ToneAudioBuffer> {
|
||||
// set the OfflineAudioContext based on the current context
|
||||
const originalContext = Context.getGlobal();
|
||||
|
||||
const context = new OfflineContext(channels, duration, sampleRate);
|
||||
Context.setGlobal(context);
|
||||
|
||||
// invoke the callback/scheduling
|
||||
await callback(context);
|
||||
|
||||
// then render the audio
|
||||
const buffer = await context.render();
|
||||
|
||||
// return the original AudioContext
|
||||
Context.setGlobal(originalContext);
|
||||
|
||||
// return the audio
|
||||
return new ToneAudioBuffer(buffer);
|
||||
}
|
Loading…
Reference in a new issue