-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmiditest.html
105 lines (89 loc) · 3.11 KB
/
miditest.html
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.4.9/Tone.js"></script>
<script>
console.clear();
class MIDIAccess {
constructor(args = {}) {
this.onDeviceInput = args.onDeviceInput || console.log;
}
start() {
return new Promise((resolve, reject) => {
this._requestAccess().then(access => {
this.initialize(access);
resolve();
}).catch(() => reject('Something went wrong.'));
});
}
initialize(access) {
const devices = access.inputs.values();
for (let device of devices) this.initializeDevice(device);
}
initializeDevice(device) {
device.onmidimessage = this.onMessage.bind(this);
}
onMessage(message) {
let [_, input, value] = message.data;
this.onDeviceInput({ input, value });
}
_requestAccess() {
return new Promise((resolve, reject) => {
if (navigator.requestMIDIAccess)
navigator.requestMIDIAccess()
.then(resolve)
.catch(reject);
else reject();
});
}
}
class Instrument {
constructor() {
this.synth = new Tone.PolySynth(Tone.FMSynth);
this.filter = new Tone.Filter();
this.volume = new Tone.Gain();
this.synth.connect(this.filter);
this.filter.connect(this.volume);
this.volume.toDestination();
this.filter.frequency.value = 200; // 200 - 15000
this.volume.gain.value = 0.8; // 0-0.8
}
toggleSound(value) {
let method = value > 0 ? 'triggerAttack' : 'releaseAll';
this.synth[method](['C4', 'E4', 'G4']);
}
handleVolume(value) { // 0-127
let val = value / 127 * 0.8;
this.volume.gain.value = val;
}
handleFilter(value) { // 0-127
let val = value / 127 * 14800 + 200;
this.filter.frequency.value = val;
}
}
// UPDATE: there is a problem in chrome with starting audio context
// before a user gesture. This fixes it.
var started = false;
document.documentElement.addEventListener('mousedown', () => {
if (started) return;
started = true;
const inst = new Instrument();
const midi = new MIDIAccess({ onDeviceInput });
midi.start().then(() => {
console.log('STARTED!');
}).catch(console.error);
function onDeviceInput({ input, value }) {
if (input === 60) inst.toggleSound(value);
else if (input === 62) inst.handleVolume(value);
else if (input === 64) inst.handleFilter(value);
else console.log('onDeviceInput!', input, value);
}
});
</script>
</body>
</html>