piano/js/components/Key/Board.js

163 lines
4.5 KiB
JavaScript

/*globals React, App */
(function () {
'use strict';
/**
* Display keyboard
*/
App.components.create('Key', {
displayName: 'Board',
mixins: [React.addons.PureRenderMixin],
clicked: false,
statics: {
offset: 27 + App.MIDI.keyOffset,
keysToNotes: [
65, 50, 90, 51, 69, 82, 53, 84, 54, 89, 55, 85, 73,
57, 79, 48, 80, 87, 83, 88, 68, 67, 70, 86, 66, 72,
78, 74, 188, 190, 76, 191, 77, 223, 192, 16
]
},
/**
* Set given note on given channel
*
* @param {note: number} Note number
* @param {channel: number} Channel ID
* @param {velocity: number} Note velocity
*/
on: function (note, channel, velocity) {
var key = this.refs['key-' + note];
if (key) {
key.on(channel, velocity);
}
},
/**
* Check whether given note plays on given channel
*
* @param {note: number} Note number
* @param {channel: number} Channel ID
*/
isOn: function (note, channel) {
var key = this.refs['key-' + note];
return (key.state.channels.indexOf(channel) > -1);
},
/**
* Set given note off given channel
*
* @param {note: number} Note number
* @param {channel: number} Channel ID
*/
off: function (note, channel) {
var key = this.refs['key-' + note];
if (key) {
key.off(channel);
}
},
/**
* Set all notes off
*/
allOff: function () {
var i, keys = this.refs;
for (i in keys) {
if (keys.hasOwnProperty(i) && i.substr(0, 4) === 'key-') {
keys[i].off();
}
}
},
/**
* Events
*/
componentDidMount: function () {
window.addEventListener('keydown', this.keyDown);
window.addEventListener('keyup', this.keyUp);
window.addEventListener('mouseup', this.release);
},
componentWillUnmount: function () {
window.removeEventListener('keydown', this.keyDown);
window.removeEventListener('keyup', this.keyUp);
window.removeEventListener('mouseup', this.release);
},
/* mouse click */
click: function (e) {
if (e.button !== 0) {
return;
}
this.clicked = true;
},
/* mouse release */
release: function () {
this.clicked = false;
},
/* play keys with keyboard (the real one) */
keyDown: function (e) {
var code = e.keyCode, index,
Keyboard = App.components.Key.Board;
// play note
if ((index = Keyboard.keysToNotes.indexOf(code)) > -1) {
index += Keyboard.offset;
if (!this.isOn(index, -1)) {
this.on(index, -1, 127);
}
e.preventDefault();
}
},
/* release keys */
keyUp: function (e) {
var index, Keyboard = App.components.Key.Board;
if ((index = Keyboard.keysToNotes.indexOf(e.keyCode)) > -1) {
this.off(index + Keyboard.offset, -1);
e.preventDefault();
}
},
/**
* Whether keys should be played on mouse over
*/
canPlay: function () {
return this.clicked;
},
/**
* Render keyboard
*/
render: function () {
var i, offset = App.MIDI.keyOffset,
length = 88 + offset, keys = [];
for (i = offset; i < length; i += 1) {
keys.push(App.components.Key.Key({
key: i,
ref: 'key-' + i,
note: i,
canPlay: this.canPlay
}));
}
return React.DOM.p({
className: 'keyboard',
onMouseDown: this.click
}, keys);
}
});
}());