2019-07-11 13:57:06 +00:00
|
|
|
import { connect } from "../../core/Connect";
|
|
|
|
import { Param } from "../../core/context/Param";
|
2019-07-30 19:35:27 +00:00
|
|
|
import { Cents, Frequency, Seconds, Time } from "../../core/type/Units";
|
2019-07-11 13:57:06 +00:00
|
|
|
import { optionsFromArguments } from "../../core/util/Defaults";
|
2019-06-18 01:52:43 +00:00
|
|
|
import { OneShotSource, OneShotSourceOptions } from "../OneShotSource";
|
2019-06-17 18:03:02 +00:00
|
|
|
|
2019-09-04 22:34:42 +00:00
|
|
|
export interface ToneOscillatorNodeOptions extends OneShotSourceOptions {
|
2019-06-17 18:03:02 +00:00
|
|
|
frequency: Frequency;
|
|
|
|
detune: Cents;
|
|
|
|
type: OscillatorType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrapper around the native fire-and-forget OscillatorNode.
|
|
|
|
* Adds the ability to reschedule the stop method.
|
2019-08-27 15:47:52 +00:00
|
|
|
* ***[[Oscillator]] is better for most use-cases***
|
2019-09-16 14:15:23 +00:00
|
|
|
* @category Source
|
2019-06-17 18:03:02 +00:00
|
|
|
*/
|
|
|
|
export class ToneOscillatorNode extends OneShotSource<ToneOscillatorNodeOptions> {
|
|
|
|
|
2019-09-04 23:18:44 +00:00
|
|
|
readonly name: string = "ToneOscillatorNode";
|
2019-06-17 18:03:02 +00:00
|
|
|
|
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* The oscillator
|
2019-06-17 18:03:02 +00:00
|
|
|
*/
|
|
|
|
private _oscillator = this.context.createOscillator();
|
2019-08-03 16:00:14 +00:00
|
|
|
protected _internalChannels = [this._oscillator];
|
2019-06-17 18:03:02 +00:00
|
|
|
|
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* The frequency of the oscillator
|
2019-06-17 18:03:02 +00:00
|
|
|
*/
|
2019-10-28 15:37:53 +00:00
|
|
|
readonly frequency: Param<"frequency">;
|
2019-06-17 18:03:02 +00:00
|
|
|
|
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* The detune of the oscillator
|
2019-06-17 18:03:02 +00:00
|
|
|
*/
|
2019-10-28 15:37:53 +00:00
|
|
|
readonly detune: Param<"cents">;
|
2019-06-17 18:03:02 +00:00
|
|
|
|
2019-08-27 15:47:52 +00:00
|
|
|
/**
|
2019-08-30 16:06:38 +00:00
|
|
|
* @param frequency The frequency value
|
|
|
|
* @param type The basic oscillator type
|
2019-08-27 15:47:52 +00:00
|
|
|
*/
|
2019-06-17 18:03:02 +00:00
|
|
|
constructor(
|
|
|
|
frequency: Frequency,
|
|
|
|
type: OscillatorType,
|
|
|
|
);
|
2019-08-30 16:34:04 +00:00
|
|
|
constructor(options?: Partial<ToneOscillatorNodeOptions>);
|
2019-06-17 18:03:02 +00:00
|
|
|
constructor() {
|
|
|
|
|
|
|
|
super(optionsFromArguments(ToneOscillatorNode.getDefaults(), arguments, ["frequency", "type"]));
|
|
|
|
const options = optionsFromArguments(ToneOscillatorNode.getDefaults(), arguments, ["frequency", "type"]);
|
|
|
|
|
|
|
|
connect(this._oscillator, this._gainNode);
|
|
|
|
|
|
|
|
this.type = options.type;
|
|
|
|
|
|
|
|
this.frequency = new Param({
|
|
|
|
context: this.context,
|
2019-09-16 03:32:40 +00:00
|
|
|
param: this._oscillator.frequency,
|
|
|
|
units: "frequency",
|
|
|
|
value: options.frequency,
|
2019-06-17 18:03:02 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
this.detune = new Param({
|
|
|
|
context: this.context,
|
2019-09-16 03:32:40 +00:00
|
|
|
param: this._oscillator.detune,
|
|
|
|
units: "cents",
|
|
|
|
value: options.detune,
|
2019-06-17 18:03:02 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static getDefaults(): ToneOscillatorNodeOptions {
|
|
|
|
return Object.assign(OneShotSource.getDefaults(), {
|
|
|
|
detune: 0,
|
|
|
|
frequency: 440,
|
|
|
|
type: "sine" as OscillatorType,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start the oscillator node at the given time
|
|
|
|
* @param time When to start the oscillator
|
|
|
|
*/
|
|
|
|
start(time?: Time): this {
|
|
|
|
const computedTime = this.toSeconds(time);
|
2019-08-14 14:02:22 +00:00
|
|
|
this.log("start", computedTime);
|
2019-06-17 18:03:02 +00:00
|
|
|
this._startGain(computedTime);
|
|
|
|
this._oscillator.start(computedTime);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-07-23 15:46:08 +00:00
|
|
|
protected _stopSource(time?: Seconds): void {
|
2019-06-17 18:03:02 +00:00
|
|
|
this._oscillator.stop(time);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets an arbitrary custom periodic waveform given a PeriodicWave.
|
|
|
|
* @param periodicWave PeriodicWave should be created with context.createPeriodicWave
|
|
|
|
*/
|
|
|
|
setPeriodicWave(periodicWave: PeriodicWave): this {
|
|
|
|
this._oscillator.setPeriodicWave(periodicWave);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The oscillator type. Either 'sine', 'sawtooth', 'square', or 'triangle'
|
|
|
|
*/
|
|
|
|
get type(): OscillatorType {
|
|
|
|
return this._oscillator.type;
|
|
|
|
}
|
|
|
|
set type(type: OscillatorType) {
|
|
|
|
this._oscillator.type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* Clean up.
|
2019-06-17 18:03:02 +00:00
|
|
|
*/
|
|
|
|
dispose(): this {
|
|
|
|
super.dispose();
|
2019-08-08 20:32:22 +00:00
|
|
|
if (this.state === "started") {
|
|
|
|
this.stop();
|
|
|
|
}
|
2019-07-24 23:30:53 +00:00
|
|
|
this._oscillator.disconnect();
|
2019-06-17 18:03:02 +00:00
|
|
|
this.frequency.dispose();
|
|
|
|
this.detune.dispose();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|