-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmidi-controller.js
More file actions
115 lines (98 loc) · 3.3 KB
/
midi-controller.js
File metadata and controls
115 lines (98 loc) · 3.3 KB
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
class MIDIController {
constructor() {
this.midiAccess = null;
this.inputs = new Map();
this.outputs = new Map();
this.lastMIDIMessage = null;
this.onMIDIMessage = null;
}
async init() {
try {
this.midiAccess = await navigator.requestMIDIAccess();
this.setupMIDI();
console.log('MIDI Controller initialized');
} catch (error) {
console.warn('MIDI not available:', error);
}
}
setupMIDI() {
if (!this.midiAccess) return;
// Setup inputs
for (const input of this.midiAccess.inputs.values()) {
this.inputs.set(input.id, input);
input.onmidimessage = this.handleMIDIMessage.bind(this);
console.log(`MIDI Input connected: ${input.name}`);
}
// Setup outputs
for (const output of this.midiAccess.outputs.values()) {
this.outputs.set(output.id, output);
console.log(`MIDI Output connected: ${output.name}`);
}
// Listen for device changes
this.midiAccess.onstatechange = this.handleStateChange.bind(this);
}
handleMIDIMessage(event) {
const [status, data1, data2] = event.data;
// Parse MIDI message
const channel = (status & 0x0F) + 1;
const messageType = status & 0xF0;
let type;
switch (messageType) {
case 0x80: // Note Off
type = 'noteoff';
break;
case 0x90: // Note On
type = data2 > 0 ? 'noteon' : 'noteoff';
break;
case 0xB0: // Control Change
type = 'cc';
break;
default:
return; // Ignore other message types
}
const message = {
type,
channel,
data1,
data2,
timestamp: event.timeStamp
};
this.lastMIDIMessage = message;
if (this.onMIDIMessage) {
this.onMIDIMessage(message);
}
console.log('MIDI:', message);
}
handleStateChange(event) {
const port = event.port;
if (port.type === 'input') {
if (port.state === 'connected') {
this.inputs.set(port.id, port);
port.onmidimessage = this.handleMIDIMessage.bind(this);
console.log(`MIDI Input connected: ${port.name}`);
} else {
this.inputs.delete(port.id);
console.log(`MIDI Input disconnected: ${port.name}`);
}
} else if (port.type === 'output') {
if (port.state === 'connected') {
this.outputs.set(port.id, port);
console.log(`MIDI Output connected: ${port.name}`);
} else {
this.outputs.delete(port.id);
console.log(`MIDI Output disconnected: ${port.name}`);
}
}
}
sendMIDI(data) {
for (const output of this.outputs.values()) {
output.send(data);
}
}
getInputs() {
return Array.from(this.inputs.values());
}
getOutputs() {
return Array.from(this.outputs.values());
}
}