2019-07-11 13:57:06 +00:00
|
|
|
import { Volume } from "../../component/channel/Volume";
|
2019-07-30 19:35:27 +00:00
|
|
|
import { Decibels } from "../type/Units";
|
2019-06-23 19:03:04 +00:00
|
|
|
import { optionsFromArguments } from "../util/Defaults";
|
2019-07-16 19:41:59 +00:00
|
|
|
import { onContextClose, onContextInit } from "./ContextInitialization";
|
2019-06-23 19:03:04 +00:00
|
|
|
import { Gain } from "./Gain";
|
|
|
|
import { Param } from "./Param";
|
2020-01-08 19:12:11 +00:00
|
|
|
import { connectSeries, ToneAudioNode, ToneAudioNodeOptions } from "./ToneAudioNode";
|
2019-06-23 19:03:04 +00:00
|
|
|
|
|
|
|
interface DestinationOptions extends ToneAudioNodeOptions {
|
|
|
|
volume: Decibels;
|
|
|
|
mute: boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-08-27 17:02:31 +00:00
|
|
|
* A single master output which is connected to the
|
|
|
|
* AudioDestinationNode (aka your speakers).
|
|
|
|
* It provides useful conveniences such as the ability
|
|
|
|
* to set the volume and mute the entire application.
|
|
|
|
* It also gives you the ability to apply master effects to your application.
|
2019-06-23 19:03:04 +00:00
|
|
|
*
|
2019-08-27 17:02:31 +00:00
|
|
|
* @example
|
2020-04-17 02:24:18 +00:00
|
|
|
* const oscillator = new Tone.Oscillator().start();
|
2019-10-23 20:30:07 +00:00
|
|
|
* // the audio will go from the oscillator to the speakers
|
2020-04-17 02:24:18 +00:00
|
|
|
* oscillator.connect(Tone.Destination);
|
2019-10-23 20:30:07 +00:00
|
|
|
* // a convenience for connecting to the master output is also provided:
|
2019-07-25 15:32:56 +00:00
|
|
|
* oscillator.toDestination();
|
2019-10-23 20:30:07 +00:00
|
|
|
* // these two are equivalent.
|
2019-08-26 17:44:43 +00:00
|
|
|
* @category Core
|
2019-06-23 19:03:04 +00:00
|
|
|
*/
|
|
|
|
export class Destination extends ToneAudioNode<DestinationOptions> {
|
|
|
|
|
2019-09-04 23:18:44 +00:00
|
|
|
readonly name: string = "Destination";
|
2019-06-23 19:03:04 +00:00
|
|
|
|
|
|
|
input: Volume = new Volume({ context: this.context });
|
2019-09-16 03:32:40 +00:00
|
|
|
output: Gain = new Gain({ context: this.context });
|
2019-06-23 19:03:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The volume of the master output.
|
|
|
|
*/
|
2019-10-28 15:37:53 +00:00
|
|
|
volume: Param<"decibels"> = this.input.volume;
|
2019-06-23 19:03:04 +00:00
|
|
|
|
|
|
|
constructor(options: Partial<DestinationOptions>);
|
|
|
|
constructor() {
|
|
|
|
|
|
|
|
super(optionsFromArguments(Destination.getDefaults(), arguments));
|
|
|
|
const options = optionsFromArguments(Destination.getDefaults(), arguments);
|
|
|
|
|
|
|
|
connectSeries(this.input, this.output, this.context.rawContext.destination);
|
|
|
|
|
|
|
|
this.mute = options.mute;
|
2020-03-02 03:03:37 +00:00
|
|
|
this._internalChannels = [this.input, this.context.rawContext.destination, this.output];
|
2019-06-23 19:03:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static getDefaults(): DestinationOptions {
|
|
|
|
return Object.assign(ToneAudioNode.getDefaults(), {
|
|
|
|
mute: false,
|
|
|
|
volume: 0,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mute the output.
|
|
|
|
* @example
|
2020-04-17 02:24:18 +00:00
|
|
|
* const oscillator = new Tone.Oscillator().start().toDestination();
|
2019-10-23 20:30:07 +00:00
|
|
|
* // mute the output
|
2020-04-17 02:24:18 +00:00
|
|
|
* Tone.Destination.mute = true;
|
2019-06-23 19:03:04 +00:00
|
|
|
*/
|
|
|
|
get mute(): boolean {
|
|
|
|
return this.input.mute;
|
|
|
|
}
|
|
|
|
|
|
|
|
set mute(mute: boolean) {
|
|
|
|
this.input.mute = mute;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* Add a master effects chain. NOTE: this will disconnect any nodes which were previously
|
|
|
|
* chained in the master effects chain.
|
2019-10-23 03:04:52 +00:00
|
|
|
* @param args All arguments will be connected in a row and the Master will be routed through it.
|
2019-08-30 16:06:38 +00:00
|
|
|
* @return {Destination} this
|
|
|
|
* @example
|
2019-10-23 20:30:07 +00:00
|
|
|
* // some overall compression to keep the levels in check
|
2020-04-17 02:24:18 +00:00
|
|
|
* const masterCompressor = new Tone.Compressor({
|
2019-10-23 20:30:07 +00:00
|
|
|
* threshold: -6,
|
|
|
|
* ratio: 3,
|
|
|
|
* attack: 0.5,
|
|
|
|
* release: 0.1
|
2019-06-23 19:03:04 +00:00
|
|
|
* });
|
2019-10-23 20:30:07 +00:00
|
|
|
* // give a little boost to the lows
|
2020-04-17 02:24:18 +00:00
|
|
|
* const lowBump = new Tone.Filter(200, "lowshelf");
|
2019-10-23 20:30:07 +00:00
|
|
|
* // route everything through the filter and compressor before going to the speakers
|
2020-04-17 02:24:18 +00:00
|
|
|
* Tone.Destination.chain(lowBump, masterCompressor);
|
2019-06-23 19:03:04 +00:00
|
|
|
*/
|
|
|
|
chain(...args: Array<AudioNode | ToneAudioNode>): this {
|
|
|
|
this.input.disconnect();
|
|
|
|
args.unshift(this.input);
|
|
|
|
args.push(this.output);
|
|
|
|
connectSeries(...args);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-03-02 03:03:37 +00:00
|
|
|
/**
|
|
|
|
* The maximum number of channels the system can output
|
|
|
|
*/
|
|
|
|
get maxChannelCount(): number {
|
|
|
|
return this.context.rawContext.destination.maxChannelCount;
|
|
|
|
}
|
|
|
|
|
2019-06-23 19:03:04 +00:00
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* Clean up
|
2019-06-23 19:03:04 +00:00
|
|
|
*/
|
|
|
|
dispose(): this {
|
|
|
|
super.dispose();
|
|
|
|
this.volume.dispose();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-14 22:06:46 +00:00
|
|
|
//-------------------------------------
|
2019-06-23 19:03:04 +00:00
|
|
|
// INITIALIZATION
|
2019-09-14 22:06:46 +00:00
|
|
|
//-------------------------------------
|
2019-06-23 19:03:04 +00:00
|
|
|
|
2019-07-11 13:57:06 +00:00
|
|
|
onContextInit(context => {
|
2019-06-23 19:03:04 +00:00
|
|
|
context.destination = new Destination({ context });
|
|
|
|
});
|
2019-07-16 19:41:59 +00:00
|
|
|
|
|
|
|
onContextClose(context => {
|
|
|
|
context.destination.dispose();
|
|
|
|
});
|