forked from Feijk/js-ynth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.js
123 lines (107 loc) · 3.3 KB
/
main.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
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
"use strict";
class KeyboardInput {
constructor(ae) {
if(!ae){
throw new Error("No audio engine defined, KeyboardInput devices need an audio engine to work.")
}
this.OCTAVE_KEY_MAP = ["+", "-"];
this.NOTE_KEY_MAP = ["a", "w", "s", "e", "d", "f", "t", "g", "y", "h", "u", "j"]; // a = C, w = C# etc.
this.currentKeysDown = {};
this.octave = 3; // 0 represents first octave
this.audioEngine = ae;
document.addEventListener("keydown", evt => {
this.handleKeyPressDown(evt);
});
document.addEventListener("keyup", evt => {
this.handleKeyPressUp(evt);
});
}
handleKeyPressDown(evt) {
const key = evt.key;
if(!evt.repeat && this.currentKeysDown[key] === undefined && this.NOTE_KEY_MAP.indexOf(key) > -1){
this.audioEngine.updateOscillators(this.getKeyNumber(key), true, this.currentKeysDown);
}
if (this.OCTAVE_KEY_MAP.indexOf(key) > -1){
this.changeOctave(key);
}
}
handleKeyPressUp (evt) {
const key = evt.key;
if(this.NOTE_KEY_MAP.indexOf(key) > -1) {
this.audioEngine.updateOscillators(this.getKeyNumber(key), false, this.currentKeysDown);
}
}
getKeyNumber(key) {
return (this.NOTE_KEY_MAP.indexOf(key)+1) + this.octave * 12 + 23;
}
getRealOctave() {
return this.octave + 1;
}
changeOctave(key) {
if (key === "+") {
this.octave++;
} else {
this.octave--;
}
if (this.octave < 0) {
this.octave = 0;
}
if (this.octave > 7) {
this.octave = 7;
}
console.log("octave:", this.getRealOctave());
}
}
class AudioEngine {
constructor() {
this.oscillators = {};
this.gainNodes = {};
this.audioCtx = new window.AudioContext();
}
updateGain(currentKeysDown) {
const notesDownCount = Object.keys(currentKeysDown).length
if(notesDownCount > 0 && Object.keys(this.gainNodes).length > 0) {
const relativeGain = 0.3// (1 / notesDownCount);
for (const gn in this.gainNodes) {
this.gainNodes[gn].gain.setValueAtTime(relativeGain, this.audioCtx.currentTime);
};
}
}
updateOscillators(key, isNew, currentKeysDown) {
if (isNew) {
const freq = this.getFrequencyForKey(key);
currentKeysDown[key] = 1;
const osc = this.audioCtx.createOscillator();
const gainNode = this.audioCtx.createGain();
osc.type = "square";
osc.frequency.setValueAtTime(freq, this.audioCtx.currentTime);
osc.connect(gainNode);
gainNode.connect(this.audioCtx.destination);
this.oscillators[key] = osc;
this.gainNodes[key] = gainNode;
this.updateGain(currentKeysDown);
osc.start();
} else {
delete currentKeysDown[key];
if(this.oscillators[key]){
this.oscillators[key].stop();
delete this.oscillators[key];
delete this.gainNodes[key];
this.updateGain(currentKeysDown);
}
}
console.log("keys:", this.currentKeysDown);
console.log("oscs:", this.oscillators);
}
getFrequencyForKey(keyNumber) {
return 440 * Math.pow(2, ((keyNumber-69)/12));
}
};
class OSC {
constructor() {
}
}
const main = () => {
const ae = new AudioEngine();
const keyboard = new KeyboardInput(ae);
};