import { InputNode, ToneAudioNode, ToneAudioNodeOptions } from "../../core/context/ToneAudioNode"; import { Compressor, CompressorOptions } from "./Compressor"; import { optionsFromArguments } from "../../core/util/Defaults"; import { readOnly, RecursivePartial } from "../../core/util/Interface"; import { Frequency } from "../../core/type/Units"; import { MultibandSplit } from "../channel/MultibandSplit"; import { Signal } from "../../signal/Signal"; import { Gain } from "../../core/context/Gain"; export interface MultibandCompressorOptions extends ToneAudioNodeOptions { mid: Omit; low: Omit; high: Omit; lowFrequency: Frequency; highFrequency: Frequency; } /** * A compressor with separate controls over low/mid/high dynamics. See [[Compressor]] and [[MultibandSplit]] * * @example * const multiband = new Tone.MultibandCompressor({ * lowFrequency: 200, * highFrequency: 1300, * low: { * threshold: -12 * } * }); */ export class MultibandCompressor extends ToneAudioNode { readonly name: string = "MultibandCompressor"; readonly input: InputNode; readonly output: ToneAudioNode; /** * Split the incoming signal into high/mid/low */ private _splitter: MultibandSplit; /** * low/mid crossover frequency. */ readonly lowFrequency: Signal<"frequency">; /** * mid/high crossover frequency. */ readonly highFrequency: Signal<"frequency">; /** * The compressor applied to the low frequencies */ readonly low: Compressor; /** * The compressor applied to the mid frequencies */ readonly mid: Compressor; /** * The compressor applied to the high frequencies */ readonly high: Compressor; constructor(options?: RecursivePartial); constructor() { super(Object.assign(optionsFromArguments(MultibandCompressor.getDefaults(), arguments))); const options = optionsFromArguments(MultibandCompressor.getDefaults(), arguments); this._splitter = this.input = new MultibandSplit({ context: this.context, lowFrequency: options.lowFrequency, highFrequency: options.highFrequency }); this.lowFrequency = this._splitter.lowFrequency; this.highFrequency = this._splitter.highFrequency; this.output = new Gain({ context: this.context }); this.low = new Compressor(Object.assign(options.low, { context: this.context })); this.mid = new Compressor(Object.assign(options.mid, { context: this.context })); this.high = new Compressor(Object.assign(options.high, { context: this.context })); // connect the compressor this._splitter.low.chain(this.low, this.output); this._splitter.mid.chain(this.mid, this.output); this._splitter.high.chain(this.high, this.output); readOnly(this, ["high", "mid", "low", "highFrequency", "lowFrequency"]); } static getDefaults(): MultibandCompressorOptions { return Object.assign(ToneAudioNode.getDefaults(), { lowFrequency: 250, highFrequency: 2000, low: { ratio: 6, threshold: -30, release: 0.25, attack: 0.03, knee: 10 }, mid: { ratio: 3, threshold: -24, release: 0.03, attack: 0.02, knee: 16 }, high: { ratio: 3, threshold: -24, release: 0.03, attack: 0.02, knee: 16 }, }); } dispose(): this { super.dispose(); this._splitter.dispose(); this.low.dispose(); this.mid.dispose(); this.high.dispose(); this.output.dispose(); return this; } }