2019-06-23 19:02:38 +00:00
|
|
|
import { getContext, setContext } from "../Global";
|
2019-07-30 19:35:27 +00:00
|
|
|
import { Seconds } from "../type/Units";
|
2019-06-17 18:04:17 +00:00
|
|
|
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
|
2019-07-25 15:32:56 +00:00
|
|
|
* var oscillator = new Tone.Oscillator().toDestination().start(0)
|
2019-06-17 18:04:17 +00:00
|
|
|
* //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){
|
2019-07-25 15:32:56 +00:00
|
|
|
* var osc = new Tone.Oscillator().toDestination()
|
2019-06-17 18:04:17 +00:00
|
|
|
* 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
|
|
|
|
* })
|
2019-08-26 17:44:43 +00:00
|
|
|
* @category Core
|
2019-06-17 18:04:17 +00:00
|
|
|
*/
|
|
|
|
export async function Offline(
|
|
|
|
callback: (context: OfflineContext) => Promise<void> | void,
|
|
|
|
duration: Seconds,
|
|
|
|
channels: number = 2,
|
2019-06-23 19:02:38 +00:00
|
|
|
sampleRate: number = getContext().sampleRate,
|
2019-06-17 18:04:17 +00:00
|
|
|
): Promise<ToneAudioBuffer> {
|
|
|
|
// set the OfflineAudioContext based on the current context
|
2019-06-23 19:02:38 +00:00
|
|
|
const originalContext = getContext();
|
2019-06-17 18:04:17 +00:00
|
|
|
|
|
|
|
const context = new OfflineContext(channels, duration, sampleRate);
|
2019-06-23 19:02:38 +00:00
|
|
|
setContext(context);
|
2019-06-17 18:04:17 +00:00
|
|
|
|
|
|
|
// invoke the callback/scheduling
|
|
|
|
await callback(context);
|
|
|
|
|
|
|
|
// then render the audio
|
2019-07-26 15:45:11 +00:00
|
|
|
const bufferPromise = context.render();
|
2019-06-17 18:04:17 +00:00
|
|
|
|
|
|
|
// return the original AudioContext
|
2019-06-23 19:02:38 +00:00
|
|
|
setContext(originalContext);
|
2019-06-17 18:04:17 +00:00
|
|
|
|
2019-07-26 15:45:11 +00:00
|
|
|
// await the rendering
|
|
|
|
const buffer = await bufferPromise;
|
|
|
|
|
2019-06-17 18:04:17 +00:00
|
|
|
// return the audio
|
|
|
|
return new ToneAudioBuffer(buffer);
|
|
|
|
}
|