-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtakenote.js
executable file
·128 lines (106 loc) · 3.22 KB
/
takenote.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
124
125
126
127
128
const EventEmitter = require('events');
const message = require('./lib/message');
const theory = require('./lib/theory');
const rules = require('./lib/rules');
class TakeNote extends EventEmitter{
constructor({
midiInput,
lowNote = 0,
highNote = 120,
ledLowNote,
ledHighNote,
numLeds = 30,
isInverted = false
}){
super();
this.config = {
lowNote,
highNote,
ledLowNote : ledLowNote || lowNote,
ledHighNote : ledHighNote || highNote,
numLeds,
isInverted
};
this._keyboardMap = Array(highNote-lowNote).fill({velocity:0,chords:[]});
this._ledMap = Array(numLeds).fill({velocity:0,key:0});
this._sustain = true;
this.activeChords = {};
this.expectedNext = [];
this.patternTests = {};
this.addRule = this.addRule.bind(this);
let startTime = process.hrtime();
midiInput.on('message',(delta,message)=>{
let eventTime = process.hrtime(startTime);
let { ledLowNote, ledHighNote, numLeds, isInverted } = this.config;
// Convert the message to an event object
let event = message.toEvent(message);
// In the event of a key
if(event.id === 'key'){
let normalisedTime = Math.round((eventTime[0]*1e9 + eventTime[1])*1e-6);
// Generate an led index for the key
let ledIndex = message.key2Led(event.key, numLeds, ledLowNote, ledHighNote, isInverted);
if(event.velocity > 0){
rules.checkRules.call(
this,
event.key,
normalisedTime,
this.patternTests);
}
// Update the keymap
this._keyboardMap[event.key].v = event.velocity;
// Emit the keypress event
let emitEvent = (event.velocity > 0) ? 'keyPress' : 'keyRelease';
this.emit(emitEvent,{
key:event.key,
velocity:event.velocity,
time:normalisedTime
});
//If the event is a key press, or this keypress is affecting the same light it initiated
if(event.velocity > 0 || event.key === this._ledMap[ledIndex].key) {
this._ledMap[ledIndex] = {velocity:event.velocity,key:event.key};
}
} else if (event.id === 'sustain'){
this._sustain = event.active;
let emitEvent = (event.active) ? 'sustainOn' : 'sustainOff';
this.emit(emitEvent,{active:event.active});
}
});
//Sets the LEDs to die, even if a key off hasn't been registered (desperately targetting 60fps)
setInterval(()=>{
this._ledMap.forEach((led,index,map)=>{
if(map[index].velocity > 0) map[index].velocity -= 1;
});
},16);
}
chordCalculator(){
}
colouriseKey(key,velocity){
if(velocity > 0){
let r,g,b,v;
v = velocity*2; //velocity is half of brightness
let n = message.normalise(key);
r = message.calculateBrightness(n,0)*v;
g = message.calculateBrightness(n,(2/3))*v;
b = message.calculateBrightness(n,(1/3))*v;
return message.toBinaryRGB(r,g,b);
} else {
return 0;
}
}
addRule(ruleName, ruleObject){
this.patternTests[ruleName] = ruleObject;
}
static toPitch(key){
return theory.toPitch(key);
}
get map(){
return this._keyboardMap;
}
get chromaMap(){
return this._ledMap.map((x)=>this.colouriseKey(x.key,x.velocity));
}
get sustain(){
return this._sustain;
}
}
module.exports = TakeNote;