/
PWMOscillator.ts
190 lines (165 loc) · 4.55 KB
/
PWMOscillator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import { Degrees, Frequency, Seconds, Time } from "../../core/type/Units";
import { optionsFromArguments } from "../../core/util/Defaults";
import { readOnly } from "../../core/util/Interface";
import { Multiply } from "../../signal/Multiply";
import { Signal } from "../../signal/Signal";
import { Source } from "../Source";
import { Oscillator } from "./Oscillator";
import { generateWaveform, PWMOscillatorOptions, ToneOscillatorInterface } from "./OscillatorInterface";
import { PulseOscillator } from "./PulseOscillator";
export { PWMOscillatorOptions } from "./OscillatorInterface";
/**
* PWMOscillator modulates the width of a Tone.PulseOscillator
* at the modulationFrequency. This has the effect of continuously
* changing the timbre of the oscillator by altering the harmonics
* generated.
* @example
* return Tone.Offline(() => {
* const pwm = new Tone.PWMOscillator(60, 0.3).toDestination().start();
* }, 0.1, 1);
* @category Source
*/
export class PWMOscillator extends Source<PWMOscillatorOptions> implements ToneOscillatorInterface {
readonly name: string = "PWMOscillator";
readonly sourceType = "pwm";
/**
* the pulse oscillator
*/
private _pulse: PulseOscillator;
/**
* the modulator
*/
private _modulator: Oscillator;
/**
* Scale the oscillator so it doesn't go silent
* at the extreme values.
*/
private _scale: Multiply = new Multiply({
context: this.context,
value: 2,
});
/**
* The frequency control.
*/
readonly frequency: Signal<"frequency">;
/**
* The detune of the oscillator.
*/
readonly detune: Signal<"cents">;
/**
* The width modulation rate of the oscillator.
* @example
* return Tone.Offline(() => {
* const osc = new Tone.PWMOscillator(20, 2).toDestination().start();
* }, 0.1, 1);
*/
readonly modulationFrequency: Signal<"frequency">;
/**
* @param {Frequency} frequency The starting frequency of the oscillator.
* @param {Frequency} modulationFrequency The modulation frequency of the width of the pulse.
*/
constructor(frequency?: Frequency, modulationFrequency?: Frequency);
constructor(options?: Partial<PWMOscillatorOptions>);
constructor() {
super(optionsFromArguments(PWMOscillator.getDefaults(), arguments, ["frequency", "modulationFrequency"]));
const options = optionsFromArguments(PWMOscillator.getDefaults(), arguments, ["frequency", "modulationFrequency"]);
this._pulse = new PulseOscillator({
context: this.context,
frequency: options.modulationFrequency,
});
// change the pulse oscillator type
this._pulse.carrierType = "sine";
this.modulationFrequency = this._pulse.frequency;
this._modulator = new Oscillator({
context: this.context,
detune: options.detune,
frequency: options.frequency,
onstop: () => this.onstop(this),
phase: options.phase,
});
this.frequency = this._modulator.frequency;
this.detune = this._modulator.detune;
// connections
this._modulator.chain(this._scale, this._pulse.width);
this._pulse.connect(this.output);
readOnly(this, ["modulationFrequency", "frequency", "detune"]);
}
static getDefaults(): PWMOscillatorOptions {
return Object.assign(Source.getDefaults(), {
detune: 0,
frequency: 440,
modulationFrequency: 0.4,
phase: 0,
type: "pwm" as "pwm",
});
}
/**
* start the oscillator
*/
protected _start(time: Time): void {
time = this.toSeconds(time);
this._modulator.start(time);
this._pulse.start(time);
}
/**
* stop the oscillator
*/
protected _stop(time: Time): void {
time = this.toSeconds(time);
this._modulator.stop(time);
this._pulse.stop(time);
}
/**
* restart the oscillator
*/
protected _restart(time: Seconds): void {
this._modulator.restart(time);
this._pulse.restart(time);
}
/**
* The type of the oscillator. Always returns "pwm".
*/
get type(): "pwm" {
return "pwm";
}
/**
* The baseType of the oscillator. Always returns "pwm".
*/
get baseType(): "pwm" {
return "pwm";
}
/**
* The partials of the waveform. Cannot set partials for this waveform type
*/
get partials(): number[] {
return [];
}
/**
* No partials for this waveform type.
*/
get partialCount(): number {
return 0;
}
/**
* The phase of the oscillator in degrees.
*/
get phase(): Degrees {
return this._modulator.phase;
}
set phase(phase: Degrees) {
this._modulator.phase = phase;
}
async asArray(length = 1024): Promise<Float32Array> {
return generateWaveform(this, length);
}
/**
* Clean up.
*/
dispose(): this {
super.dispose();
this._pulse.dispose();
this._scale.dispose();
this._modulator.dispose();
return this;
}
}