define(["Tone/core/Tone", "Tone/component/Volume", "Tone/core/Context", "Tone/core/AudioNode"], function(Tone){ "use strict"; /** * @class 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. *

* Like Tone.Transport, A single Tone.Master is created * on initialization and you do not need to explicitly construct one. * * @constructor * @extends {Tone} * @singleton * @example * //the audio will go from the oscillator to the speakers * oscillator.connect(Tone.Master); * //a convenience for connecting to the master output is also provided: * oscillator.toMaster(); * //the above two examples are equivalent. */ Tone.Master = function(){ Tone.AudioNode.call(this); Tone.getContext(function(){ this.createInsOuts(1, 0); /** * The private volume node * @type {Tone.Volume} * @private */ this._volume = this.output = new Tone.Volume(); /** * The volume of the master output. * @type {Decibels} * @signal */ this.volume = this._volume.volume; this._readOnly("volume"); //connections this.input.chain(this.output, this.context.destination); }.bind(this)); }; Tone.extend(Tone.Master, Tone.AudioNode); /** * @type {Object} * @const */ Tone.Master.defaults = { "volume" : 0, "mute" : false }; /** * Mute the output. * @memberOf Tone.Master# * @type {boolean} * @name mute * @example * //mute the output * Tone.Master.mute = true; */ Object.defineProperty(Tone.Master.prototype, "mute", { get : function(){ return this._volume.mute; }, set : function(mute){ this._volume.mute = mute; } }); /** * Add a master effects chain. NOTE: this will disconnect any nodes which were previously * chained in the master effects chain. * @param {AudioNode|Tone} args... All arguments will be connected in a row * and the Master will be routed through it. * @return {Tone.Master} this * @example * //some overall compression to keep the levels in check * var masterCompressor = new Tone.Compressor({ * "threshold" : -6, * "ratio" : 3, * "attack" : 0.5, * "release" : 0.1 * }); * //give a little boost to the lows * var lowBump = new Tone.Filter(200, "lowshelf"); * //route everything through the filter * //and compressor before going to the speakers * Tone.Master.chain(lowBump, masterCompressor); */ Tone.Master.prototype.chain = function(){ this.input.disconnect(); this.input.chain.apply(this.input, arguments); arguments[arguments.length - 1].connect(this.output); }; /** * Clean up * @return {Tone.Master} this */ Tone.Master.prototype.dispose = function(){ Tone.AudioNode.prototype.dispose.call(this); this._writable("volume"); this._volume.dispose(); this._volume = null; this.volume = null; }; /////////////////////////////////////////////////////////////////////////// // AUGMENT TONE's PROTOTYPE /////////////////////////////////////////////////////////////////////////// /** * Connect 'this' to the master output. Shorthand for this.connect(Tone.Master) * @returns {Tone.AudioNode} this * @example * //connect an oscillator to the master output * var osc = new Tone.Oscillator().toMaster(); */ Tone.AudioNode.prototype.toMaster = function(){ this.connect(Tone.Master); return this; }; if (window.AudioNode){ // Also augment AudioNode's prototype to include toMaster as a convenience AudioNode.prototype.toMaster = function(){ this.connect(Tone.Master); return this; }; } /** * initialize the module and listen for new audio contexts */ var MasterConstructor = Tone.Master; Tone.Master = new MasterConstructor(); Tone.Context.on("init", function(context){ // if it already exists, just restore it if (context.Master instanceof MasterConstructor){ Tone.Master = context.Master; } else { Tone.Master = new MasterConstructor(); } context.Master = Tone.Master; }); Tone.Context.on("close", function(context){ if (context.Master instanceof MasterConstructor){ context.Master.dispose(); } }); return Tone.Master; });