jzz-input-kbd
Version:
Virtual piano controls for your MIDI projects
1,421 lines (1,307 loc) • 57.1 kB
JavaScript
(function(global, factory) {
if (typeof exports === 'object' && typeof module !== 'undefined') {
factory.Kbd = factory;
module.exports = factory;
}
else if (typeof define === 'function' && define.amd) {
define('JZZ.input.Kbd', ['JZZ'], factory);
}
else {
factory(JZZ);
}
})(this, function(JZZ) {
if (!JZZ) return;
if (!JZZ.input) JZZ.input = {};
var _version = '1.3.4';
function _name(name, deflt) { return name ? name : deflt; }
function _copy(obj) {
var ret = {};
for(var k in obj) ret[k] = obj[k];
return ret;
}
function _keycode(x) {
var z = x.toUpperCase();
if (z.length == 1) {
var k = z.charCodeAt(0);
if (k >= 65 && k <= 90) return 'Key' + z;
if (k >= 48 && k <= 57) return 'Digit' + z;
}
z = {
ESC: 'Escape',
TAB: 'Tab',
BSP: 'Backspace',
'-': 'Minus', '_': 'Minus',
'+': 'Equal', '=': 'Equal',
'[': 'BracketLeft', '{': 'BracketLeft',
']': 'BracketRight', '}': 'BracketRight',
';':'Semicolon', ':': 'Semicolon',
"'": 'Quote', '"': 'Quote',
'`': 'Backquote', '~': 'Backquote',
'|': 'Backslash', '\\': 'Backslash',
',': 'Comma', '<': 'Comma',
'.': 'Period', '>': 'Period',
'/': 'Slash', '?': 'Slash',
' ': 'Space'
}[z];
return z ? z : x;
}
function _codekey(k) {
if (k >= 65 && k <= 90) return 'Key' + String.fromCharCode(k);
if (k >= 48 && k <= 57) return 'Digit' + String.fromCharCode(k);
return {
9: 'Tab',
8: 'Backspace',
27: 'Escape',
32: 'Space',
59: 'Semicolon',
171: 'Equal',
173: 'Minus',
188: 'Comma',
190: 'Period',
191: 'Slash',
192: 'Backquote',
219: 'BracketLeft',
220: 'Backslash',
221: 'BracketRight',
222: 'Quote',
}[k];
}
var _channelMap = { a:10, b:11, c:12, d:13, e:14, f:15, A:10, B:11, C:12, D:13, E:14, F:15 };
for (var k = 0; k < 16; k++) _channelMap[k] = k;
function Keyboard(arg) {
this.notes = {};
this.playing = [];
if (typeof arg == 'undefined') arg = {};
if (typeof arg.mpe != 'undefined') {
JZZ.MPE.validate(arg.mpe);
this.mpe = arg.mpe;
this.chan = arg.mpe[0];
}
else {
this.chan = _channelMap[arg.chan];
if (typeof this.chan == 'undefined') this.chan = 0;
}
for (var k in arg) {
var key = _keycode(k);
if (typeof arg[k] == 'function') {
this.notes[key] = arg[k];
}
else {
var val = JZZ.MIDI.noteValue(arg[k]);
if (typeof key != 'undefined' && typeof val != 'undefined') this.notes[key] = val;
}
}
var self = this;
this.keydown = function(e) {
var midi = e.code ? self.notes[e.code] : self.notes[_codekey(e.keyCode)];
if (typeof midi != 'undefined') {
e.preventDefault();
if (typeof midi == 'function') {
midi.apply(self, [true]);
}
else if (!self.playing[midi]) {
self.playing[midi] = true;
self.noteOn(midi);
}
}
};
this.keyup = function(e) {
var midi = e.code ? self.notes[e.code] : self.notes[_codekey(e.keyCode)];
if (typeof midi != 'undefined') {
e.preventDefault();
if (typeof midi == 'function') {
midi.apply(self, [false]);
}
if (self.playing[midi]) {
self.playing[midi] = undefined;
self.noteOff(midi);
}
}
};
if (typeof arg.at == 'string') this.at = document.getElementById(arg.at);
try {
this.at.addEventListener('keydown', this.keydown);
this.at.addEventListener('keyup', this.keyup);
if (!this.at.tabIndex || this.at.tabIndex < 0) this.at.tabIndex = 0; // allow keyboard focus
}
catch(e) {
document.addEventListener('keydown', this.keydown);
document.addEventListener('keyup', this.keyup);
this.at = document;
}
this._close = function() {
this.at.removeEventListener('keydown', this.keydown);
this.at.removeEventListener('keyup', this.keyup);
for (var midi in self.playing) self.noteOff(midi);
};
}
Keyboard.prototype.channel = function(c) {
if (typeof this.mpe == 'undefined') {
var chan = _channelMap[c];
if (typeof chan != 'undefined') this.chan = chan;
}
return this.chan;
};
function AsciiEngine() {}
AsciiEngine.prototype._info = function(name) {
return {
type: 'html/javascript',
name: _name(name, 'ASCII'),
manufacturer: 'virtual',
version: _version
};
};
AsciiEngine.prototype._openIn = function(port, name) {
var keyboard = new Keyboard(this._arg);
keyboard.port = port;
if (keyboard.mpe) {
if (!port._orig._mpe) port._orig._mpe = JZZ.MPE();
port._orig._mpe.setup(keyboard.mpe[0], keyboard.mpe[1]);
keyboard.noteOn = function(note) {
var msg = JZZ.MIDI(0x90 + this.chan, note, 127);
msg._mpe = note;
port._receive(msg);
};
keyboard.noteOff = function(note) {
var msg = JZZ.MIDI(0x80 + this.chan, note, 127);
msg._mpe = note;
port._receive(msg);
};
}
else {
keyboard.noteOn = function(note) { port._receive(JZZ.MIDI(0x90 + this.chan, note, 127)); };
keyboard.noteOff = function(note) { port._receive(JZZ.MIDI(0x80 + this.chan, note, 127)); };
}
port._info = this._info(name);
port._close = function() { keyboard._close(); };
port.channel = function(x) { return keyboard.channel(x); };
port._resume();
};
JZZ.input.ASCII = function() {
var name, arg;
if (arguments.length == 1) {
if (typeof arguments[0] == 'string') name = arguments[0];
else arg = arguments[0];
}
else { name = arguments[0]; arg = arguments[1];}
var _AsciiEngine = new AsciiEngine();
_AsciiEngine._arg = arg;
return JZZ.lib.openMidiIn(name, _AsciiEngine);
};
JZZ.input.ASCII.register = function() {
var name, arg;
if (arguments.length == 1) {
if (typeof arguments[0] == 'string') name = arguments[0];
else arg = arguments[0];
}
else { name = arguments[0]; arg = arguments[1];}
var _AsciiEngine = new AsciiEngine();
_AsciiEngine._arg = arg;
return JZZ.lib.registerMidiIn(name, _AsciiEngine);
};
var _firefoxBug;
function _fixBtnUp(e) {
if (typeof e.buttons == 'undefined' || e.buttons != _firefoxBug) return e;
e.stopPropagation();
if (e.button == 0) return {buttons:_firefoxBug^1};
if (e.button == 1) return {buttons:_firefoxBug^4};
if (e.button == 2) return {buttons:_firefoxBug^2};
}
function _lftBtnDn(e) { return typeof e.buttons == 'undefined' ? !e.button : e.buttons & 1; }
function _lftBtnUp(e) { return typeof e.buttons == 'undefined' ? !e.button : !(e.buttons & 1); }
function _stay(c, p) { for (; c; c = c.parentNode) if (c == p) return true; return false; }
function _returnFalse() { return false; }
function _style(key, stl) {
if (key) for(var k in stl) key.style[k] = stl[k];
}
function _keyNum(n, up) {
n = JZZ.MIDI.noteValue(n);
return (up ? [0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6] : [0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6])[n % 12] + Math.floor(n / 12) * 7;
}
function _keyMidi(n) {
return Math.floor(n / 7) * 12 + {0:0, 1:2, 2:4, 3:5, 4:7, 5:9, 6:11}[n % 7];
}
function _handleMouseDown(piano, midi) {
return function(e) {
if (_lftBtnDn(e) && !piano.playing[midi]) {
piano.mouseDown = true;
piano.playing[midi] = 'M';
piano.press(midi);
}
_firefoxBug = e.buttons;
};
}
function _handleMouseOver(piano, midi) {
return function(e) {
if (piano.mouseDown && !piano.playing[midi]) {
piano.playing[midi] = 'M';
piano.press(midi);
}
_firefoxBug = e.buttons;
};
}
function _handleMouseOut(piano, midi) {
return function(e) {
if (piano.mouseDown && piano.playing[midi] == 'M' && !_stay(e.relatedTarget, this)) {
piano.playing[midi] = undefined;
piano.release(midi);
}
_firefoxBug = e.buttons;
};
}
function _handleMouseUp(piano, midi) {
return function(e) {
e = _fixBtnUp(e);
if (_lftBtnUp(e) && piano.mouseDown && piano.playing[midi] == 'M') {
piano.playing[midi] = undefined;
piano.release(midi);
piano.mouseDown = false;
}
};
}
function _handleMouseOff(piano) {
return function(e) {
e = _fixBtnUp(e);
if (_lftBtnUp(e)) piano.mouseDown = false;
};
}
function _watchMouseButtons() {
return function(e) {
_firefoxBug = e.buttons;
};
}
function _handleTouch(piano) {
return function(e) {
e.preventDefault();
var t = {};
for (var i = 0; i < e.touches.length; i++) piano.findKey(e.touches[i].clientX, e.touches[i].clientY, t);
var tt = {};
var midi;
for (midi in t) {
if (midi in piano.touches) tt[midi] = true;
else if (typeof piano.playing[midi] == 'undefined') {
piano.playing[midi] = 'T';
piano.press(midi);
tt[midi] = true;
}
}
for (midi in piano.touches) {
if (!(midi in t)) {
piano.playing[midi] = undefined;
piano.release(midi);
}
}
piano.touches = tt;
};
}
function Piano(arg) {
this.bins = [];
this.params = {0:{}};
var common = {from:'C4', to:'E6', ww:42, bw:24, wl:150, bl:100, pos:'N'};
if (typeof arg == 'undefined') arg = {};
if (typeof arg.mpe != 'undefined') {
JZZ.MPE.validate(arg.mpe);
this.mpe = arg.mpe;
this.chan = arg.mpe[0];
}
else {
this.chan = _channelMap[arg.chan];
if (typeof this.chan == 'undefined') this.chan = 0;
}
var key;
for (key in arg) {
if (key == parseInt(key)) this.params[key] = _copy(arg[key]);
else {
if (key == 'chan') continue;
if ((key == 'from' || key == 'to') && typeof JZZ.MIDI.noteValue(arg[key]) == 'undefined') continue;
common[key] = arg[key];
}
}
for (key in this.params) {
this.bins.push(key);
for (var k in common) {
if ((k == 'from' || k == 'to') && (typeof this.params[key][k] == 'undefined' || typeof JZZ.MIDI.noteValue(this.params[key][k]) == 'undefined')) this.params[key][k] = common[k];
if (!(k in this.params[key])) this.params[key][k] = common[k];
}
var from = this.params[key].from;
var to = this.params[key].to;
if (JZZ.MIDI.noteValue(from) > JZZ.MIDI.noteValue(to)) {
this.params[key].from = to;
this.params[key].to = from;
}
}
this.bins.sort(function(a, b) { return a - b;});
}
Piano.prototype.channel = function(c) {
if (typeof this.mpe == 'undefined') {
var chan = _channelMap[c];
if (typeof chan != 'undefined' && chan != this.chan) {
for (var midi in this.playing) {
_style(this.keys[midi], this.keys[midi]._active ? this.stl0[midi] : this.stl2[midi]);
_style(this.keys[midi], this.locs[midi]);
}
this.chan = chan;
}
}
return this.chan;
};
Piano.prototype._close = function() {
for (var midi in this.playing) if (this.playing[midi] == 'M' || this.playing[midi] == 'T') this.noteOff(midi);
if (this.resize) window.removeEventListener('resize', this.resize);
this.cleanup();
};
Piano.prototype.press = function(midi) {
if (this.keys[midi]._active) {
_style(this.keys[midi], this.stl1[midi]);
_style(this.keys[midi], this.locs[midi]);
this.noteOn(midi);
}
};
Piano.prototype.release = function(midi) {
if (this.keys[midi]._active) {
_style(this.keys[midi], this.stl0[midi]);
_style(this.keys[midi], this.locs[midi]);
this.noteOff(midi);
}
};
Piano.prototype.forward = function(msg) {
var n = msg[1];
var ch = msg.getChannel();
if (ch >= this.chan && ch <= (this.mpe ? this.chan + this.mpe[1] : this.chan)) {
var s = msg[0] >> 4;
if (msg.isNoteOn()) {
if (this.keys[n]) {
this.playing[n] = 'E';
_style(this.keys[n], this.stl1[n]);
_style(this.keys[n], this.locs[n]);
}
}
else if (msg.isNoteOff()) {
if (this.keys[n]) {
this.playing[n] = undefined;
_style(this.keys[n], this.keys[n]._active ? this.stl0[n] : this.stl2[n]);
_style(this.keys[n], this.locs[n]);
}
}
else if (s == 0xb && (n == 0x78 || n == 0x7b)) { // all notes/snd off
for (n in this.playing) {
this.playing[n] = undefined;
_style(this.keys[n], this.keys[n]._active ? this.stl0[n] : this.stl2[n]);
_style(this.keys[n], this.locs[n]);
}
}
}
this.emit(msg);
};
Piano.prototype.clear = function() {
for (var n in this.playing) {
this.playing[n] = undefined;
_style(this.keys[n], this.keys[n]._active ? this.stl0[n] : this.stl2[n]);
_style(this.keys[n], this.locs[n]);
}
};
Piano.prototype.findKey = function(x, y, ret) {
for (var midi in this.keys) {
for (var elm = document.elementFromPoint(x, y); elm; elm = elm.parentNode) {
if (this.keys[midi] == elm) {
ret[midi] = true;
return;
}
}
}
};
Piano.prototype.create = function() {
var bin = 0;
for (var i = 0; i < this.bins.length; i++) {
if (this.bins[i] <= window.innerWidth) bin = this.bins[i];
else break;
}
this.current = this.params[bin];
this.createCurrent();
};
function _unit(a, b) {
a = (a + '').trim();
b = (b + '').trim();
return a.endsWith('%') && b.endsWith('%') ? '%' : 'px';
}
Piano.prototype.createCurrent = function() {
this.cleanup();
this.keys = {}; this.locs = {};
this.stl0 = {}; this.stl1 = {}; this.stl2 = {};
this.playing = {}; this.touches = {};
if (!this.current.ul) {
this.current.ul = _unit(this.current.wl, this.current.bl);
this.current.wl = parseFloat(this.current.wl);
this.current.bl = parseFloat(this.current.bl);
}
if (!this.current.uw) {
this.current.uw = _unit(this.current.ww, this.current.bw);
this.current.ww = parseFloat(this.current.ww);
this.current.bw = parseFloat(this.current.bw);
}
if (this.current.keys) {
this.createWithKeys(this.current.keys);
return;
}
if (typeof this.current.at == 'string') this.current.at = document.getElementById(this.current.at);
try { this.createAt(this.current.at); }
catch(e) {
if (!this.bottom) {
this.bottom = document.createElement('div');
document.body.appendChild(this.bottom);
}
this.createAt(this.bottom);
}
};
Piano.prototype.createWithKeys = function(keys) {
for (var k in keys) {
var midi = JZZ.MIDI.noteValue(keys[k][1]);
var dom = keys[k][0];
if (typeof dom == 'string') dom = document.getElementById(dom);
this.keys[midi] = dom;
this.locs[midi] = {};
this.stl0[midi] = {};
this.stl1[midi] = {};
this.stl2[midi] = {};
}
this.setListeners();
if (this.current.onCreate) this.current.onCreate.apply(this);
};
Piano.prototype.createAt = function(at) {
at.innerHTML = '';
var pos = this.current.pos.toUpperCase();
var first = _keyNum(this.current.from);
var last = _keyNum(this.current.to, true);
var num = last - first + 1;
var w = num * this.current.ww;
var h = this.current.wl;
var ul = this.current.ul;
var uw = this.current.uw;
var ww = this.current.ww;
var wl = this.current.wl;
var bw = this.current.bw;
var bl = this.current.bl;
if (uw != '%') { w++; ww--; bw--; }
if (ul != '%') { h++; wl--; bl--; }
var l2r = (pos != 'N') ^ !this.current.rev;
var t2b = (pos != 'E') ^ !this.current.rev;
var midi;
var key;
var stl;
var piano = document.createElement('span');
piano.style.display = 'inline-block';
piano.style.position = 'relative';
piano.style.margin = '0px';
piano.style.padding = '0px';
piano.style.borderStyle = 'none';
piano.style.userSelect = 'none';
piano.style.MozUserSelect = 'none';
piano.style.WebkitUserSelect = 'none';
piano.style.MsUserSelect = 'none';
piano.style.KhtmlUserSelect = 'none';
piano.style.cursor = 'default';
if (pos == 'E' || pos == 'W') {
piano.style.width = h + ul;
piano.style.height = w + uw;
}
else {
piano.style.width = w + uw;
piano.style.height = h + ul;
}
for (var i = 0; i < num; i++) {
midi = _keyMidi(i + first);
key = document.createElement('span'); this.keys[midi] = key;
stl = { display:'inline-block', position:'absolute', margin:'0px', padding:'0px', borderStyle:'solid', borderWidth:'1px' };
this.locs[midi] = stl;
if (pos == 'E' || pos == 'W') {
stl.width = wl + ul;
stl.height = ww + uw;
stl.left = '0px';
stl[t2b ? 'top' : 'bottom'] = (this.current.ww * i) + uw;
}
else {
stl.width = ww + uw;
stl.height = wl + ul;
stl.top = '0px';
stl[l2r ? 'left' : 'right'] = (this.current.ww * i) + uw;
stl.verticalAlign = 'top';
}
this.stl0[midi] = { backgroundColor:'#fff', borderColor:'#000' };
this.stl1[midi] = { backgroundColor:'#aaa', borderColor:'#000' };
this.stl2[midi] = { backgroundColor:'#fff', borderColor:'#000' };
_style(key, this.stl0[midi]);
_style(key, stl);
piano.appendChild(key);
}
var hole = Math.ceil(this.current.ww - this.current.bw * 3 / 4);
if ((hole + this.current.ww) % 2) hole--; // both even or both odd
var from = _keyMidi(first) + 1;
var to = _keyMidi(last);
for (midi = from; midi < to; midi++) {
var note = midi % 12;
var oct = Math.floor(midi / 12);
var shift;
if (note == 1) { // C#
shift = Math.floor(this.current.ww * (oct * 7 + 1.5 - first)) - hole / 2 - this.current.bw;
}
else if (note == 3) { // D#
shift = Math.floor(this.current.ww * (oct * 7 + 1.5 - first) + hole / 2);
}
else if (note == 6) { // F#
shift = this.current.ww * (oct * 7 + 5 - first) - Math.floor(this.current.bw / 2) - hole - this.current.bw;
}
else if (note == 8) { // G#
shift = this.current.ww * (oct * 7 + 5 - first) - Math.floor(this.current.bw / 2);
}
else if (note == 10) {// Bb
shift = this.current.ww * (oct * 7 + 5 - first) - Math.floor(this.current.bw / 2) + hole + this.current.bw;
}
else continue;
key = document.createElement('span'); this.keys[midi] = key;
stl = { display:'inline-block', position:'absolute', margin:'0px', padding:'0px', borderStyle:'solid', borderWidth:'1px' };
this.locs[midi] = stl;
if (pos == 'E' || pos == 'W') {
stl.width = bl + ul;
stl.height = bw + uw;
stl[pos == 'E' ? 'right' : 'left'] = '0px';
stl[t2b ? 'top' : 'bottom'] = shift + uw;
}
else {
stl.width = bw + uw;
stl.height = bl + ul;
stl[pos == 'N' ? 'top' : 'bottom'] = '0px';
stl[l2r ? 'left' : 'right'] = shift + uw;
}
this.stl0[midi] = { backgroundColor:'#000', borderColor:'#000' };
this.stl1[midi] = { backgroundColor:'#888', borderColor:'#000' };
this.stl2[midi] = { backgroundColor:'#000', borderColor:'#000' };
_style(key, this.stl0[midi]);
_style(key, stl);
piano.appendChild(key);
}
at.appendChild(piano);
this.current.at = at;
this.at = at;
this.setListeners();
if (this.current.onCreate) this.current.onCreate.apply(this);
};
Piano.prototype.setListeners = function() {
var active = typeof this.current.active == 'undefined' || !!this.current.active;
var midi;
this.watchButtons = _watchMouseButtons();
this.mouseUpHandle = _handleMouseOff(this);
window.addEventListener("mousedown", this.watchButtons);
window.addEventListener("mousemove", this.watchButtons);
window.addEventListener("mouseup", this.mouseUpHandle);
this.touchHandle = _handleTouch(this);
this.mouseDownH = [];
this.mouseOverH = [];
this.mouseOutH = [];
this.mouseUpH = [];
for (midi in this.keys) {
this.mouseDownH[midi] = _handleMouseDown(this, midi);
this.mouseOverH[midi] = _handleMouseOver(this, midi);
this.mouseOutH[midi] = _handleMouseOut(this, midi);
this.mouseUpH[midi] = _handleMouseUp(this, midi);
this.keys[midi].addEventListener("mousedown", this.mouseDownH[midi]);
this.keys[midi].addEventListener("mouseover", this.mouseOverH[midi]);
this.keys[midi].addEventListener("mouseout", this.mouseOutH[midi]);
this.keys[midi].addEventListener("mouseup", this.mouseUpH[midi]);
this.keys[midi].addEventListener("touchstart", this.touchHandle);
this.keys[midi].addEventListener("touchmove", this.touchHandle);
this.keys[midi].addEventListener("touchend", this.touchHandle);
this.keys[midi].addEventListener("touchcancel", this.touchHandle);
}
for (midi in this.keys) {
if (typeof this.keys[midi]._active == 'undefined') this.keys[midi]._active = active;
this.keys[midi].ondragstart = _returnFalse;
this.keys[midi].onselectstart = _returnFalse;
}
if (!this.resize && this.bins.length > 1) {
var self = this;
this.resize = function() { self.onResize(); };
window.addEventListener('resize', this.resize);
}
};
Piano.prototype.cleanup = function() {
if (this.watchButtons) {
window.removeEventListener("mousedown", this.watchButtons);
window.removeEventListener("mousemove", this.watchButtons);
window.removeEventListener("mouseup", this.mouseUpHandle);
}
for (var midi in this.keys) {
if (this.mouseDownH[midi]) this.keys[midi].removeEventListener("mousedown", this.mouseDownH[midi]);
if (this.mouseOverH[midi]) this.keys[midi].removeEventListener("mouseover", this.mouseOverH[midi]);
if (this.mouseOutH[midi]) this.keys[midi].removeEventListener("mouseout", this.mouseOutH[midi]);
if (this.mouseUpH[midi]) this.keys[midi].removeEventListener("mouseup", this.mouseUpH[midi]);
if (this.touchHandle) {
this.keys[midi].removeEventListener("touchstart", this.touchHandle);
this.keys[midi].removeEventListener("touchmove", this.touchHandle);
this.keys[midi].removeEventListener("touchend", this.touchHandle);
this.keys[midi].removeEventListener("touchcancel", this.touchHandle);
}
}
if (this.at) this.at.innerHTML = '';
};
Piano.prototype.settings = function() { return _copy(this.current); };
Piano.prototype.onResize = function() {
var bin = 0;
for (var i = 0; i < this.bins.length; i++) {
if (this.bins[i] <= window.innerWidth) bin = this.bins[i];
else break;
}
if (this.current == this.params[bin]) return;
this.current = this.params[bin];
this.createCurrent();
};
Piano.prototype.enable = function() {
for (var k in this.keys) this.keys[k]._active = true;
return this;
};
Piano.prototype.disable = function() {
for (var k in this.keys) this.keys[k]._active = false;
return this;
};
Piano.prototype.getKey = function(note) {
var keys = new Keys(this);
var k = JZZ.MIDI.noteValue(note);
if (typeof this.keys[k] != 'undefined') keys.keys.push(k);
return keys;
};
Piano.prototype.getKeys = function(from, to) {
var keys = new Keys(this);
var n0 = typeof from == 'undefined' ? undefined : JZZ.MIDI.noteValue(from);
var n1 = typeof to == 'undefined' ? undefined : JZZ.MIDI.noteValue(to);
if (typeof n0 != 'undefined' && typeof n1 != 'undefined' && n1 < n0) { var nn = n0; n0 = n1; n1 = nn; }
for (var k in this.keys) {
if (typeof n0 != 'undefined' && k < n0) continue;
if (typeof n1 != 'undefined' && k > n1) continue;
keys.keys.push(k);
}
return keys;
};
Piano.prototype.getWhiteKeys = function(from, to) {
var keys = new Keys(this);
var n0 = typeof from == 'undefined' ? undefined : JZZ.MIDI.noteValue(from);
var n1 = typeof to == 'undefined' ? undefined : JZZ.MIDI.noteValue(to);
if (typeof n0 != 'undefined' && typeof n1 != 'undefined' && n1 < n0) { var nn = n0; n0 = n1; n1 = nn; }
for (var k in this.keys) {
if (typeof n0 != 'undefined' && k < n0) continue;
if (typeof n1 != 'undefined' && k > n1) continue;
var n = k % 12;
if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) continue;
keys.keys.push(k);
}
return keys;
};
Piano.prototype.getBlackKeys = function(from, to) {
var keys = new Keys(this);
var n0 = typeof from == 'undefined' ? undefined : JZZ.MIDI.noteValue(from);
var n1 = typeof to == 'undefined' ? undefined : JZZ.MIDI.noteValue(to);
if (typeof n0 != 'undefined' && typeof n1 != 'undefined' && n1 < n0) { var nn = n0; n0 = n1; n1 = nn; }
for (var k in this.keys) {
if (typeof n0 != 'undefined' && k < n0) continue;
if (typeof n1 != 'undefined' && k > n1) continue;
var n = k % 12;
if (n != 1 && n != 3 && n != 6 && n != 8 && n != 10) continue;
keys.keys.push(k);
}
return keys;
};
function Keys(piano) {
this.piano = piano;
this.keys = [];
}
Keys.prototype.setInnerHTML = function(html) {
for (var k in this.keys) this.piano.keys[this.keys[k]].innerHTML = html;
return this;
};
Keys.prototype.setStyle = function(s0, s1, s2) {
var k, n, midi;
if (typeof s1 == 'undefined') s1 = s0;
if (typeof s2 == 'undefined') s2 = s0;
for (k in this.keys) {
midi = this.keys[k];
for (n in s0) this.piano.stl0[midi][n] = s0[n];
for (n in s1) this.piano.stl1[midi][n] = s1[n];
for (n in s2) this.piano.stl2[midi][n] = s2[n];
_style(this.piano.keys[midi], this.piano.playing[midi] ? this.piano.stl1[midi] : this.piano.keys[midi]._active ? this.piano.stl0[midi] : this.piano.stl2[midi]);
_style(this.piano.keys[midi], this.piano.locs[midi]);
}
return this;
};
Keys.prototype.enable = function() {
var k, midi;
for (k in this.keys) {
midi = this.keys[k];
this.piano.keys[midi]._active = true;
_style(this.piano.keys[midi], this.piano.playing[midi] ? this.piano.stl1[midi] : this.piano.stl0[midi]);
_style(this.piano.keys[midi], this.piano.locs[midi]);
}
return this;
};
Keys.prototype.disable = function() {
var k, midi;
for (k in this.keys) {
midi = this.keys[k];
this.piano.keys[midi]._active = false;
_style(this.piano.keys[midi], this.piano.playing[midi] ? this.piano.stl1[midi] : this.piano.stl2[midi]);
_style(this.piano.keys[midi], this.piano.locs[midi]);
}
return this;
};
function KbdEngine() {}
KbdEngine.prototype._info = function(name) {
return {
type: 'html/javascript',
name: _name(name, 'Kbd'),
manufacturer: 'virtual',
version: _version
};
};
KbdEngine.prototype._openIn = function(port, name) {
var piano = new Piano(this._arg);
piano.send = function() { port.send.apply(port, arguments); };
piano.connect = function() { port.connect.apply(port, arguments); };
piano.create();
if (piano.mpe) {
if (!port._orig._mpe) port._orig._mpe = JZZ.MPE();
port._orig._mpe.setup(piano.mpe[0], piano.mpe[1]);
piano.noteOn = function(note) {
var msg = JZZ.MIDI(0x90 + this.chan, note, 127);
msg._mpe = note;
port._emit(port._filter(msg));
};
piano.noteOff = function(note) {
var msg = JZZ.MIDI(0x80 + this.chan, note, 127);
msg._mpe = note;
port._emit(port._filter(msg));
};
}
else {
piano.noteOn = function(note) { port._emit(JZZ.MIDI(0x90 + this.chan, note, 127)); };
piano.noteOff = function(note) { port._emit(JZZ.MIDI(0x80 + this.chan, note, 127)); };
}
piano.emit = function(msg) { port._emit(port._filter(msg)); };
port._info = this._info(name);
port._receive = function(msg) { piano.forward(msg); };
port._close = function() { piano._close(); };
port.settings = function() { return piano.settings(); };
port.getKey = function(note) { return piano.getKey(note); };
port.getKeys = function(a, b) { return piano.getKeys(a, b); };
port.getWhiteKeys = function(a, b) { return piano.getWhiteKeys(a, b); };
port.getBlackKeys = function(a, b) { return piano.getBlackKeys(a, b); };
port.channel = function(x) { return piano.channel(x); };
port.clear = function() { return piano.clear(); };
port._resume();
};
JZZ.input.Kbd = function() {
var name, arg;
if (arguments.length == 1) {
if (typeof arguments[0] === 'string') name = arguments[0];
else arg = arguments[0];
}
else { name = arguments[0]; arg = arguments[1];}
var _KbdEngine = new KbdEngine();
_KbdEngine._arg = arg;
return JZZ.lib.openMidiIn(name, _KbdEngine);
};
JZZ.input.Kbd.version = function() { return _version; };
JZZ.input.Kbd.register = function() {
var name, arg;
if (arguments.length == 1) {
if (typeof arguments[0] === 'string') name = arguments[0];
else arg = arguments[0];
}
else { name = arguments[0]; arg = arguments[1];}
var _KbdEngine = new KbdEngine();
_KbdEngine._arg = arg;
return JZZ.lib.registerMidiIn(name, _KbdEngine);
};
////////////////////////////////////////////////////////////////////////
var _innerStyle = {margin:0, padding:0, width:'100%', height:'100%'};
function _Data(d) {
this.base = 0.5;
this.val = 0.5;
this.msb = 0;
this.lsb = 0;
this.chan = 0;
if (d instanceof Array) {
if (d.length != 1 && d.length != 2) return;
if (d.length == 2) {
if (d[1] != parseInt(d[1]) || d[1] < 1 || d[1] > 0x7f) return;
this.msb = d[0];
if (d[1] != d[0]) this.lsb = d[1];
}
else this.msb = d[0];
}
else if (d == parseInt(d)) {
if (d < 1 || d > 0x7f) return;
this.msb = d;
}
else {
var z = {
mod:[0x01, 0x21], breath:[0x02, 0x22], foot:[0x04, 0x24], portamento:[0x05, 0x25], volume:[0x07, 0x27],
balance:[0x08, 0x28], pan:[0x0a, 0x2a], expression:[0x0b, 0x2b], effect1:[0x0c, 0x2c], effect2:[0x0d, 0x2d]
}[d];
if (z) {
this.msb = z[0];
this.lsb = z[1];
}
}
if (this.msb && this.msb != 7 && this.msb != 8 && this.msb != 0xa) this.base = 0;
this.val = -1;
this.setValue(this.base);
}
_Data.prototype.setBase = function(x) {
x = parseFloat(x);
if (!isNaN(x) && isFinite(x) && x >= 0 && x <= 1) this.base = x;
};
_Data.prototype.setValue = function(x) {
x = parseFloat(x);
if (isNaN(x) || !isFinite(x) || x < 0 || x > 1 || x == this.val) return;
this.val = x;
this.num = Math.round(x * (this.lsb || !this.msb ? 0x3fff : 0x7f));
return true;
};
_Data.prototype.emit = function(out) {
if (!this.msb) {
out.emit([0xe0 + this.chan, this.num & 0x7f, this.num >> 7]);
}
else if (!this.lsb) {
out.emit([0xb0 + this.chan, this.msb, this.num]);
}
else {
out.emit([0xb0 + this.chan, this.msb, this.num >> 7]);
out.emit([0xb0 + this.chan, this.lsb, this.num & 0x7f]);
}
};
_Data.prototype.read = function(msg) {
if (!this.msb && msg[0] == 0xe0 + this.chan && msg[1] == parseInt(msg[1]) && msg[2] == parseInt(msg[2])) {
this.num = (msg[2] << 7) | (msg[1] & 0x7f);
this.val = this.num / 0x3fff;
return true;
}
else if (this.msb && msg[0] == 0xb0 + this.chan && msg[2] == parseInt(msg[2])) {
if (msg[1] == this.msb) {
if (this.lsb) {
this.num = (msg[2] << 7) | (this.num & 0x7f);
this.val = this.num / 0x3fff;
}
else {
this.num = msg[2] & 0x7f;
this.val = this.num / 0x7f;
}
return true;
}
if (msg[1] == this.lsb) {
this.num = (this.num & 0x3f80) | (msg[2] & 0x7f);
this.val = this.num / 0x3fff;
return true;
}
}
};
////////////////////////////////////////////////////////////////////////////
function _Span(ctrl, span, inner, stl, stl0, stl1) {
this.ctrl = ctrl;
this.span = span;
this.inner = inner;
this.stl = stl;
this.stl0 = stl0;
this.stl1 = stl1;
}
_Span.prototype.setInnerHTML = function(html) {
this.inner.innerHTML = html;
return this;
};
_Span.prototype.setStyle = function(s0, s1) {
if (typeof s1 == 'undefined') s1 = s0;
var k;
for(k in s0) this.stl0[k] = s0[k];
for(k in s1) this.stl1[k] = s1[k];
_style(this.span, this.ctrl.isSelected() ? this.stl1 : this.stl0);
_style(this.span, this.stl);
return this;
};
////////////////////////////////////////////////////////////////////////////
function _Knob() {}
function _initKnob(arg, common) {
this.bins = [];
this.params = {0:{}};
if (typeof arg == 'undefined') arg = {};
if (typeof common == 'undefined') common = {};
this.chan = _channelMap[arg.chan];
if (typeof this.chan == 'undefined') this.chan = 0;
var key;
for (key in arg) {
if (key == parseInt(key)) this.params[key] = _copy(arg[key]);
else {
if (key == 'chan') continue;
common[key] = arg[key];
}
}
for (key in this.params) {
this.bins.push(key);
for (var k in common) {
if ((k == 'from' || k == 'to') && typeof _keyNum(this.params[key][k]) == 'undefined') this.params[key][k] = common[k];
if (!(k in this.params[key])) this.params[key][k] = common[k];
}
}
this.bins.sort(function(a, b) { return a - b; });
}
_Knob.prototype._close = function() {
if (this.at) this.at.innerHTML = '';
if (this.mouseUpHandler) window.removeEventListener("mouseup", this.mouseUpHandler);
};
_Knob.prototype.create = function() {
var bin = 0;
for (var i = 0; i < this.bins.length; i++) {
if (this.bins[i] <= window.innerWidth) bin = this.bins[i];
else break;
}
this.current = this.params[bin];
this.createCurrent();
};
_Knob.prototype.createCurrent = function() {
if (this.at) this.at.innerHTML = '';
if (typeof this.current.at == 'string') this.current.at = document.getElementById(this.current.at);
try { this.createAt(this.current.at); }
catch(e) {
if (!this.bottom) {
this.bottom = document.createElement('div');
document.body.appendChild(this.bottom);
}
this.createAt(this.bottom);
}
};
_Knob.prototype.onResize = function() {
var bin = 0;
for (var i = 0; i < this.bins.length; i++) {
if (this.bins[i] <= window.innerWidth) bin = this.bins[i];
else break;
}
if (this.current == this.params[bin]) return;
this.current = this.params[bin];
this.createCurrent();
};
_Knob.prototype.settings = function() { return _copy(this.current); };
_Knob.prototype.isSelected = function() { return typeof this.dragX != 'undefined'; };
_Knob.prototype.restyle = function() {
for (var i in this.spans) this.spans[i].setStyle();
};
_Knob.prototype.onMouseDown = function(e) {
if (typeof this.dragX != 'undefined') return;
this.dragX = e.clientX;
this.dragY = e.clientY;
this.mouseMove = _MouseMove(this);
this.mouseUp = _MouseUp(this);
window.addEventListener('mousemove', this.mouseMove);
window.addEventListener('mouseup', this.mouseUp);
this.restyle();
};
_Knob.prototype.onMouseMove = function(e) {
if (typeof this.dragX != 'undefined') this.onMove(e.clientX, e.clientY);
};
_Knob.prototype.onMouseUp = function() {
// mouse or touch ended
};
_Knob.prototype.onTouchStart = function(e) {
e.preventDefault();
if (typeof this.dragX != 'undefined') return;
this.touch = e.targetTouches[0].identifier;
this.dragX = e.targetTouches[0].clientX;
this.dragY = e.targetTouches[0].clientY;
this.restyle();
};
_Knob.prototype.onTouchMove = function(e) {
e.preventDefault();
if (typeof this.dragX == 'undefined' || typeof this.touch == 'undefined') return;
for (var i in e.targetTouches) if (e.targetTouches[0].identifier == this.touch) {
this.onMove(e.targetTouches[i].clientX, e.targetTouches[i].clientY);
return;
}
};
_Knob.prototype.onTouchEnd = function(e) {
e.preventDefault();
this.touch = undefined;
this.dragX = undefined;
this.restyle();
this.onMouseUp(e);
};
function _MouseDown(x) { return function(e) { _firefoxBug = e.buttons; if (_lftBtnDn(e)) x.onMouseDown(e); }; }
function _MouseMove(x) { return function(e) { _firefoxBug = e.buttons; x.onMouseMove(e); }; }
function _MouseUp(x) { return function(e) {
e = _fixBtnUp(e);
if (_lftBtnUp(e)) {
window.removeEventListener("mousemove", x.mouseMove);
window.removeEventListener("mouseup", x.mouseUp);
x.dragX = undefined;
x.restyle();
x.onMouseUp(e);
}
}; }
function _TouchStart(x) { return function(e) { x.onTouchStart(e); }; }
function _TouchMove(x) { return function(e) { x.onTouchMove(e); }; }
function _TouchEnd(x) { return function(e) { x.onTouchEnd(e); }; }
function _IgnoreTouch(e) { e.preventDefault(); }
////////////////////////////////////////////////////////////////////////////
function Slider(arg) {
_initKnob.call(this, arg, {pos:'N', rw:2, rh:128, kw:24, kh:16});
}
Slider.prototype = new _Knob();
Slider.prototype.channel = function(c) {
var chan = _channelMap[c];
if (typeof chan != 'undefined' && chan != this.chan) {
this.chan = chan;
this.data.chan = chan;
this.setValue(this.data.base);
}
return this.chan;
};
Slider.prototype.createAt = function(at) {
at.innerHTML = '';
var bh = parseInt(this.current.bh);
var bw = parseInt(this.current.bw);
var rh = parseInt(this.current.rh); if (!rh) rh = 128;
this.rh = rh;
var rw = parseInt(this.current.rw); if (!rw) rw = 2;
var kh = parseInt(this.current.kh); if (!kh) kh = 24;
var kw = parseInt(this.current.kw); if (!kw) kw = 16;
var pos = this.current.pos.toUpperCase();
this.pos = pos;
if (!this.data) {
this.data = new _Data(this.current.data);
this.data.chan = this.chan;
this.data.setBase(this.current.base);
this.data.setValue(this.current.val);
}
this.dx = - (kw / 2);
this.dy = - (kh / 2 + 1);
if (!bh) bh = kh + rh + 2;
if (!bw) bw = (kw > rw ? kw : rw) + 2;
this.stlB = { display:'inline-block', position:'relative', margin:'0', padding:'0', userSelect:'none', KhtmlUserSelect:'none', MozUserSelect:'none', MsUserSelect:'none', OUserSelect:'none', WebkitUserSelect:'none', cursor:'default' };
this.stlB0 = { borderStyle:'none' };
this.stlB1 = { borderStyle:'none' };
this.stlR = { display:'inline-block', position:'absolute', margin:'0', padding:'0', borderStyle:'solid', borderWidth:'1px' };
this.stlR0 = { backgroundColor:'#aaa' };
this.stlR1 = { backgroundColor:'#bbb' };
this.stlK = { display:'inline-block', position:'absolute', margin:'0', padding:'0', borderStyle:'solid', borderWidth:'1px' };
this.stlK0 = { backgroundColor:'#ddd' };
this.stlK1 = { backgroundColor:'#eee' };
if (pos == 'E' || pos == 'W') {
this.stlB.width = bh + 'px';
this.stlB.height = bw + 'px';
this.stlR.width = rh + 'px';
this.stlR.height = rw + 'px';
this.stlR.left = ((bh - rh) / 2 - 1) + 'px';
this.stlR.top = ((bw - rw) / 2 - 1) + 'px';
this.stlK.width = kh + 'px';
this.stlK.height = kw + 'px';
this.stlK.top = this.dx + 'px';
}
else {
this.stlB.width = bw + 'px';
this.stlB.height = bh + 'px';
this.stlR.width = rw + 'px';
this.stlR.height = rh + 'px';
this.stlR.top = ((bh - rh) / 2 - 1) + 'px';
this.stlR.left = ((bw - rw) / 2 - 1) + 'px';
this.stlK.width = kw + 'px';
this.stlK.height = kh + 'px';
this.stlK.left = this.dx + 'px';
}
var box = document.createElement('span');
this.box = box;
var box_ = document.createElement('span');
_style(box_, _innerStyle);
this.boxSpan = new _Span(this, box, box_, this.stlB, this.stlB0, this.stlB1);
var range = document.createElement('span');
this.range = range;
var range_ = document.createElement('span');
_style(range_, _innerStyle);
this.rangeSpan = new _Span(this, range, range_, this.stlR, this.stlR0, this.stlR1);
var knob = document.createElement('span');
this.knob = knob;
this.knobSpan = new _Span(this, knob, knob, this.stlK, this.stlK0, this.stlK1);
this.spans = [this.boxSpan, this.rangeSpan, this.knobSpan];
var active = typeof this.current.active == 'undefined' || this.current.active;
if (active) {
box.addEventListener("touchstart", _IgnoreTouch);
knob.addEventListener("mousedown", _MouseDown(this));
knob.addEventListener("touchstart", _TouchStart(this));
knob.addEventListener("touchmove", _TouchMove(this));
knob.addEventListener("touchend", _TouchEnd(this));
knob.addEventListener("touchcancel", _TouchEnd(this));
}
if (this.current.onCreate) this.current.onCreate.apply(this);
range.appendChild(range_);
range.appendChild(knob);
box.appendChild(box_);
box.appendChild(range);
box.ondragstart = _returnFalse;
box.onselectstart = _returnFalse;
at.appendChild(box);
if (!this.at && this.bins.length > 1) {
var self = this;
this.resize = function() { self.onResize(); };
window.addEventListener('resize', this.resize);
}
this.current.at = at;
this.at = at;
this.setValue();
_style(this.box, typeof this.dragX == 'undefined' ? this.stlB0 : this.stlB1);
_style(this.box, this.stlB);
_style(this.range, typeof this.dragX == 'undefined' ? this.stlR0 : this.stlR1);
_style(this.range, this.stlR);
_style(this.knob, typeof this.dragX == 'undefined' ? this.stlK0 : this.stlK1);
_style(this.knob, this.stlK);
};
Slider.prototype.getBox = function() { return this.boxSpan; };
Slider.prototype.getRange = function() { return this.rangeSpan; };
Slider.prototype.getKnob = function() { return this.knobSpan; };
Slider.prototype.setValue = function(x) {
if (typeof x == 'undefined') x = this.data.val;
else if (!this.data.setValue(x)) return;
x = this.data.val;
if (this.pos == 'N' || this.pos == 'W') x = 1.0 - x;
x *= this.rh;
this.coord = x;
x += this.dy;
if (this.pos == 'N' || this.pos == 'S') {
this.stlK.top = x + 'px';
this.knob.style.top = x + 'px';
}
else {
this.stlK.left = x + 'px';
this.knob.style.left = x + 'px';
}
};
Slider.prototype.onMove = function(x, y) {
var coord;
if (this.pos == 'N' || this.pos == 'S') coord = this.coord + y - this.dragY;
else coord = this.coord + x - this.dragX;
if (coord < 0) coord = 0;
if (coord > this.rh) coord = this.rh;
this.move(coord);
};
Slider.prototype.move = function(coord) {
if (this.coord == coord) return;
if (this.pos == 'N' || this.pos == 'S') {
this.knob.style.top = coord + this.dy + 'px';
this.stlK.top = this.knob.style.top;
this.dragY += coord - this.coord;
}
else {
this.knob.style.left = coord + this.dy + 'px';
this.stlK.left = this.knob.style.left;
this.dragX += coord - this.coord;
}
var x = coord / this.rh;
if (this.pos == 'N' || this.pos == 'W') x = 1.0 - x;
if (this.data.setValue(x)) this.data.emit(this);
this.coord = coord;
};
Slider.prototype.forward = function(msg) {
this.emit(msg);
if (this.data.read(msg)) {
this.setValue();
}
};
////////////////////////////////////////////////////////////////////////////
function Pad(arg) {
_initKnob.call(this, arg, {pos:'N', rw:128, rh:128, kw:24, kh:16});
}
Pad.prototype = new _Knob();
Pad.prototype.channel = function(c) {
var chan = _channelMap[c];
if (typeof chan != 'undefined' && chan != this.chan) {
this.chan = chan;
this.dataX.chan = chan;
this.dataY.chan = chan;
this.setValue(this.dataX.base, this.dataY.base);
}
return this.chan;
};
Pad.prototype.createAt = function(at) {
at.innerHTML = '';
var bh = parseInt(this.current.bh);
var bw = parseInt(this.current.bw);
var rh = parseInt(this.current.rh); if (!rh) rh = 128;
this.rh = rh;
var rw = parseInt(this.current.rw); if (!rw) rw = 128;
this.rw = rw;
var kh = parseInt(this.current.kh); if (!kh) kh = 24;
var kw = parseInt(this.current.kw); if (!kw) kw = 16;
var pos = this.current.pos.toUpperCase();
this.pos = pos;
if (!this.dataX) {
this.dataX = new _Data(this.current.dataX);
this.dataY = new _Data(this.current.dataY);
if (typeof this.current.dataX == 'undefined' && typeof this.current.dataY != 'undefined' && !this.dataY.msb) this.dataX = new _Data('mod');
if (typeof this.current.dataY == 'undefined' && !this.dataX.msb) this.dataY = new _Data('mod');
this.dataX.chan = this.chan;
this.dataY.chan = this.chan;
this.dataX.setBase(this.current.baseX);
this.dataY.setBase(this.current.baseY);
this.dataX.setValue(this.current.valX);
this.dataY.setValue(this.current.valY);
}
this.dx = - (kw / 2 + 1);
this.dy = - (kh / 2 + 1);
if (!bh) bh = kh + rh + 2;
if (!bw) bw = kw + rw + 2;
this.stlB = { display:'inline-block', position:'relative', margin:'0', padding:'0', userSelect:'none', KhtmlUserSelect:'none', MozUserSelect:'none', MsUserSelect:'none', OUserSelect:'none', WebkitUserSelect:'none', cursor:'default' };
this.stlB0 = { borderStyle:'none' };
this.stlB1 = { borderStyle:'none' };
this.stlR = { display:'inline-block', position:'absolute', margin:'0', padding:'0', borderStyle:'solid', borderWidth:'1px' };
this.stlR0 = { backgroundColor:'#aaa' };
this.stlR1 = { backgroundColor:'#bbb' };
this.stlK = { display:'inline-block', position:'absolute', margin:'0', padding:'0', borderStyle:'solid', borderWidth:'1px' };
this.stlK0 = { backgroundColor:'#ddd' };
this.stlK1 = { backgroundColor:'#eee' };
if (pos == 'E' || pos == 'W') {
this.stlB.width = bh + 'px';
this.stlB.height = bw + 'px';
this.stlR.width = rh + 'px';
this.stlR.height = rw + 'px';
this.stlR.left = ((bh - rh) / 2 - 1) + 'px';
this.stlR.top = ((bw - rw) / 2 - 1) + 'px';
this.stlK.width = kh + 'px';
this.stlK.height = kw + 'px';
this.stlK.top = this.dx + 'px';
}
else {
this.stlB.width = bw + 'px';
this.stlB.height = bh + 'px';
this.stlR.width = rw + 'px';
this.stlR.height = rh + 'px';
this.stlR.top = ((bh - rh) / 2 - 1) + 'px';
this.stlR.left = ((bw - rw) / 2 - 1) + 'px';
this.stlK.width = kw + 'px';
this.stlK.height = kh + 'px';
this.stlK.left = this.dx + 'px';
}
var box = document.createElement('span');
this.box = box;
var box_ = document.createElement('span');
_style(box_, _innerStyle);
this.boxSpan = new _Span(this, box, box_, this.stlB, this.stlB0, this.stlB1);
var range = document.createElement('span');
this.range = range;
var range_ = document.createElement('span');
_style(range_, _innerStyle);
this.rangeSpan = new _Span(this, range, range_, this.stlR, this.stlR0, this.stlR1);
var knob = document.createElement('span');
this.knob = knob;
this.knobSpan = new _Span(this, knob, knob, this.stlK, this.stlK0, this.stlK1);
this.spans = [this.boxSpan, this.rangeSpan, this.knobSpan];
var active = typeof this.current.active == 'undefined' || this.current.active;
if (active) {
box.addEventListener("touchstart", _IgnoreTouch);
knob.addEventListener("mousedown", _MouseDown(this));
knob.addEventListener("touchstart", _TouchStart(this));
knob.addEventListener("touchmove", _TouchMove(this));
knob.addEventListener("touchend", _TouchEnd(this));
knob.addEventListener("touchcancel", _TouchEnd(this));
}
if (this.current.onCreate) this.current.onCr