import { Gain } from "../../core/context/Gain";
import { connect, ToneAudioNode } from "../../core/context/ToneAudioNode";
import { optionsFromArguments } from "../../core/util/Defaults";
import { readOnly } from "../../core/util/Interface";
import { GainToAudio } from "../../signal/GainToAudio";
import { Signal } from "../../signal/Signal";
/**
 * Tone.Crossfade provides equal power fading between two inputs.
 * More on crossfading technique [here](https://en.wikipedia.org/wiki/Fade_(audio_engineering)#Crossfading).
 * ```
 *                                             +---------+
 *                                            +> input a +>--+
 * +-----------+   +---------------------+     |         |   |
 * | 1s signal +>--> stereoPannerNode  L +>----> gain    |   |
 * +-----------+   |                     |     +---------+   |
 *               +-> pan               R +>-+                |   +--------+
 *               | +---------------------+  |                +---> output +>
 *  +------+     |                          |  +---------+   |   +--------+
 *  | fade +>----+                          | +> input b +>--+
 *  +------+                                |  |         |
 *                                          +--> gain    |
 *                                             +---------+
 * ```
 * @example
 * const crossFade = new Tone.CrossFade().toDestination();
 * // connect two inputs Tone.to a/b
 * const inputA = new Tone.Oscillator(440, "square").connect(crossFade.a).start();
 * const inputB = new Tone.Oscillator(440, "sine").connect(crossFade.b).start();
 * // use the fade to control the mix between the two
 * crossFade.fade.value = 0.5;
 * @category Component
 */
export class CrossFade extends ToneAudioNode {
    constructor() {
        super(Object.assign(optionsFromArguments(CrossFade.getDefaults(), arguments, ["fade"])));
        this.name = "CrossFade";
        /**
         * The crossfading is done by a StereoPannerNode
         */
        this._panner = this.context.createStereoPanner();
        /**
         * Split the output of the panner node into two values used to control the gains.
         */
        this._split = this.context.createChannelSplitter(2);
        /**
         * Convert the fade value into an audio range value so it can be connected
         * to the panner.pan AudioParam
         */
        this._g2a = new GainToAudio({ context: this.context });
        /**
         * The input which is at full level when fade = 0
         */
        this.a = new Gain({
            context: this.context,
            gain: 0,
        });
        /**
         * The input which is at full level when fade = 1
         */
        this.b = new Gain({
            context: this.context,
            gain: 0,
        });
        /**
         * The output is a mix between `a` and `b` at the ratio of `fade`
         */
        this.output = new Gain({ context: this.context });
        this._internalChannels = [this.a, this.b];
        const options = optionsFromArguments(CrossFade.getDefaults(), arguments, ["fade"]);
        this.fade = new Signal({
            context: this.context,
            units: "normalRange",
            value: options.fade,
        });
        readOnly(this, "fade");
        this.context.getConstant(1).connect(this._panner);
        this._panner.connect(this._split);
        // this is necessary for standardized-audio-context
        // doesn't make any difference for the native AudioContext
        // https://github.com/chrisguttandin/standardized-audio-context/issues/647
        this._panner.channelCount = 1;
        this._panner.channelCountMode = "explicit";
        connect(this._split, this.a.gain, 0);
        connect(this._split, this.b.gain, 1);
        this.fade.chain(this._g2a, this._panner.pan);
        this.a.connect(this.output);
        this.b.connect(this.output);
    }
    static getDefaults() {
        return Object.assign(ToneAudioNode.getDefaults(), {
            fade: 0.5,
        });
    }
    dispose() {
        super.dispose();
        this.a.dispose();
        this.b.dispose();
        this.output.dispose();
        this.fade.dispose();
        this._g2a.dispose();
        this._panner.disconnect();
        this._split.disconnect();
        return this;
    }
}
//# sourceMappingURL=CrossFade.js.map