1 | import { Monophonic } from "./Monophonic.js";
|
2 | import { MonoSynth } from "./MonoSynth.js";
|
3 | import { Signal } from "../signal/Signal.js";
|
4 | import { readOnly } from "../core/util/Interface.js";
|
5 | import { LFO } from "../source/oscillator/LFO.js";
|
6 | import { Gain } from "../core/context/Gain.js";
|
7 | import { Multiply } from "../signal/Multiply.js";
|
8 | import { deepMerge, omitFromObject, optionsFromArguments, } from "../core/util/Defaults.js";
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | export class DuoSynth extends Monophonic {
|
18 | constructor() {
|
19 | const options = optionsFromArguments(DuoSynth.getDefaults(), arguments);
|
20 | super(options);
|
21 | this.name = "DuoSynth";
|
22 | this.voice0 = new MonoSynth(Object.assign(options.voice0, {
|
23 | context: this.context,
|
24 | onsilence: () => this.onsilence(this),
|
25 | }));
|
26 | this.voice1 = new MonoSynth(Object.assign(options.voice1, {
|
27 | context: this.context,
|
28 | }));
|
29 | this.harmonicity = new Multiply({
|
30 | context: this.context,
|
31 | units: "positive",
|
32 | value: options.harmonicity,
|
33 | });
|
34 | this._vibrato = new LFO({
|
35 | frequency: options.vibratoRate,
|
36 | context: this.context,
|
37 | min: -50,
|
38 | max: 50,
|
39 | });
|
40 |
|
41 | this._vibrato.start();
|
42 | this.vibratoRate = this._vibrato.frequency;
|
43 | this._vibratoGain = new Gain({
|
44 | context: this.context,
|
45 | units: "normalRange",
|
46 | gain: options.vibratoAmount,
|
47 | });
|
48 | this.vibratoAmount = this._vibratoGain.gain;
|
49 | this.frequency = new Signal({
|
50 | context: this.context,
|
51 | units: "frequency",
|
52 | value: 440,
|
53 | });
|
54 | this.detune = new Signal({
|
55 | context: this.context,
|
56 | units: "cents",
|
57 | value: options.detune,
|
58 | });
|
59 |
|
60 | this.frequency.connect(this.voice0.frequency);
|
61 | this.frequency.chain(this.harmonicity, this.voice1.frequency);
|
62 | this._vibrato.connect(this._vibratoGain);
|
63 | this._vibratoGain.fan(this.voice0.detune, this.voice1.detune);
|
64 | this.detune.fan(this.voice0.detune, this.voice1.detune);
|
65 | this.voice0.connect(this.output);
|
66 | this.voice1.connect(this.output);
|
67 | readOnly(this, [
|
68 | "voice0",
|
69 | "voice1",
|
70 | "frequency",
|
71 | "vibratoAmount",
|
72 | "vibratoRate",
|
73 | ]);
|
74 | }
|
75 | getLevelAtTime(time) {
|
76 | time = this.toSeconds(time);
|
77 | return (this.voice0.envelope.getValueAtTime(time) +
|
78 | this.voice1.envelope.getValueAtTime(time));
|
79 | }
|
80 | static getDefaults() {
|
81 | return deepMerge(Monophonic.getDefaults(), {
|
82 | vibratoAmount: 0.5,
|
83 | vibratoRate: 5,
|
84 | harmonicity: 1.5,
|
85 | voice0: deepMerge(omitFromObject(MonoSynth.getDefaults(), Object.keys(Monophonic.getDefaults())), {
|
86 | filterEnvelope: {
|
87 | attack: 0.01,
|
88 | decay: 0.0,
|
89 | sustain: 1,
|
90 | release: 0.5,
|
91 | },
|
92 | envelope: {
|
93 | attack: 0.01,
|
94 | decay: 0.0,
|
95 | sustain: 1,
|
96 | release: 0.5,
|
97 | },
|
98 | }),
|
99 | voice1: deepMerge(omitFromObject(MonoSynth.getDefaults(), Object.keys(Monophonic.getDefaults())), {
|
100 | filterEnvelope: {
|
101 | attack: 0.01,
|
102 | decay: 0.0,
|
103 | sustain: 1,
|
104 | release: 0.5,
|
105 | },
|
106 | envelope: {
|
107 | attack: 0.01,
|
108 | decay: 0.0,
|
109 | sustain: 1,
|
110 | release: 0.5,
|
111 | },
|
112 | }),
|
113 | });
|
114 | }
|
115 | |
116 |
|
117 |
|
118 | _triggerEnvelopeAttack(time, velocity) {
|
119 |
|
120 | this.voice0._triggerEnvelopeAttack(time, velocity);
|
121 |
|
122 | this.voice1._triggerEnvelopeAttack(time, velocity);
|
123 | }
|
124 | |
125 |
|
126 |
|
127 | _triggerEnvelopeRelease(time) {
|
128 |
|
129 | this.voice0._triggerEnvelopeRelease(time);
|
130 |
|
131 | this.voice1._triggerEnvelopeRelease(time);
|
132 | return this;
|
133 | }
|
134 | dispose() {
|
135 | super.dispose();
|
136 | this.voice0.dispose();
|
137 | this.voice1.dispose();
|
138 | this.frequency.dispose();
|
139 | this.detune.dispose();
|
140 | this._vibrato.dispose();
|
141 | this.vibratoRate.dispose();
|
142 | this._vibratoGain.dispose();
|
143 | this.harmonicity.dispose();
|
144 | return this;
|
145 | }
|
146 | }
|
147 |
|
\ | No newline at end of file |