wam-community
Version:
A collection of prebuilt Web Audio Modules ready for use
1,507 lines (1,494 loc) • 55 kB
JavaScript
/* *
*
* WebAudio-Controls is based on
* webaudio-knob by Eiji Kitamura http://google.com/+agektmr
* webaudio-slider by RYoya Kawai https://plus.google.com/108242669191458983485/posts
* webaudio-switch by Keisuke Ai http://d.hatena.ne.jp/aike/
* Integrated and enhanced by g200kg http://www.g200kg.com/
*
* Copyright 2013 Eiji Kitamura / Ryoya KAWAI / Keisuke Ai / g200kg(Tatsuya Shinyagaito)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* */
if (window.customElements) {
let styles = document.createElement("style");
styles.innerHTML =
`#webaudioctrl-context-menu {
display: none;
position: absolute;
z-index: 10;
padding: 0;
width: 100px;
color:#eee;
background-color: #268;
border: solid 1px #888;
box-shadow: 1px 1px 2px #888;
font-family: sans-serif;
font-size: 11px;
line-height:1.7em;
text-align:center;
cursor:pointer;
color:#fff;
list-style: none;
}
#webaudioctrl-context-menu.active {
display: block;
}
.webaudioctrl-context-menu__item {
display: block;
margin: 0;
padding: 0;
color: #000;
background-color:#eee;
text-decoration: none;
}
.webaudioctrl-context-menu__title{
font-weight:bold;
}
.webaudioctrl-context-menu__item:last-child {
margin-bottom: 0;
}
.webaudioctrl-context-menu__item:hover {
background-color: #b8b8b8;
}
`;
document.head.appendChild(styles);
let midimenu = document.createElement("ul");
midimenu.id = "webaudioctrl-context-menu";
midimenu.innerHTML =
`<li class="webaudioctrl-context-menu__title">MIDI Learn</li>
<li class="webaudioctrl-context-menu__item" id="webaudioctrl-context-menu-learn" onclick="webAudioControlsMidiManager.contextMenuLearn()">Learn</li>
<li class="webaudioctrl-context-menu__item" onclick="webAudioControlsMidiManager.contextMenuClear()">Clear</li>
<li class="webaudioctrl-context-menu__item" onclick="webAudioControlsMidiManager.contextMenuClose()">Close</li>
`;
let opt = {
useMidi: 0,
midilearn: 0,
mididump: 0,
outline: 0,
knobSrc: null,
knobSprites: 0,
knobWidth: 0,
knobHeight: 0,
knobDiameter: 64,
knobColors: "#fff;#000;#000",
sliderSrc: null,
sliderKnobsrc: null,
sliderWidth: 0,
sliderHeight: 0,
sliderKnobwidth: 0,
sliderKnobheight: 0,
sliderDitchlength: 0,
sliderColors: "#bbb;#444;#fff",
switchWidth: 0,
switchHeight: 0,
switchDiameter: 24,
switchColors: "#e00;#000;#fcc",
paramWidth: 32,
paramHeight: 16,
paramColors: "#fff;#000",
};
if (window.WebAudioControlsOptions)
Object.assign(opt, window.WebAudioControlsOptions);
class WebAudioControlsWidget extends HTMLElement {
constructor() {
super();
this.addEventListener("keydown", this.keydown);
this.addEventListener("mousedown", this.pointerdown, { passive: false });
this.addEventListener("touchstart", this.pointerdown, { passive: false });
this.addEventListener("wheel", this.wheel, { passive: true });
this.addEventListener("mouseover", this.pointerover);
this.addEventListener("mouseout", this.pointerout);
this.addEventListener("contextmenu", this.contextMenu);
this.hover = this.drag = 0;
document.body.appendChild(midimenu);
this.basestyle = `
.webaudioctrl-tooltip{
display:inline-block;
position:absolute;
margin:0 -1000px;
z-index: 999;
background:#eee;
color:#000;
border:1px solid #666;
border-radius:4px;
padding:5px 10px;
text-align:center;
left:0; top:0;
font-size:11px;
opacity:0;
visibility:hidden;
}
.webaudioctrl-tooltip:before{
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -8px;
border: 8px solid transparent;
border-top: 8px solid #666;
}
.webaudioctrl-tooltip:after{
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -6px;
border: 6px solid transparent;
border-top: 6px solid #eee;
}
`;
}
sendEvent(ev) {
let event;
event = document.createEvent("HTMLEvents");
event.initEvent(ev, false, true);
this.dispatchEvent(event);
}
getAttr(n, def) {
let v = this.getAttribute(n);
if (v == "" || v == null) return def;
switch (typeof (def)) {
case "number":
if (v == "true") return 1;
v = +v;
if (isNaN(v)) return 0;
return v;
}
return v;
}
showtip(d) {
function numformat(s, x) {
let i = s.indexOf("%");
let c = [0, 0], type = 0, m = 0, r = "", j = i + 1;
for (; j < s.length; ++j) {
if ("dfxXs".indexOf(s[j]) >= 0) {
type = s[j];
break;
}
if (s[j] == ".")
m = 1;
else
c[m] = c[m] * 10 + parseInt(s[j]);
}
switch (type) {
case "x": r = (x | 0).toString(16); break;
case "X": r = (x | 0).toString(16).toUpperCase(); break;
case "d": r = (x | 0).toString(); break;
case "f": r = x.toFixed(c[1]); break;
case "s": r = x.toString(); break;
}
if (c[0] > 0)
r = (" " + r).slice(-c[0]);
r = s.replace(/%.*[xXdfs]/, r);
return r;
}
let s = this.tooltip;
if (this.drag || this.hover) {
if (this.valuetip) {
if (s == null)
s = `%.${this.digits}f`;
else if (s.indexOf("%") < 0)
s += ` : %.${this.digits}f`;
}
if (s) {
this.ttframe.innerHTML = numformat(s, this.convValue);
this.ttframe.style.display = "inline-block";
this.ttframe.style.width = "auto";
this.ttframe.style.height = "auto";
this.ttframe.style.transition = "opacity 0.5s " + d + "s,visibility 0.5s " + d + "s";
this.ttframe.style.opacity = 0.9;
this.ttframe.style.visibility = "visible";
let rc = this.getBoundingClientRect(), rc2 = this.ttframe.getBoundingClientRect(), rc3 = document.documentElement.getBoundingClientRect();
this.ttframe.style.left = ((rc.width - rc2.width) * 0.5 + 1000) + "px";
this.ttframe.style.top = (-rc2.height - 8) + "px";
return;
}
}
this.ttframe.style.transition = "opacity 0.1s " + d + "s,visibility 0.1s " + d + "s";
this.ttframe.style.opacity = 0;
this.ttframe.style.visibility = "hidden";
}
pointerover(e) {
this.hover = 1;
this.showtip(0.6);
}
pointerout(e) {
this.hover = 0;
this.showtip(0);
}
contextMenu(e) {
if (window.webAudioControlsMidiManager && this.midilearn) {
webAudioControlsMidiManager.contextMenuOpen(e, this);
}
e.preventDefault();
e.stopPropagation();
}
setMidiController(channel, cc) {
if (this.listeningToThisMidiController(channel, cc)) return;
this.midiController = { 'channel': channel, 'cc': cc };
console.log("Added mapping for channel=" + channel + " cc=" + cc + " tooltip=" + this.tooltip);
}
listeningToThisMidiController(channel, cc) {
const c = this.midiController;
if ((c.channel === channel || c.channel < 0) && c.cc === cc)
return true;
return false;
}
processMidiEvent(event) {
const channel = event.data[0] & 0xf;
const controlNumber = event.data[1];
if (this.midiMode == 'learn') {
this.setMidiController(channel, controlNumber);
webAudioControlsMidiManager.contextMenuClose();
this.midiMode = 'normal';
}
if (this.listeningToThisMidiController(channel, controlNumber)) {
if (this.tagName == "WEBAUDIO-SWITCH") {
switch (this.type) {
case "toggle":
if (event.data[2] >= 64)
this.setValue(1 - this.value, true);
break;
case "kick":
this.setValue(event.data[2] >= 64 ? 1 : 0);
break;
case "radio":
let els = document.querySelectorAll("webaudio-switch[type='radio'][group='" + this.group + "']");
for (let i = 0; i < els.length; ++i) {
if (els[i] == this)
els[i].setValue(1);
else
els[i].setValue(0);
}
break;
}
}
else {
const val = this.min + (this.max - this.min) * event.data[2] / 127;
this.setValue(val, true);
}
}
}
}
try {
customElements.define("webaudio-knob", class WebAudioKnob extends WebAudioControlsWidget {
constructor() {
super();
}
get src() { return this._src; }
set src(v) { this._src = v; this.setupImage(); }
get value() { return this._value; }
set value(v) { this._value = +v; this.redraw(); }
get min() { return this._min; }
set min(v) { this._min = +v; this.redraw(); }
get max() { return this._max; }
set max(v) { this._max = +v; this.redraw(); }
get step() { return this._step; }
set step(v) { this._step = +v; this.redraw(); }
get sprites() { return this._sprites; }
set sprites(v) { this._sprites = +v; this.setupImage(); }
get width() { return this._width; }
set width(v) { this._width = +v; this.setupImage(); }
get height() { return this._height; }
set height(v) { this._height = +v; this.setupImage(); }
get diameter() { return this._diameter; }
set diameter(v) { this._diameter = +v; this.setupImage(); }
get colors() { return this._colors; }
set colors(v) { this._colors = v; this.setupImage(); }
connectedCallback() {
let root;
// if(this.attachShadow)
// root=this.attachShadow({mode: 'open'});
// else
root = this;
root.innerHTML =
`<style>
${this.basestyle}
webaudio-knob{
display:inline-block;
position:relative;
margin:0;
padding:0;
cursor:pointer;
font-family: sans-serif;
font-size: 11px;
}
.webaudio-knob-body{
display:inline-block;
position:relative;
z-index:1;
margin:0;
padding:0;
}
</style>
<div class='webaudio-knob-body' tabindex='1' touch-action='none'></div><div class='webaudioctrl-tooltip'></div>
`;
this.elem = root.childNodes[2];
this.ttframe = root.childNodes[3];
this.enable = this.getAttr("enable", 1);
this._src = this.getAttr("src", opt.knobSrc);
this._value = this.getAttr("value", 0);
this.defvalue = this.getAttr("defvalue", 0);
this._min = this.getAttr("min", 0);
this._max = this.getAttr("max", 100);
this._step = this.getAttr("step", 1);
this._sprites = this.getAttr("sprites", opt.knobSprites);
this._width = this.getAttr("width", opt.knobWidth);
this._height = this.getAttr("height", opt.knobHeight);
this._diameter = this.getAttr("diameter", opt.knobDiameter);
this._colors = this.getAttr("colors", opt.knobColors);
this.outline = this.getAttr("outline", opt.outline);
this.sensitivity = this.getAttr("sensitivity", 1);
this.valuetip = this.getAttr("valuetip", 1);
this.tooltip = this.getAttr("tooltip", null);
this.conv = this.getAttr("conv", null);
if (this.conv)
this.convValue = eval(this.conv)(this._value);
else
this.convValue = this._value;
this.midilearn = this.getAttr("midilearn", opt.midilearn);
this.midicc = this.getAttr("midicc", null);
this.midiController = {};
this.midiMode = "normal";
if (this.midicc) {
let ch = parseInt(this.midicc.substring(0, this.midicc.lastIndexOf("."))) - 1;
let cc = parseInt(this.midicc.substring(this.midicc.lastIndexOf(".") + 1));
this.setMidiController(ch, cc);
}
this.setupImage();
this.digits = 0;
this.coltab = ["#e00", "#000", "#000"];
if (window.webAudioControlsMidiManager)
// window.webAudioControlsMidiManager.updateWidgets();
window.webAudioControlsMidiManager.addWidget(this);
}
disconnectedCallback() { }
setupImage() {
this.kw = this.width || this.diameter;
this.kh = this.height || this.diameter;
if (!this.src) {
if (this.colors)
this.coltab = this.colors.split(";");
if (!this.coltab)
this.coltab = ["#e00", "#000", "#000"];
let svg =
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="6464" preserveAspectRatio="none">
<radialGradient id="gr" cx="30%" cy="30%"><stop offset="0%" stop-color="${this.coltab[2]}"/><stop offset="100%" stop-color="${this.coltab[1]}"/></radialGradient>
<defs><circle id="B" cx="32" cy="32" r="30" fill="url(#gr)"/></defs>
<defs><line id="K" x1="32" y1="28" x2="32" y2="7" stroke-linecap="round" stroke-width="6" stroke="${this.coltab[0]}"/></defs>`;
for (let i = 0; i < 101; ++i) {
svg += `<use xlink:href="#B" y="${64 * i}"/>`;
svg += `<use xlink:href="#K" y="${64 * i}" transform="rotate(${(-135 + 270 * i / 101).toFixed(2)},32,${64 * i + 32})"/>`;
}
svg += "</svg>";
this.elem.style.backgroundImage = "url(data:image/svg+xml;base64," + btoa(svg) + ")";
// this.elem.style.backgroundSize = "100% 10100%";
this.elem.style.backgroundSize = `${this.kw}px ${this.kh * 101}px`;
}
else {
this.elem.style.backgroundImage = "url(" + (this.src) + ")";
if (!this.sprites)
this.elem.style.backgroundSize = "100% 100%";
else {
// this.elem.style.backgroundSize = `100% ${(this.sprites+1)*100}%`;
this.elem.style.backgroundSize = `${this.kw}px ${this.kh * (this.sprites + 1)}px`;
}
}
this.elem.style.outline = this.outline ? "" : "none";
this.elem.style.width = this.kw + "px";
this.elem.style.height = this.kh + "px";
this.redraw();
}
redraw() {
if (!this.isConnected) return;
this.digits = 0;
if (this.step && this.step < 1) {
for (let n = this.step; n < 1; n *= 10)
++this.digits;
}
if (this.value < this.min) {
this.value = this.min;
return;
}
if (this.value > this.max) {
this.value = this.max;
return;
}
let range = this.max - this.min;
let style = this.elem.style;
let sp = this.src ? this.sprites : 100;
if (sp >= 1) {
let offset = ((sp * (this.value - this.min) / range) | 0);
style.backgroundPosition = "0px " + (-offset * this.kh) + "px";
style.transform = 'rotate(0deg)';
} else {
let deg = 270 * ((this.value - this.min) / range - 0.5);
style.backgroundPosition = "0px 0px";
style.transform = 'rotate(' + deg + 'deg)';
}
}
_setValue(v) {
if (this.step)
v = (Math.round((v - this.min) / this.step)) * this.step + this.min;
this._value = Math.min(this.max, Math.max(this.min, v));
if (this._value != this.oldvalue) {
this.oldvalue = this._value;
if (this.conv)
this.convValue = eval(this.conv)(this._value);
else
this.convValue = this._value;
this.redraw();
this.showtip(0);
return 1;
}
return 0;
}
setValue(v, f) {
if (this._setValue(v) && f)
this.sendEvent("input"), this.sendEvent("change");
}
wheel(e) {
let delta = (this.max - this.min) * 0.01;
delta = e.deltaY > 0 ? -delta : delta;
if (!e.shiftKey)
delta *= 5;
if (Math.abs(delta) < this.step)
delta = (delta > 0) ? +this.step : -this.step;
this.setValue(+this.value + delta, true);
e.preventDefault();
e.stopPropagation();
}
pointerdown(ev) {
if (!this.enable)
return;
let e = ev;
if (ev.touches) {
e = ev.changedTouches[0];
this.identifier = e.identifier;
}
else {
if (e.buttons != 1 && e.button != 0)
return;
}
this.elem.focus();
this.drag = 1;
this.showtip(0);
let pointermove = (ev) => {
let e = ev;
if (ev.touches) {
for (let i = 0; i < ev.touches.length; ++i) {
if (ev.touches[i].identifier == this.identifier) {
e = ev.touches[i];
break;
}
}
}
if (this.lastShift !== e.shiftKey) {
this.lastShift = e.shiftKey;
this.startPosX = e.pageX;
this.startPosY = e.pageY;
this.startVal = this.value;
}
let offset = (this.startPosY - e.pageY - this.startPosX + e.pageX) * this.sensitivity;
this._setValue(this.min + ((((this.startVal + (this.max - this.min) * offset / ((e.shiftKey ? 4 : 1) * 128)) - this.min) / this.step) | 0) * this.step);
this.sendEvent("input");
if (e.preventDefault)
e.preventDefault();
if (e.stopPropagation)
e.stopPropagation();
return false;
}
let pointerup = (ev) => {
let e = ev;
if (ev.touches) {
for (let i = 0; ;) {
if (ev.changedTouches[i].identifier == this.identifier) {
break;
}
if (++i >= ev.changedTouches.length)
return;
}
}
this.drag = 0;
this.showtip(0);
this.startPosX = this.startPosY = null;
window.removeEventListener('mousemove', pointermove);
window.removeEventListener('touchmove', pointermove, { passive: false });
window.removeEventListener('mouseup', pointerup);
window.removeEventListener('touchend', pointerup);
window.removeEventListener('touchcancel', pointerup);
document.body.removeEventListener('touchstart', preventScroll, { passive: false });
this.sendEvent("change");
}
let preventScroll = (e) => {
e.preventDefault();
}
if (e.ctrlKey || e.metaKey)
this.setValue(this.defvalue, true);
else {
this.startPosX = e.pageX;
this.startPosY = e.pageY;
this.startVal = this.value;
window.addEventListener('mousemove', pointermove);
window.addEventListener('touchmove', pointermove, { passive: false });
}
window.addEventListener('mouseup', pointerup);
window.addEventListener('touchend', pointerup);
window.addEventListener('touchcancel', pointerup);
document.body.addEventListener('touchstart', preventScroll, { passive: false });
ev.preventDefault();
ev.stopPropagation();
return false;
}
});
} catch (error) {
//console.log("webaudio-knob already defined");
}
try {
customElements.define("webaudio-slider", class WebAudioSlider extends WebAudioControlsWidget {
constructor() {
super();
}
get src() { return this._src; }
set src(v) { this._src = v; this.setupImage(); }
get knobsrc() { return this._knobsrc; }
set knobsrc(v) { this._knobsrc = v; this.setupImage(); }
get value() { return this._value; }
set value(v) { this._value = +v; this.redraw(); }
get min() { return this._min; }
set min(v) { this._min = +v; this.redraw(); }
get max() { return this._max; }
set max(v) { this._max = +v; this.redraw(); }
get step() { return this._step; }
set step(v) { this._step = +v; this.redraw(); }
get sprites() { return this._sprites; }
set sprites(v) { this._sprites = +v; this.setupImage(); }
get direction() { return this._direction; }
set direction(v) { this._direction = +v; this.setupImage(); }
get width() { return this._width; }
set width(v) { this._width = +v; this.setupImage(); }
get height() { return this._height; }
set height(v) { this._height = +v; this.setupImage(); }
get knobwidth() { return this._knobwidth; }
set knobwidth(v) { this._knobwidth = +v; this.setupImage(); }
get knobheight() { return this._knobheight; }
set knobheight(v) { this._knobheight = +v; this.setupImage(); }
get ditchlength() { return this._ditchlength; }
set ditchlength(v) { this._ditchlength = +v; this.setupImage(); }
get colors() { return this._colors; }
set colors(v) { this._colors = v; this.setupImage(); }
connectedCallback() {
let root;
// if(this.attachShadow)
// root=this.attachShadow({mode: 'open'});
// else
root = this;
root.innerHTML =
`<style>
${this.basestyle}
webaudio-slider{
display:inline-block;
position:relative;
margin:0;
padding:0;
font-family: sans-serif;
font-size: 11px;
cursor:pointer;
}
.webaudio-slider-body{
display:inline-block;
position:relative;
margin:0;
padding:0;
}
.webaudio-slider-knob{
display:inline-block;
position:absolute;
margin:0;
padding:0;
}
</style>
<div class='webaudio-slider-body' tabindex='1' touch-action='none'><div class='webaudio-slider-knob' touch-action='none'></div></div><div class='webaudioctrl-tooltip'></div>
`;
this.elem = root.childNodes[2];
this.knob = this.elem.childNodes[0];
this.ttframe = root.childNodes[3];
this.enable = this.getAttr("enable", 1);
this._src = this.getAttr("src", opt.sliderSrc);
this._knobsrc = this.getAttr("knobsrc", opt.sliderKnobsrc);
this._value = this.getAttr("value", 0);
this.defvalue = this.getAttr("defvalue", 0);
this._min = this.getAttr("min", 0);
this._max = this.getAttr("max", 100);
this._step = this.getAttr("step", 1);
this._sprites = this.getAttr("sprites", 0);
this._direction = this.getAttr("direction", null);
this._width = this.getAttr("width", opt.sliderWidth);
this._height = this.getAttr("height", opt.sliderHeight);
if (this._direction == "horz") {
if (this._width == 0) this._width = 128;
if (this._height == 0) this._height = 24;
}
else {
if (this._width == 0) this._width = 24;
if (this._height == 0) this._height = 128;
}
this._knobwidth = this.getAttr("knobwidth", opt.sliderKnobwidth);
this._knobheight = this.getAttr("knbheight", opt.sliderKnobheight);
this._ditchlength = this.getAttr("ditchlength", opt.sliderDitchlength);
this._colors = this.getAttr("colors", opt.sliderColors);
this.outline = this.getAttr("outline", opt.outline);
this.sensitivity = this.getAttr("sensitivity", 1);
this.valuetip = this.getAttr("valuetip", 1);
this.tooltip = this.getAttr("tooltip", null);
this.conv = this.getAttr("conv", null);
if (this.conv)
this.convValue = eval(this.conv)(this._value);
else
this.convValue = this._value;
this.midilearn = this.getAttr("midilearn", opt.midilearn);
this.midicc = this.getAttr("midicc", null);
this.midiController = {};
this.midiMode = "normal";
if (this.midicc) {
let ch = parseInt(this.midicc.substring(0, this.midicc.lastIndexOf("."))) - 1;
let cc = parseInt(this.midicc.substring(this.midicc.lastIndexOf(".") + 1));
this.setMidiController(ch, cc);
}
this.setupImage();
this.digits = 0;
if (window.webAudioControlsMidiManager)
// window.webAudioControlsMidiManager.updateWidgets();
window.webAudioControlsMidiManager.addWidget(this);
this.elem.onclick = (e) => { e.stopPropagation() };
}
disconnectedCallback() { }
setupImage() {
this.coltab = this.colors.split(";");
this.dr = this.direction;
this.dlen = this.ditchlength;
if (!this.width) {
if (this.dr == "horz")
this.width = 128;
else
this.width = 24;
}
if (!this.height) {
if (this.dr == "horz")
this.height = 24;
else
this.height = 128;
}
if (!this.dr)
this.dr = (this.width <= this.height) ? "vert" : "horz";
if (this.dr == "vert") {
if (!this.dlen)
this.dlen = this.height - this.width;
}
else {
if (!this.dlen)
this.dlen = this.width - this.height;
}
this.knob.style.backgroundSize = "100% 100%";
this.elem.style.backgroundSize = "100% 100%";
this.elem.style.width = this.width + "px";
this.elem.style.height = this.height + "px";
this.kwidth = this.knobwidth || (this.dr == "horz" ? this.height : this.width);
this.kheight = this.knobheight || (this.dr == "horz" ? this.height : this.width);
this.knob.style.width = this.kwidth + "px";
this.knob.style.height = this.kheight + "px";
if (!this.src) {
let r = Math.min(this.width, this.height) * 0.5;
let svgbody =
`<svg xmlns="http://www.w3.org/2000/svg" width="${this.width}" height="${this.height}" preserveAspectRatio="none">
<rect x="1" y="1" rx="${r}" ry="${r}" width="${this.width - 2}" height="${this.height - 2}" fill="${this.coltab[1]}"/></svg>`;
this.elem.style.backgroundImage = "url(data:image/svg+xml;base64," + btoa(svgbody) + ")";
}
else {
this.elem.style.backgroundImage = "url(" + (this.src) + ")";
}
if (!this.knobsrc) {
let svgthumb =
`<svg xmlns="http://www.w3.org/2000/svg" width="${this.kwidth}" height="${this.kheight}" preserveAspectRatio="none">
<radialGradient id="gr" cx="30%" cy="30%"><stop offset="0%" stop-color="${this.coltab[2]}"/><stop offset="100%" stop-color="${this.coltab[0]}"/></radialGradient>
<rect x="2" y="2" width="${this.kwidth - 4}" height="${this.kheight - 4}" rx="${this.kwidth * 0.5}" ry="${this.kheight * 0.5}" fill="url(#gr)"/></svg>`;
this.knob.style.backgroundImage = "url(data:image/svg+xml;base64," + btoa(svgthumb) + ")";
}
else {
this.knob.style.backgroundImage = "url(" + (this.knobsrc) + ")";
}
this.elem.style.outline = this.outline ? "" : "none";
this.redraw();
}
redraw() {
if (!this.isConnected) return;
this.digits = 0;
if (this.step && this.step < 1) {
for (let n = this.step; n < 1; n *= 10)
++this.digits;
}
if (this.value < this.min) {
this.value = this.min;
return;
}
if (this.value > this.max) {
this.value = this.max;
return;
}
let range = this.max - this.min;
let style = this.knob.style;
if (this.dr == "vert") {
style.left = (this.width - this.kwidth) * 0.5 + "px";
style.top = (1 - (this.value - this.min) / range) * this.dlen + "px";
this.sensex = 0; this.sensey = 1;
}
else {
style.top = (this.height - this.kheight) * 0.5 + "px";
style.left = (this.value - this.min) / range * this.dlen + "px";
this.sensex = 1; this.sensey = 0;
}
}
_setValue(v) {
v = (Math.round((v - this.min) / this.step)) * this.step + this.min;
this._value = Math.min(this.max, Math.max(this.min, v));
if (this._value != this.oldvalue) {
this.oldvalue = this._value;
if (this.conv)
this.convValue = eval(this.conv)(this._value);
else
this.convValue = this._value;
this.redraw();
this.showtip(0);
return 1;
}
return 0;
}
setValue(v, f) {
if (this._setValue(v) && f)
this.sendEvent("input"), this.sendEvent("change");
}
wheel(e) {
let delta = (this.max - this.min) * 0.01;
delta = e.deltaY > 0 ? -delta : delta;
if (!e.shiftKey)
delta *= 5;
if (Math.abs(delta) < this.step)
delta = (delta > 0) ? +this.step : -this.step;
this.setValue(+this.value + delta, true);
e.preventDefault();
e.stopPropagation();
this.redraw();
}
pointerdown(ev) {
if (!this.enable)
return;
let e = ev;
if (ev.touches) {
e = ev.changedTouches[0];
this.identifier = e.identifier;
}
else {
if (e.buttons != 1 && e.button != 0)
return;
}
this.elem.focus();
this.drag = 1;
this.showtip(0);
let pointermove = (ev) => {
let e = ev;
if (ev.touches) {
for (let i = 0; i < ev.touches.length; ++i) {
if (ev.touches[i].identifier == this.identifier) {
e = ev.touches[i];
break;
}
}
}
if (this.lastShift !== e.shiftKey) {
this.lastShift = e.shiftKey;
this.startPosX = e.pageX;
this.startPosY = e.pageY;
this.startVal = this.value;
}
let offset = ((this.startPosY - e.pageY) * this.sensey - (this.startPosX - e.pageX) * this.sensex) * this.sensitivity;
this._setValue(this.min + ((((this.startVal + (this.max - this.min) * offset / ((e.shiftKey ? 4 : 1) * this.dlen)) - this.min) / this.step) | 0) * this.step);
this.sendEvent("input");
if (e.preventDefault)
e.preventDefault();
if (e.stopPropagation)
e.stopPropagation();
return false;
}
let pointerup = (ev) => {
let e = ev;
if (ev.touches) {
for (let i = 0; ;) {
if (ev.changedTouches[i].identifier == this.identifier) {
break;
}
if (++i >= ev.changedTouches.length)
return;
}
}
this.drag = 0;
this.showtip(0);
this.startPosX = this.startPosY = null;
window.removeEventListener('mousemove', pointermove);
window.removeEventListener('touchmove', pointermove, { passive: false });
window.removeEventListener('mouseup', pointerup);
window.removeEventListener('touchend', pointerup);
window.removeEventListener('touchcancel', pointerup);
document.body.removeEventListener('touchstart', preventScroll, { passive: false });
this.sendEvent("change");
}
let preventScroll = (e) => {
e.preventDefault();
}
if (e.touches)
e = e.touches[0];
if (e.ctrlKey || e.metaKey)
this.setValue(this.defvalue, true);
else {
this.startPosX = e.pageX;
this.startPosY = e.pageY;
this.startVal = this.value;
window.addEventListener('mousemove', pointermove);
window.addEventListener('touchmove', pointermove, { passive: false });
}
window.addEventListener('mouseup', pointerup);
window.addEventListener('touchend', pointerup);
window.addEventListener('touchcancel', pointerup);
document.body.addEventListener('touchstart', preventScroll, { passive: false });
e.preventDefault();
e.stopPropagation();
return false;
}
});
} catch (error) {
//console.log("webaudio-slider already defined");
}
try {
customElements.define("webaudio-switch", class WebAudioSwitch extends WebAudioControlsWidget {
constructor() {
super();
}
get src() { return this._src; }
set src(v) { this._src = v; this.setupImage(); }
get value() { return this._value; }
set value(v) { this._value = +v; this.redraw(); }
get width() { return this._width; }
set width(v) { this._width = +v; this.setupImage(); }
get height() { return this._height; }
set height(v) { this._height = +v; this.setupImage(); }
get diameter() { return this._diameter; }
set diameter(v) { this._diameter = +v; this.setupImage(); }
get colors() { return this._colors; }
set colors(v) { this._colors = v; this.setupImage(); }
connectedCallback() {
let root;
// if(this.attachShadow)
// root=this.attachShadow({mode: 'open'});
// else
root = this;
root.innerHTML =
`<style>
${this.basestyle}
webaudio-switch{
display:inline-block;
margin:0;
padding:0;
font-family: sans-serif;
font-size: 11px;
cursor:pointer;
}
.webaudio-switch-body{
display:inline-block;
margin:0;
padding:0;
}
</style>
<div class='webaudio-switch-body' tabindex='1' touch-action='none'><div class='webaudioctrl-tooltip'></div></div>
`;
this.elem = root.childNodes[2];
this.ttframe = this.elem.childNodes[0];
this.enable = this.getAttr("enable", 1);
this._src = this.getAttr("src", null);
this._value = this.getAttr("value", 0);
this.defvalue = this.getAttr("defvalue", 0);
this.type = this.getAttr("type", "toggle");
this.group = this.getAttr("group", "");
this._width = this.getAttr("width", 0);
this._height = this.getAttr("height", 0);
this._diameter = this.getAttr("diameter", 0);
this.invert = this.getAttr("invert", 0);
this._colors = this.getAttr("colors", opt.switchColors);
this.outline = this.getAttr("outline", opt.outline);
this.valuetip = 0;
this.tooltip = this.getAttr("tooltip", null);
this.midilearn = this.getAttr("midilearn", opt.midilearn);
this.midicc = this.getAttr("midicc", null);
this.midiController = {};
this.midiMode = "normal";
if (this.midicc) {
let ch = parseInt(this.midicc.substring(0, this.midicc.lastIndexOf("."))) - 1;
let cc = parseInt(this.midicc.substring(this.midicc.lastIndexOf(".") + 1));
this.setMidiController(ch, cc);
}
this.setupImage();
this.digits = 0;
if (window.webAudioControlsMidiManager)
// window.webAudioControlsMidiManager.updateWidgets();
window.webAudioControlsMidiManager.addWidget(this);
this.elem.onclick = (e) => { e.stopPropagation() };
}
disconnectedCallback() { }
setupImage() {
let w = this.width || this.diameter || opt.switchWidth || opt.switchDiameter;
let h = this.height || this.diameter || opt.switchHeight || opt.switchDiameter;
if (!this.src) {
this.coltab = this.colors.split(";");
let mm = Math.min(w, h);
let svg =
`<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h * 2}" preserveAspectRatio="none">
<radialGradient id="gr" cx="30%" cy="30%"><stop offset="0%" stop-color="${this.coltab[2]}"/><stop offset="100%" stop-color="${this.coltab[0]}"/></radialGradient>
<rect x="${w * 0.05}" y="${h * 0.05}" width="${w * 0.9}" height="${h * 0.9}" rx="${mm * 0.1}" ry="${mm * 0.1}" fill="${this.coltab[1]}"/>
<rect x="${w * 0.05}" y="${h * 1.05}" width="${w * 0.9}" height="${h * 0.9}" rx="${mm * 0.1}" ry="${mm * 0.1}" fill="${this.coltab[1]}"/>
<circle cx="${w * 0.5}" cy="${h * 0.5}" r="${mm * 0.3}" stroke="${this.coltab[0]}" stroke-width="2"/>
<circle cx="${w * 0.5}" cy="${h * 1.5}" r="${mm * 0.3}" stroke="${this.coltab[0]}" stroke-width="2" fill="url(#gr)"/></svg>`;
this.elem.style.backgroundImage = "url(data:image/svg+xml;base64," + btoa(svg) + ")";
this.elem.style.backgroundSize = "100% 200%";
}
else {
this.elem.style.backgroundImage = "url(" + (this.src) + ")";
if (!this.sprites)
this.elem.style.backgroundSize = "100% 200%";
else
this.elem.style.backgroundSize = `100% ${(this.sprites + 1) * 100}%`;
}
this.elem.style.width = w + "px";
this.elem.style.height = h + "px";
this.elem.style.outline = this.outline ? "" : "none";
this.redraw();
}
redraw() {
if (!this.isConnected) return;
let style = this.elem.style;
if (this.value ^ this.invert)
style.backgroundPosition = "0px -100%";
else
style.backgroundPosition = "0px 0px";
}
setValue(v, f) {
console.log(v, f)
this.value = v;
this.checked = (!!v);
if (this.value != this.oldvalue) {
this.redraw();
this.showtip(0);
if (f) {
this.sendEvent("input");
this.sendEvent("change");
}
this.oldvalue = this.value;
}
}
pointerdown(ev) {
if (!this.enable)
return;
let e = ev;
if (ev.touches) {
e = ev.changedTouches[0];
this.identifier = e.identifier;
}
else {
if (e.buttons != 1 && e.button != 0)
return;
}
this.elem.focus();
this.drag = 1;
this.showtip(0);
let pointermove = (e) => {
e.preventDefault();
e.stopPropagation();
return false;
}
let pointerup = (e) => {
this.drag = 0;
this.showtip(0);
window.removeEventListener('mousemove', pointermove);
window.removeEventListener('touchmove', pointermove, { passive: false });
window.removeEventListener('mouseup', pointerup);
window.removeEventListener('touchend', pointerup);
window.removeEventListener('touchcancel', pointerup);
document.body.removeEventListener('touchstart', preventScroll, { passive: false });
if (this.type == "kick") {
this.value = 0;
this.checked = false;
this.redraw();
this.sendEvent("change");
}
this.sendEvent("click");
e.preventDefault();
e.stopPropagation();
}
let preventScroll = (e) => {
e.preventDefault();
}
switch (this.type) {
case "kick":
this.setValue(1);
this.sendEvent("change");
break;
case "toggle":
if (e.ctrlKey || e.metaKey)
this.value = defvalue;
else
this.value = 1 - this.value;
this.checked = !!this.value;
this.sendEvent("change");
break;
case "radio":
let els = document.querySelectorAll("webaudio-switch[type='radio'][group='" + this.group + "']");
for (let i = 0; i < els.length; ++i) {
if (els[i] == this)
els[i].setValue(1);
else
els[i].setValue(0);
}
this.sendEvent("change");
break;
}
window.addEventListener('mouseup', pointerup);
window.addEventListener('touchend', pointerup);
window.addEventListener('touchcancel', pointerup);
document.body.addEventListener('touchstart', preventScroll, { passive: false });
this.redraw();
e.preventDefault();
e.stopPropagation();
return false;
}
});
} catch (error) {
//console.log("webaudio-switch already defined");
}
try {
customElements.define("webaudio-param", class WebAudioParam extends WebAudioControlsWidget {
constructor() {
super();
this.addEventListener("keydown", this.keydown);
this.addEventListener("mousedown", this.pointerdown, { passive: false });
this.addEventListener("touchstart", this.pointerdown, { passive: false });
this.addEventListener("wheel", this.wheel);
this.addEventListener("mouseover", this.pointerover);
this.addEventListener("mouseout", this.pointerout);
this.addEventListener("contextmenu", this.contextMenu);
}
get src() { return this._src; }
set src(v) { this._src = v; this.setupImage(); }
get value() { return this._value; }
set value(v) { this._value = +v; this.redraw(); }
get fontsize() { return this._fontsize; }
set fontsize(v) { this._fontsize = +v; this.setupImage(); }
get width() { return this._width; }
set width(v) { this._width = +v; this.setupImage(); }
get height() { return this._height; }
set height(v) { this._height = +v; this.setupImage(); }
get colors() { return this._colors; }
set colors(v) { this._colors = v; this.setupImage(); }
connectedCallback() {
let root;
// if(this.attachShadow)
// root=this.attachShadow({mode: 'open'});
// else
root = this;
root.innerHTML =
`<style>
${this.basestyle}
webaudio-param{
display:inline-block;
user-select:none;
margin:0;
padding:0;
font-family: sans-serif;
font-size: 8px;
cursor:pointer;
}
.webaudio-param-body{
display:inline-block;
text-align:center;
vertical-align:middle;
position:relative;
border:1px solid #888;
background:none;
border-radius:4px;
margin:0;
padding:0;
font-family:sans-serif;
font-size:11px;
}
</style>
<input class='webaudio-param-body' value='0' tabindex='1' touch-action='none'/><div class='webaudioctrl-tooltip'></div>
`;
this.elem = root.childNodes[2];
this.ttframe = root.childNodes[3];
this.enable = this.getAttr("enable", 1);
this._value = this.getAttr("value", 0);
this.defvalue = this.getAttr("defvalue", 0);
this._fontsize = this.getAttr("fontsize", 9);
this._src = this.getAttr("src", null);
this.link = this.getAttr("link", "");
this._width = this.getAttr("width", 32);
this._height = this.getAttr("height", 16);
this._colors = this.getAttr("colors", "#fff;#000");
this.outline = this.getAttr("outline", opt.outline);
this.midiController = {};
this.midiMode = "normal";
if (this.midicc) {
let ch = parseInt(this.midicc.substring(0, this.midicc.lastIndexOf("."))) - 1;
let cc = parseInt(this.midicc.substring(this.midicc.lastIndexOf(".") + 1));
this.setMidiController(ch, cc);
}
this.setupImage();
if (window.webAudioControlsMidiManager)
// window.webAudioControlsMidiManager.updateWidgets();
window.webAudioControlsMidiManager.addWidget(this);
this.fromLink = ((e) => {
this.setValue(e.target.convValue.toFixed(e.target.digits));
}).bind(this);
this.elem.onchange = () => {
let le = document.getElementById(this.link);
if (le)
le.setValue(+this.elem.value);
}
}
disconnectedCallback() { }
setupImage() {
this.coltab = this.colors.split(";");
this.elem.style.color = this.coltab[0];
if (!this.src) {
this.elem.style.backgroundColor = this.coltab[1];
}
else {
this.elem.style.backgroundImage = "url(" + (this.src) + ")";
this.elem.style.backgroundSize = "100% 100%";
}
this.elem.style.width = this.width + "px";
this.elem.style.height = this.height + "px";
this.elem.style.fontSize = this.fontsize + "px";
this.elem.style.outline = this.outline ? "" : "none";
let l = document.getElementById(this.link);
if (l) {
this.setValue(l.value.toFixed(l.digits));
l.addEventListener("input", (e) => { this.setValue(l.value.toFixed(l.digits)) });
}
this.redraw();
}
redraw() {
if (!this.isConnected) return;
this.elem.value = this.value;
}
setValue(v, f) {
this.value = v;
if (this.value != this.oldvalue) {
this.redraw();
this.showtip(0);
if (f) {
let event = document.createEvent("HTMLEvents");
event.initEvent("change", false, true);
this.dispatchEvent(event);
}
this.oldvalue = this.value;
}
}
pointerdown(ev) {
if (!this.enable)
return;
let e = ev;
if (ev.touches)
e = ev.touches[0];
else {
if (e.buttons != 1 && e.button != 0)
return;
}
this.elem.focus();
this.drag = 1;
this.showtip(0);
let pointermove = (e) => {
e.preventDefault();
e.stopPropagation();
return false;
}
let pointerup = (e) => {
this.drag = 0;
this.showtip(0);
window.removeEventListener('mouseup', pointerup);
window.removeEventListener('touchend', pointerup);
window.removeEventListener('touchcancel', pointerup);
document.body.removeEventListener('touchstart', preventScroll, { passive: false });
}
let preventScroll = (e) => {
e.preventDefault();
}
window.addEventListener('mouseup', pointerup);
window.addEventListener('touchend', pointerup);
window.addEventListener('touchcancel', pointerup);
document.body.addEventListener('touchstart', preventScroll, { passive: false });
this.redraw();
if (e.preventDefault)
e.preventDefault();
if (e.stopPropagation)
e.stopPropagation();
return false;
}
});
} catch (error) {
//console.log("webaudio-param already defined");
}
try {
customElements.define("webaudio-keyboard", class WebAudioKeyboard extends WebAudioControlsWidget {
constructor() {
super();
}
get width() { return this._width; }
set width(v) { this._width = v; this.setupImage(); }
get height() { return this._height; }
set height(v) { this._height = v; this.setupImage(); }
get min() { return this._min; }
set min(v) { this._min = +v; this.redraw(); }
get step() { return this._step; }
set step(v) { this._step = +v; this.redraw(); }
get keys() { return this._keys; }
set keys(v) { this._keys = +v; this.setupImage(); }
get colors() { return this._colors; }
set colors(v) { this._colors = v; this.setupImage(); }
connectedCallback() {
let root;
// if(this.attachShadow)
// root=this.attachShadow({mode: 'open'});
// else
root = this;
root.innerHTML =
`<style>
${this.basestyle}
webaudio-keyboard{
display:inline-block;
position:relative;
margin:0;
padding:0;
font-family: sans-serif;
font-size: 11px;
}
.webaudio-keyboard-body{
display:inline-block;
margin:0;
padding:0;
}
</style>
<canvas class='webaudio-keyboard-body' tabindex='1' touch-action='none'></canvas><div class='webauioctrl-tooltip'></div>
`;
this.cv = root.childNodes[2];
this.ttframe = root.childNodes[3];
this.ctx = this.cv.getContext("2d");
this._values = [];
this.enable = this.getAttr("enable", 1);
this._width = this.getAttr("width", 480);
this._height = this.getAttr("height", 128);
this._min = this.getAttr("min", 0);
this._keys = this.getAttr("keys", 25);
this._colors = this.getAttr("colors", "#222;#eee;#ccc;#333;#000;#e88;#c44;#c33;#800");
this.outline = this.getAttr("outline", opt.outline);
this.midilearn = this.getAttr("midilearn", 0);
this.midicc = this.getAttr("midicc", null);
this.press = 0;
this.keycodes1 = [90, 83, 88, 68, 67, 86, 71, 66, 72, 78, 74, 77, 188, 76, 190, 187, 191, 226];
this.keycodes2 = [81, 50, 87, 51, 69, 82, 53, 84, 54, 89, 55, 85, 73, 57, 79, 48, 80, 192, 222, 219];
this.addEventListener("keyup", this.keyup);
this.midiController = {};
this.midiMode = "normal";
if (this.midicc) {
let ch = parseInt(this.midicc.substring(0, this.midicc.lastIndexOf("."))) - 1;
let cc = parseInt(this.midicc.substring(this.midicc.lastIndexOf(".") + 1));
this.setMidiController(ch, cc);
}
this.setupImage();
this.digits = 0;
this.addEventListener("mousemove", this.pointermove);
this.addEventListener("touchmove", this.pointermove, { passive: false });
this.addEventListener("mouseup", this.pointerup);
this.addEventListener("touchend", this.pointerup);
this.addEventListener("touchcancel", this.pointerup);
if (window.webAudioControlsMidiManager)
// window.webAudioControlsMidiManager.updateWidgets();
window.webAudioControlsMidiManager.addWidget(this);
}
disconnectedCallback() { }
setupImage() {
this.cv.style.width = this.width + "px";
this.cv.style.height = this.height + "px";
this.bheight = this.height * 0.55;
this.kp = [0, 7 / 12, 1, 3 * 7 / 12, 2, 3, 6 * 7 / 12, 4, 8 * 7 / 12, 5, 10 * 7 / 12, 6];
this.kf = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0];
this.ko = [0, 0, (7 * 2) / 12 - 1, 0, (7 * 4) / 12 - 2, (7 * 5) / 12 - 3, 0, (7 * 7) / 12 - 4, 0, (7 * 9) / 12 - 5, 0, (7 * 11) / 12 - 6];
this.kn = [0, 2, 4, 5, 7, 9, 11];
this.coltab = this.colors.split(";");
this.cv.width = this.width;
this.cv.height = this.height;
this.cv.style.width = this.width + 'px';
this.cv.style.height = this.height + 'px';
this.cv.style.outline = this.outline ? "" : "none";
this.bheight = this.height * 0.55;
this.max = this.min + this.keys - 1;
this.dispvalues = [];
this.valuesold = [];
if (this.kf[this.min % 12])
--this.min;
if (this.kf[this.max % 12])
++this.max;
this.redraw();
}
redraw() {
if (!this.isConnected) return;
function rrect(ctx, x, y, w, h, r, c1, c2) {
if (c2) {
let g = ctx.createLinearGradient(x, y, x + w, y);
g.addColorStop(0, c1);
g.addColorStop(1, c2);
ctx.fillStyle = g;
}
else
ctx.fillStyle = c1;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + w, y);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y);
ctx.fill();
}
this.ctx.fillStyle = this.coltab[0];
this.ctx.fillRect(0, 0, this.width, this.height);
let x0 = 7 * ((this.min / 12) | 0) + this.kp[this.min % 12];
let x1 = 7 * ((this.max / 12) | 0) + this.kp[this.max % 12];
let n = x1 - x0;
this.wwidth = (this.width - 1) / (n + 1);
this.bwidth = this.wwidth * 7 / 12;
let h2 = this.bheight;
let r = Math.min(8, this.wwidth * 0.2);
for (let i = this.min, j = 0; i <= this.max; ++i) {
if (this.kf[i % 12] == 0) {
let x = this.wwidth * (j++) + 1;
if (this.dispvalues.indexOf(i) >= 0)
rrect(this.ctx, x, 1, this.wwidth - 1, this.height - 2, r, this.coltab[5], this.coltab[6]);
else
rrect(this.ctx, x, 1, this.wwidth - 1, this.height - 2, r, this.coltab[1], this.coltab[2]);
}
}
r = Math.min(8, this.bwidth * 0.3);
for (let i = this.min; i < this.max; ++i) {
if (this.kf[i % 12]) {
let x = this.wwidth * this.ko[this.min % 12] + this.bwidth * (i - this.min) + 1;
if (this.dispvalues.indexOf(i) >= 0)
rrect(this.ctx, x, 1, this.bwidth, h2, r, this.coltab[7], this.coltab[8]);
else
rrect(this.ctx, x, 1, this.bwidth, h2, r, this.coltab[3], this.coltab[4]);
this.ctx.strokeStyle = this.coltab[0];
this.ctx.stroke();
}
}
}
_setValue(v) {
if (this.step)
v = (Math.round((v - this.min) / this.step)) * this.step + this.min;
this._value = Math.min(this.max, Math.max(this.min, v));
if (this._value != this.oldvalue) {
this.oldvalue = this._value;
this.redraw();
this.showtip(0);
return 1;
}
return 0;
}
setValue(v, f) {
if (this._setValue(v) && f)
this.sendEvent("input"), this.sendEvent("change");
}
wheel(e) { }
keydown(e) {
let m = Math.floor((this.min + 11) / 12) * 12;
let k = this.keycodes1.indexOf(e.keyCode);
if (k < 0) {
k = this.keycodes2.indexOf(e.keyCode);
if (k >= 0) k += 12;
}
if (k >= 0) {
k += m;
if (this.currentKey != k) {
this.currentKey = k;
this.sendEventFromKey(1, k);
this.setNote(1, k);
}
}
}
keyup(e) {
let m = Math.floor((this.min + 11) / 12) * 12;
let k = this.keycodes1.indexOf(e.keyCode);
if (k < 0) {
k = this.keycodes2.indexOf(e.keyCode);
if (k >= 0) k += 12;
}
if (k >= 0) {
k += m;
this.currentKey = -1;
this.sendEventFromKey(0, k);
this.setNote(0, k);
}
}
pointerdown(e) {
this.cv.focus();
// document.body.addEventListener('touchstart',this.preventScroll,{passive:false});
if (this.enable) {
++this.press;
this.pointermove(e);
}
e.preventDefault();
}
pointermove(e) {
if (!this.enable)
return;
let r = this.getBoundingClientRect();
let v = [], p;
if (e.touches)
p = e.targetTouches;
else if (this.press)
p = [e];
else
p = [];
if (p.length > 0)
this.drag = 1;
for (let i = 0; i < p.length; ++i) {
let px = p[i].clientX - r.left;
let py = p[i].clientY - r.top;
let x, k, ko;
if (py < this.bheight) {
x = px - this.wwidth * this.ko[this.min % 12];
k = this.min + ((x / this.bwidth) | 0);
}
else {
k = (px / this.wwidth) | 0;
ko = this.kp[this.min % 12];
k += ko;
k = this.min + ((k / 7)