-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPolySynth.js
77 lines (75 loc) · 2.49 KB
/
PolySynth.js
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
class Adsr {
constructor(envelope_object) {
for (let i in envelope_object) {
this[i] = envelope_object[i];
}
this.ramp = (this.linear)
? "linearRampToValueAtTime"
: "exponentialRampToValueAtTime";
}
async attack(gainNode,context) {
gainNode.gain.setValueAtTime(0.0001, context.currentTime);
gainNode.gain[this.ramp](this.attackLevel,
context.currentTime + this.attackTime);
gainNode.gain.setValueAtTime(this.attackLevel, context.currentTime + this.attackTime);
gainNode.gain[this.ramp](this.decayLevel,
context.currentTime + this.decayTime);
}
async release(gainNode,context) {
gainNode.gain.setValueAtTime(gainNode.gain.value, context.currentTime);
gainNode.gain[this.ramp](0.0001, context.currentTime + this.releaseTime);
gainNode.gain.setValueAtTime(0, context.currentTime + this.releaseTime);
}
}
class polyphonicSynth {
constructor(ctx,waveForm,output,env) {
this.voices = [];
this.out = output;
this.id = 0;
this.envelope = new Adsr(env);
this.context = ctx;
this.setWave(waveForm);
}
createWave(harmonics) {
let phase = 0;
let real = new Float32Array(harmonics.length);
let imag = new Float32Array(harmonics.length);
for (let i in harmonics) {
real[i] = harmonics[i]*Math.cos(phase);
imag[i] = -harmonics[i]*Math.sin(phase);
}
return this.context.createPeriodicWave(real,imag);
}
setWave(harmonics_array) { this.wave = this.createWave(harmonics_array); }
midiToFreq(midi_note) { return Math.pow(2,(midi_note-69)/12)*440 }
getId() {
this.id++;
return this.id;
}
noteOn(midi_note) {
let voice = this.voices.find(e => e.envelopeGain.gain.value == 0);
if (!voice) {
let voice_id = this.getId();
let envelopeGain = this.context.createGain();
let osc = this.context.createOscillator();
envelopeGain.connect(this.out);
this.voices.push({osc,id:voice_id,active:true,envelopeGain:envelopeGain});
voice = this.voices.find(e => (e.id == voice_id));
envelopeGain.connect(this.out);
osc.connect(envelopeGain);
osc.start();
}
voice.osc.setPeriodicWave(this.wave);
voice.osc.frequency.setValueAtTime(
this.midiToFreq(midi_note),
this.context.currentTime
);
this.envelope.attack(voice.envelopeGain,this.context);
return voice.id;
}
noteOff(voice) {
voice = this.voices.find(e => (e.id == voice));
this.envelope.release(voice.envelopeGain,this.context);
}
}
export { polyphonicSynth };