mirror of
https://github.com/Tonejs/Tone.js
synced 2024-12-27 12:03:12 +00:00
142 lines
3.4 KiB
TypeScript
142 lines
3.4 KiB
TypeScript
import { optionsFromArguments } from "../../core/util/Defaults.js";
|
|
import { Frequency, Hertz, NormalRange, Time } from "../../core/type/Units.js";
|
|
import { Envelope, EnvelopeOptions } from "./Envelope.js";
|
|
import { Scale } from "../../signal/Scale.js";
|
|
import { Pow } from "../../signal/Pow.js";
|
|
import { assertRange } from "../../core/util/Debug.js";
|
|
|
|
export interface FrequencyEnvelopeOptions extends EnvelopeOptions {
|
|
baseFrequency: Frequency;
|
|
octaves: number;
|
|
exponent: number;
|
|
}
|
|
/**
|
|
* FrequencyEnvelope is an {@link Envelope} which ramps between {@link baseFrequency}
|
|
* and {@link octaves}. It can also have an optional {@link exponent} to adjust the curve
|
|
* which it ramps.
|
|
* @example
|
|
* const oscillator = new Tone.Oscillator().toDestination().start();
|
|
* const freqEnv = new Tone.FrequencyEnvelope({
|
|
* attack: 0.2,
|
|
* baseFrequency: "C2",
|
|
* octaves: 4
|
|
* });
|
|
* freqEnv.connect(oscillator.frequency);
|
|
* freqEnv.triggerAttack();
|
|
* @category Component
|
|
*/
|
|
export class FrequencyEnvelope extends Envelope {
|
|
readonly name: string = "FrequencyEnvelope";
|
|
|
|
/**
|
|
* Private reference to the base frequency as a number
|
|
*/
|
|
private _baseFrequency: Hertz;
|
|
|
|
/**
|
|
* The number of octaves
|
|
*/
|
|
private _octaves: number;
|
|
|
|
/**
|
|
* Internal scaler from 0-1 to the final output range
|
|
*/
|
|
private _scale: Scale;
|
|
|
|
/**
|
|
* Apply a power curve to the output
|
|
*/
|
|
private _exponent: Pow;
|
|
|
|
/**
|
|
* @param attack the attack time in seconds
|
|
* @param decay the decay time in seconds
|
|
* @param sustain a percentage (0-1) of the full amplitude
|
|
* @param release the release time in seconds
|
|
*/
|
|
constructor(
|
|
attack?: Time,
|
|
decay?: Time,
|
|
sustain?: NormalRange,
|
|
release?: Time
|
|
);
|
|
constructor(options?: Partial<FrequencyEnvelopeOptions>);
|
|
constructor() {
|
|
const options = optionsFromArguments(
|
|
FrequencyEnvelope.getDefaults(),
|
|
arguments,
|
|
["attack", "decay", "sustain", "release"]
|
|
);
|
|
super(options);
|
|
|
|
this._octaves = options.octaves;
|
|
this._baseFrequency = this.toFrequency(options.baseFrequency);
|
|
|
|
this._exponent = this.input = new Pow({
|
|
context: this.context,
|
|
value: options.exponent,
|
|
});
|
|
this._scale = this.output = new Scale({
|
|
context: this.context,
|
|
min: this._baseFrequency,
|
|
max: this._baseFrequency * Math.pow(2, this._octaves),
|
|
});
|
|
this._sig.chain(this._exponent, this._scale);
|
|
}
|
|
|
|
static getDefaults(): FrequencyEnvelopeOptions {
|
|
return Object.assign(Envelope.getDefaults(), {
|
|
baseFrequency: 200,
|
|
exponent: 1,
|
|
octaves: 4,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* The envelope's minimum output value. This is the value which it
|
|
* starts at.
|
|
*/
|
|
get baseFrequency(): Frequency {
|
|
return this._baseFrequency;
|
|
}
|
|
set baseFrequency(min) {
|
|
const freq = this.toFrequency(min);
|
|
assertRange(freq, 0);
|
|
this._baseFrequency = freq;
|
|
this._scale.min = this._baseFrequency;
|
|
// update the max value when the min changes
|
|
this.octaves = this._octaves;
|
|
}
|
|
|
|
/**
|
|
* The number of octaves above the baseFrequency that the
|
|
* envelope will scale to.
|
|
*/
|
|
get octaves(): number {
|
|
return this._octaves;
|
|
}
|
|
set octaves(octaves: number) {
|
|
this._octaves = octaves;
|
|
this._scale.max = this._baseFrequency * Math.pow(2, octaves);
|
|
}
|
|
|
|
/**
|
|
* The envelope's exponent value.
|
|
*/
|
|
get exponent(): number {
|
|
return this._exponent.value;
|
|
}
|
|
set exponent(exponent) {
|
|
this._exponent.value = exponent;
|
|
}
|
|
|
|
/**
|
|
* Clean up
|
|
*/
|
|
dispose(): this {
|
|
super.dispose();
|
|
this._exponent.dispose();
|
|
this._scale.dispose();
|
|
return this;
|
|
}
|
|
}
|