// gTar HTML 5 SDK
// Currently this requires the Jazz-Plugin to work: http://jazz-soft.net/
// Tested in Chrome
var version = {
major: 0,
minor: 1
};
var MIDI_MSG = {
NOTE_ON : 0x90,
NOTE_OFF : 0x80,
CTRL_CHN : 0xB0,
START_SYSEX : 0xF0,
END_SYSEX : 0xF7
};
var GTAR_ID = 0x77;
var GTAR_MSG = {
SET_LED : 0x00,
SET_NOTE_ACTIVE : 0x01,
SET_FRET_FOLLOW : 0x02,
REQ_AUTH_REDOWNLOAD : 0x03,
REQ_FW_VERSION : 0x04,
DOWNLOAD_NEW_FW_PACKAGE : 0x05,
EXEC_FW_UPDATE : 0x06,
SET_PIEZO_STATE : 0x07,
SET_PIEZO_THRESH : 0x08,
SET_SMART_PICK_THRESH : 0x09,
SET_LED_EX : 0x0A,
CALIBRATE_PIEZO_STRING : 0x0B,
ENABLE_VELOCITY : 0x0C,
DISABLE_VELOCITY : 0x0D,
REQ_BATTERY_STATUS : 0x0E,
SET_FRETBOARD_THRESH : 0x0F,
ENABLE_DEBUG : 0x11,
DISABLE_DEBUG : 0x12,
SET_PIEZO_CT_MATRIX : 0x13,
GET_PIEZO_CT_MATRIX : 0x14,
SET_PIEZO_SENSITIVITY : 0x15,
GET_PIEZO_SENSITIVITY : 0x16,
SET_PIEZO_WINDOW : 0x17,
GET_PIEZO_WINDOW : 0x10,
GET_PIEZO_TIMEOUT : 0x1B,
SET_PIEZO_TIMEOUT : 0x1C,
REQ_SERIAL_NUM : 0x18,
SET_SERIAL_NUMBER : 0x19,
SET_ACCELEROMETER_STATE : 0x1A,
COMMIT_USERSPACE : 0x1D,
RESET_USERSPACE : 0x1E,
INVALID : 0xFF
};
var GTAR_ACK = {
DOWNLOAD_FW : 0x35,
BATTERY_STATUS : 0x36,
BATTERY_PERCENTAGE : 0x37,
GET_PIEZO_CT_MATRIX : 0x38,
GET_PIEZO_SENSITIVITY : 0x39,
GET_PIEZO_WINDOW : 0x3A,
GET_PIEZO_TIMEOUT : 0x3B,
REQUEST_SERIAL_NUMBER : 0x3C,
CALIBRATE_PIEZO_STRING : 0x3D,
COMMIT_USERSPACE : 0x3E,
RESET_USERSPACE : 0x3F,
INVALID : 0xFF
};
var g_gtar = null;
function gtarConnect() {
console.log("Connecting to gTar...");
g_gtar = new gtar();
return g_gtar;
}
function MRGB(M, R, G, B)
{
return ((M & 0x3) << 6) +
((R & 0x3) << 4) +
((G & 0x3) << 2) +
((B & 0x3) << 0);
};
function RGBM(R, G, B, M)
{
return ((R & 0x3) << 6) +
((G & 0x3) << 4) +
((B & 0x3) << 2) +
((M & 0x3) << 0);
};
var g_GtarSubscriberIdCount = 0;
function getGtarSubscriberId() {
return g_GtarSubscriberIdCount++;
}
function GtarSubscriber(cbNotification) {
this.self = this;
this.m_id = getGtarSubscriberId();
this.m_cbNotification = cbNotification;
}
function gtar()
{
this.self = this;
console.log(this.self);
this.m_midi = null;
this.m_input = null;
this.m_output = null;
// subscribers
this.m_Subscribers = new Array();
// Init MIDI
navigator.requestMIDIAccess(gtarHandleMidiSuccess, gtarHandleMidiFailure);
};
gtar.prototype.isConnected = function() {
if(this.m_input != null && this.m_output != null && this.m_midi != null)
return true;
else
return false;
}
// MIDI Handler
function gtarHandleMidi( ev ) {
var self = g_gtar;
var msgType = ev.data[0] & 0xF0;
var channel = ev.data[0] & 0x0F;
//console.log('midi msg type ' + msgType + ' on channel ' + channel);
self.NotifySubscribers(msgType, channel, ev.data[1], ev.data[2]);
};
gtar.prototype.AddSubscriber = function(cbNotification) {
var gtarSubscriber = new GtarSubscriber(cbNotification);
this.m_Subscribers.push(gtarSubscriber);
return gtarSubscriber.m_id;
}
gtar.prototype.RemoveSubscriber = function(SubscriberId) {
console.log(this.m_Subscribers);
for(subscriber in this.m_Subscribers) {
if(this.m_Subscribers[subscriber].m_id == SubscriberId)
{
var newArray = null;
if(subscriber == 0) { // first eleemtn
newArray = this.m_Subscribers.slice(1, this.m_Subscribers.length);
}
else if (subscriber == this.m_Subscribers.length - 1) { // last element
newArray = this.m_Subscribers.slice(0, -1);
}
else { // some element in the middle
var left = this.m_Subscribers.slice(0, subscriber);
var rightIndex = parseInt(subscriber) + 1;
newArray = left.concat(this.m_Subscribers.slice(rightIndex, this.m_Subscribers.length));
}
this.m_Subscribers = newArray;
return this.m_Subscribers.length;
}
}
return -1; // subscriber not found
}
gtar.prototype.NotifySubscribers = function(msgType, channel, data1, data2) {
for(subscriber in this.m_Subscribers) {
if(this.m_Subscribers[subscriber].m_cbNotification != null) {
this.m_Subscribers[subscriber].m_cbNotification(msgType, channel, data1, data2);
}
}
}
function gtarHandleMidiSuccess( midi )
{
var self = g_gtar;
self.m_midi = midi;
console.log("Midi Available");
// Set up inputs
var inputs = self.m_midi.getInputs();
console.log("Found " + inputs.length + " inputs:");
for( var i = 0; i < inputs.length; i++)
{
console.log(i +": " + inputs[i]);
if(inputs[i].name == "gTar" )
{
self.m_input = self.m_midi.getInput(i);
self.m_input.onmessage = gtarHandleMidi;
console.log("Found gTar input device: " + i);
}
}
var outputs = self.m_midi.getOutputs();
console.log("Found " + outputs.length + " outputs:");
for( var i = 0; i < outputs.length; i++)
{
console.log(i +": " + outputs[i]);
if(outputs[i].name === 'gTar')
{
self.m_output = self.m_midi.getOutput(i);
console.log("Found gTar output device: " + i);
}
}
if(self.m_input == null || self.m_output == null)
{
console.log("gTar not found");
return false;
}
else
{
console.log("gTar found and initialized");
return true;
}
};
function gtarHandleMidiFailure( error )
{
console.log("Failed to initialize MIDI: ");
if(error.code == 1)
console.log("permission denied");
else
console.log("error code " + error.code);
return false;
};
gtar.prototype.sendBuffer = function(uint8arrayData)
{
if(this.m_output === null)
{
console.log("sendBuffer: gTar output null");
return false;
}
try {
this.m_output.send(uint8arrayData);
}
catch(err) {
console.log("setLEDEx: Failed to send data");
console.log(err);
}
}
gtar.prototype.checkStringFret = function(string, fret)
{
if(string < 0 || string > 6) {
console.log("checkStringFret: string out of range");
return false;
}
else if(fret < 0 || fret > 16) {
console.log("checkStringFret: fret out of range");
return false;
}
else {
return true;
}
}
gtar.prototype.setLED = function(string, fret, R, G, B, M)
{
if(!this.checkStringFret(string, fret)) {
console.log("setLEDEx: check params");
return false;
}
var data = new Uint8Array([MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.SET_LED,
(string & 0xFF), (fret & 0xFF), RGBM(M, R, G, B),
MIDI_MSG.END_SYSEX]);
return this.sendBuffer(data);
}
gtar.prototype.setLEDEx = function(string, fret, R, G, B, M)
{
if(!this.checkStringFret(string, fret)) {
console.log("setLEDEx: check params");
return false;
}
var data = new Uint8Array([MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.SET_LED_EX,
(string & 0xFF), (fret & 0xFF), MRGB(M, R, G, B),
MIDI_MSG.END_SYSEX]);
return this.sendBuffer(data);
}
gtar.prototype.setNoteActive = function(R, G, B, M) {
return this.sendBuffer(
new Uint8Array(
[MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.SET_NOTE_ACTIVE, MRGB(M, R, G, B), MIDI_MSG.END_SYSEX]));
}
gtar.prototype.setFretFollow = function(R, G, B, M) {
return this.sendBuffer(
new Uint8Array(
[MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.SET_FRET_FOLLOW, MRGB(M, R, G, B), MIDI_MSG.END_SYSEX]));
}
gtar.prototype.requestBatteryStatus = function() {
return this.sendBuffer(
new Uint8Array(
[MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.REQ_BATTERY_STATUS, MIDI_MSG.END_SYSEX]));
}
gtar.prototype.requestFWVersion = function () {
return this.sendBuffer(
new Uint8Array(
[MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.REQ_FW_VERSION, MIDI_MSG.END_SYSEX]));
}
gtar.prototype.requestSerialNumberByte = function(byteNumber) {
if(byteNumber < 0 || byteNumber > 16) {
console.log("requestSerialNumberByte: byteNumber out of bounds");
return false;
}
return this.sendBuffer(
new Uint8Array(
[MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.REQ_SERIAL_NUM, (byteNumber & 0xFF), MIDI_MSG.END_SYSEX]));
}
// TODO
/*
gtar.prototype.downloadFirmwarePackage = function() {
}
gtar.prototype.executeFWUpdate = function () {
}
*/
gtar.prototype.setSerialNumber = function(serialBuffer) {
if(serialBuffer.length != 16) {
console.log("setSerialNumber: serialBuffer length must be 16");
return false;
}
var setSerialNumberCmd = new Uint8Array(
[MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.SET_SERIAL_NUMBER, 0x00, 0x00, MIDI_MSG.END_SYSEX]
);
// Splice in the serial number buffer at byte #5 (gTar HW spec)
var splceArgs = [5, serialBuffer.length].concat(serialBuffer);
Array.prototype.splice.apply(setSerialNumberCmd, spliceArgs);
return this.sendBuffer(setSerialNumberCmd);
}
gtar.prototype.setAccelerometerState = function(accelEnableBitfield, msUpdateSpeed) {
// Keep it 8-bit
accelEnableBitfield = accelEnableBitfield & 0xFF;
msUpdateSpeed = msUpdateSpeed & 0xFF;
return this.sendBuffer(
new Uint8Array(
[MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.SET_ACCELEROMETER_STATE, accelEnableBitfield, msUpdateSpeed, MIDI_MSG.END_SYSEX]
)
);
}
gtar.prototype.enableDebugMode = function() {
return this.sendBuffer(new Uint8Array([MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.ENABLE_DEBUG, MIDI_MSG.END_SYSEX]));
}
gtar.prototype.disableDebugMode = function() {
return this.sendBuffer(new Uint8Array([MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.DISABLE_DEBUG, MIDI_MSG.END_SYSEX]));
}
gtar.prototype.commitUserspace = function() {
return this.sendBuffer(new Uint8Array([MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.COMMIT_USERSPACE, MIDI_MSG.END_SYSEX]));
}
gtar.prototype.resetUserspace = function() {
return this.sendBuffer(new Uint8Array([MIDI_MSG.START_SYSEX, GTAR_ID, GTAR_MSG.RESET_USERSPACE, MIDI_MSG.END_SYSEX]));
}