167 lines
4.7 KiB
JavaScript
167 lines
4.7 KiB
JavaScript
/*jshint es5: true, bitwise: true */
|
|
/*globals App */
|
|
|
|
/**
|
|
* io.js
|
|
*
|
|
* Handle communication with MIDI inputs and outputs
|
|
* Request navigator access to MIDI devices
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
/**
|
|
* Wrap around low-level MIDI output
|
|
*
|
|
* @param {native: MIDIOutput} Native MIDIOutput to wrap around
|
|
*/
|
|
function Output(native) {
|
|
this.native = native || {
|
|
send: function () {}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* List of MIDI channel events
|
|
*/
|
|
Output.messages = {
|
|
noteOff: 0x80,
|
|
noteOn: 0x90,
|
|
noteAftertouch: 0xA0,
|
|
controller: 0xB0,
|
|
programChange: 0xC0,
|
|
channelAftertouch: 0xD0,
|
|
pitchBend: 0xE0
|
|
};
|
|
|
|
/**
|
|
* List of controller types
|
|
* (not complete)
|
|
*/
|
|
Output.controllers = {
|
|
modulationWheel: 1,
|
|
volume: 7,
|
|
pan: 10,
|
|
expression: 11,
|
|
sustainPedal: 64
|
|
};
|
|
|
|
Output.prototype.programChange = function (channel, program, delay) {
|
|
this.native.send([
|
|
Output.messages.programChange + channel,
|
|
program
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
Output.prototype.noteOn = function (channel, note, velocity, delay) {
|
|
this.native.send([
|
|
Output.messages.noteOn + channel,
|
|
note,
|
|
velocity
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
Output.prototype.noteOff = function (channel, note, delay) {
|
|
this.native.send([
|
|
Output.messages.noteOff + channel,
|
|
note,
|
|
0
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
Output.prototype.noteAftertouch = function (channel, note, amount, delay) {
|
|
this.native.send([
|
|
Output.messages.noteAftertouch + channel,
|
|
note,
|
|
amount
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
Output.prototype.controller = function (channel, type, value, delay) {
|
|
this.native.send([
|
|
Output.messages.controller + channel,
|
|
type,
|
|
value
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
Output.prototype.programChange = function (channel, program, delay) {
|
|
this.native.send([
|
|
Output.messages.programChange + channel,
|
|
program
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
Output.prototype.channelAftertouch = function (channel, amount, delay) {
|
|
this.native.send([
|
|
Output.messages.channelAftertouch + channel,
|
|
amount
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
Output.prototype.pitchBend = function (channel, value, delay) {
|
|
var lsb, msb;
|
|
|
|
value += 8192;
|
|
lsb = value & 127;
|
|
msb = value >> 7;
|
|
|
|
this.native.send([
|
|
Output.messages.pitchBend + channel,
|
|
lsb,
|
|
msb
|
|
], (delay || 0) * 1000);
|
|
};
|
|
|
|
/**
|
|
* Request MIDI access, select first available output
|
|
*
|
|
* @return Promise
|
|
*/
|
|
function connect() {
|
|
var promise;
|
|
|
|
promise = new window.Promise(function (resolve, reject) {
|
|
var ignoreAlert = "Si vous continuez, " +
|
|
"<em>aucun son ne sera émis ou reçu,</em> mais vous " +
|
|
"pourrez utiliser les autres fonctionnalités " +
|
|
"du logiciel.";
|
|
|
|
// by default, we use a no-op output
|
|
App.MIDI.output = new Output();
|
|
|
|
navigator.requestMIDIAccess().then(function (access) {
|
|
var outputs = access.outputs(),
|
|
output;
|
|
|
|
if (outputs && outputs.length) {
|
|
output = new Output(outputs[0]);
|
|
App.MIDI.output = output;
|
|
|
|
resolve(output);
|
|
} else {
|
|
reject(new Error(
|
|
"Aucun synthétiseur MIDI n'est disponible. Sur " +
|
|
"systèmes d'exploitation, un synthétiseur " +
|
|
"est disponible par défaut. S'il ce n'est pas " +
|
|
"votre cas, il faudra utiliser un logiciel " +
|
|
"tiers pour synthétiser les sons.<br /><br />" +
|
|
ignoreAlert
|
|
));
|
|
}
|
|
}).catch(function () {
|
|
reject(new Error(
|
|
"Impossible d'obtenir un accès aux contrôleurs " +
|
|
"MIDI, il est possible que votre système ne " +
|
|
"supporte pas la norme MIDI ou bien que " +
|
|
"vous ayez refusé l'accès à ces périphériques. " +
|
|
"<br /><br />" + ignoreAlert
|
|
));
|
|
});
|
|
});
|
|
|
|
return promise;
|
|
}
|
|
|
|
App.MIDI.connect = connect;
|
|
}()); |