Tone.js/Tone/signal/Signal.ts

199 lines
6.3 KiB
TypeScript
Raw Normal View History

2019-05-23 18:00:49 +00:00
import { AbstractParam } from "../core/context/AbstractParam";
import { Param } from "../core/context/Param";
import { InputNode, OutputNode, ToneAudioNode, ToneAudioNodeOptions } from "../core/context/ToneAudioNode";
import { connect } from "../core/context/ToneAudioNode";
2019-05-23 18:00:49 +00:00
import { optionsFromArguments } from "../core/util/Defaults";
2019-04-12 14:37:47 +00:00
2019-07-15 19:37:25 +00:00
export interface SignalOptions<Type> extends ToneAudioNodeOptions {
value: Type;
units: UnitName;
2019-04-12 14:37:47 +00:00
convert: boolean;
}
/**
* A signal is an audio-rate value. Tone.Signal is a core component of the library.
* Unlike a number, Signals can be scheduled with sample-level accuracy. Tone.Signal
* has all of the methods available to native Web Audio
* [AudioParam](http://webaudio.github.io/web-audio-api/#the-audioparam-interface)
* as well as additional conveniences. Read more about working with signals
* [here](https://github.com/Tonejs/Tone.js/wiki/Signals).
* @param value Initial value of the signal
* @param units unit The units the signal is in.
* @example
* const signal = new Tone.Signal(10);
*/
2019-07-15 19:37:25 +00:00
export class Signal<Type extends Unit = number> extends ToneAudioNode<SignalOptions<any>>
2019-04-12 14:37:47 +00:00
implements AbstractParam<Type> {
name = "Signal";
/**
* Indicates if the value should be overridden on connection.
*/
readonly override: boolean = true;
2019-04-12 14:37:47 +00:00
/**
* The constant source node which generates the signal
*/
private _constantSource: ConstantSourceNode = this.context.createConstantSource();
readonly output: OutputNode = this._constantSource;
protected _param: Param<Type>;
readonly input: InputNode;
2019-04-12 14:37:47 +00:00
protected _internalChannels = [this._constantSource];
2019-07-15 19:37:25 +00:00
constructor(value?: Type, units?: UnitName);
constructor(options?: Partial<SignalOptions<Type>>);
2019-04-12 14:37:47 +00:00
constructor() {
super(optionsFromArguments(Signal.getDefaults(), arguments, ["value", "units"]));
2019-07-15 19:37:25 +00:00
const options = optionsFromArguments(Signal.getDefaults(), arguments, ["value", "units"]) as SignalOptions<Type>;
2019-04-12 14:37:47 +00:00
this._constantSource.start(0);
this.input = this._param = new Param({
context: this.context,
convert: options.convert,
param: this._constantSource.offset,
units: options.units,
value: options.value,
});
}
2019-07-15 19:37:25 +00:00
static getDefaults(): SignalOptions<any> {
return Object.assign(ToneAudioNode.getDefaults(), {
channelCount: 1,
channelCountMode: "explicit",
channelInterpretation: "discrete",
convert: true,
numberOfInputs: 1,
numberOfOutputs: 1,
units: "number" as UnitName,
value: 0,
}) as SignalOptions<any>;
}
2019-04-12 14:37:47 +00:00
connect(destination: InputNode, outputNum = 0, inputNum = 0): this {
2019-07-18 15:23:45 +00:00
connectSignal(this, destination, outputNum, inputNum);
2019-04-12 14:37:47 +00:00
return this;
}
///////////////////////////////////////////////////////////////////////////
// ABSTRACT PARAM INTERFACE
// just a proxy for the ConstantSourceNode's offset AudioParam
2019-05-23 18:00:49 +00:00
// all docs are generated from AbstractParam.ts
2019-04-12 14:37:47 +00:00
///////////////////////////////////////////////////////////////////////////
2019-07-15 19:37:25 +00:00
setValueAtTime(value: Type, time: Time): this {
2019-04-12 14:37:47 +00:00
this._param.setValueAtTime(value, time);
return this;
}
2019-07-15 19:37:25 +00:00
getValueAtTime(time: Time): Type {
2019-04-12 14:37:47 +00:00
return this._param.getValueAtTime(time);
}
setRampPoint(time: Time): this {
this._param.setRampPoint(time);
return this;
}
2019-07-15 19:37:25 +00:00
linearRampToValueAtTime(value: Type, time: Time): this {
2019-04-12 14:37:47 +00:00
this._param.linearRampToValueAtTime(value, time);
return this;
}
2019-07-15 19:37:25 +00:00
exponentialRampToValueAtTime(value: Type, time: Time): this {
2019-04-12 14:37:47 +00:00
this._param.exponentialRampToValueAtTime(value, time);
return this;
}
2019-07-15 19:37:25 +00:00
exponentialRampTo(value: Type, rampTime: Time, startTime?: Time): this {
2019-04-12 14:37:47 +00:00
this._param.exponentialRampTo(value, rampTime, startTime);
return this;
}
2019-07-15 19:37:25 +00:00
linearRampTo(value: Type, rampTime: Time, startTime?: Time): this {
2019-04-12 14:37:47 +00:00
this._param.linearRampTo(value, rampTime, startTime);
return this;
}
2019-07-15 19:37:25 +00:00
targetRampTo(value: Type, rampTime: Time, startTime?: Time): this {
2019-04-12 14:37:47 +00:00
this._param.targetRampTo(value, rampTime, startTime);
return this;
}
2019-07-15 19:37:25 +00:00
exponentialApproachValueAtTime(value: Type, time: Time, rampTime: Time): this {
2019-04-12 14:37:47 +00:00
this._param.exponentialApproachValueAtTime(value, time, rampTime);
return this;
}
2019-07-15 19:37:25 +00:00
setTargetAtTime(value: Type, startTime: Time, timeConstant: number): this {
2019-04-12 14:37:47 +00:00
this._param.setTargetAtTime(value, startTime, timeConstant);
return this;
}
2019-07-15 19:37:25 +00:00
setValueCurveAtTime(values: Type[], startTime: Time, duration: Time, scaling?: number): this {
2019-04-12 14:37:47 +00:00
this._param.setValueCurveAtTime(values, startTime, duration, scaling);
return this;
}
cancelScheduledValues(time: Time): this {
this._param.cancelScheduledValues(time);
return this;
}
cancelAndHoldAtTime(time: Time): this {
this._param.cancelAndHoldAtTime(time);
return this;
}
2019-07-15 19:37:25 +00:00
rampTo(value: Type, rampTime: Time, startTime?: Time): this {
2019-04-12 14:37:47 +00:00
this._param.rampTo(value, rampTime, startTime);
return this;
}
2019-07-15 19:37:25 +00:00
get value(): Type {
2019-04-12 14:37:47 +00:00
return this._param.value;
}
2019-07-15 19:37:25 +00:00
set value(value: Type) {
2019-04-12 14:37:47 +00:00
this._param.value = value;
}
get convert(): boolean {
return this._param.convert;
}
set convert(convert: boolean) {
this._param.convert = convert;
}
2019-07-15 19:37:25 +00:00
get units(): UnitName {
2019-04-12 14:37:47 +00:00
return this._param.units;
}
get overridden(): boolean {
return this._param.overridden;
}
set overridden(overridden: boolean) {
this._param.overridden = overridden;
}
2019-07-15 19:37:25 +00:00
get maxValue(): number {
2019-04-12 14:37:47 +00:00
return this._param.maxValue;
}
2019-07-15 19:37:25 +00:00
get minValue(): number {
2019-04-12 14:37:47 +00:00
return this._param.minValue;
}
}
/**
* When connecting from a signal, it's necessary to zero out the node destination
* node if that node is also a signal. If the destination is not 0, then the values
* will be summed. This method insures that the output of the destination signal will
* be the same as the source signal, making the destination signal a pass through node.
* @param signal The output signal to connect from
* @param destination the destination to connect to
* @param outputNum the optional output number
* @param inputNum the input number
*/
export function connectSignal(signal: OutputNode, destination: InputNode, outputNum?: number, inputNum?: number): void {
if (destination instanceof Param || destination instanceof AudioParam ||
(destination instanceof Signal && destination.override)) {
// cancel changes
destination.cancelScheduledValues(0);
// reset the value
destination.setValueAtTime(0, 0);
// mark the value as overridden
if (destination instanceof Signal) {
destination.overridden = true;
}
}
connect(signal, destination, outputNum, inputNum);
}