-
Notifications
You must be signed in to change notification settings - Fork 17
/
Ringmodulator.ts
136 lines (114 loc) · 3.41 KB
/
Ringmodulator.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
import { Effector } from './Effector';
export type RingmodulatorParams = {
state?: boolean,
depth?: number,
rate?: number
};
/**
* Effector's subclass for Ring Modulator.
* @constructor
* @extends {Effector}
*/
export class Ringmodulator extends Effector {
private amplitude: GainNode;
/**
* @param {AudioContext} context This argument is in order to use Web Audio API.
*/
constructor(context: AudioContext) {
super(context, 0);
this.amplitude = context.createGain();
// Initialize parameter
this.amplitude.gain.value = 0; // 0 +- depth
this.depth.gain.value = 1;
this.rate.value = 0;
// `Ringmodulator` is not connected by default
this.deactivate();
// LFO
// OscillatorNode (LFO) -> GainNode (Depth) -> AudioParam (gain)
this.lfo.connect(this.depth);
this.depth.connect(this.amplitude.gain);
}
/** @override */
public override stop(stopTime?: number, releaseTime?: number): void {
super.stop(stopTime, releaseTime);
if (this.isActive) {
// Connect `AudioNode`s again
this.lfo.connect(this.depth);
this.depth.connect(this.amplitude.gain);
}
}
/** @override */
public override connect(): GainNode {
// Clear connection
this.input.disconnect(0);
this.amplitude.disconnect(0);
if (this.isActive) {
// Effect ON
// GainNode (Input) -> GainNode (Ring Modulator) -> GainNode (Output)
this.input.connect(this.amplitude);
this.amplitude.connect(this.output);
} else {
// Effect OFF
// GainNode (Input) -> GainNode (Output)
this.input.connect(this.output);
}
return this.output;
}
/**
* This method gets or sets parameters for ring modulator effector.
* This method is overloaded for type interface and type check.
* @param {keyof RingmodulatorParams|RingmodulatorParams} params This argument is string if getter. Otherwise, setter.
* @return {RingmodulatorParams[keyof RingmodulatorParams]|Autopanner} Return value is parameter for ring modulator effector if getter.
* Otherwise, return value is for method chain.
*/
public param(params: 'depth'): number;
public param(params: 'rate'): number;
public param(params: RingmodulatorParams): Ringmodulator;
public param(params: keyof RingmodulatorParams | RingmodulatorParams): RingmodulatorParams[keyof RingmodulatorParams] | Ringmodulator {
if (typeof params === 'string') {
switch (params) {
case 'depth':
return this.depth.gain.value;
case 'rate':
return this.rate.value;
default:
return this;
}
}
for (const [key, value] of Object.entries(params)) {
switch (key) {
case 'depth':
if (typeof value === 'number') {
this.depth.gain.value = value;
}
break;
case 'rate':
if (typeof value === 'number') {
this.rate.value = value;
}
break;
default:
break;
}
}
return this;
}
/** @override */
public override params(): RingmodulatorParams {
return {
state: this.isActive,
depth: this.depth.gain.value,
rate : this.rate.value
};
}
/** @override */
public override activate(): Ringmodulator {
super.activate();
return this;
}
/** @override */
public override deactivate(): Ringmodulator {
super.deactivate();
return this;
}
}